From 1f44b5a4c87850e7d1e02a763b98e8530fba604a Mon Sep 17 00:00:00 2001 From: flarum-bot Date: Thu, 24 Sep 2020 02:56:26 +0000 Subject: [PATCH] Bundled output for commit a2049ebbb866cf587aad46c6bea0bc10c1be6431 [skip ci] --- extensions/statistics/js/dist/admin.js | 2 +- extensions/statistics/js/dist/admin.js.map | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/statistics/js/dist/admin.js b/extensions/statistics/js/dist/admin.js index 3dbf52c6f..333bb5acc 100644 --- a/extensions/statistics/js/dist/admin.js +++ b/extensions/statistics/js/dist/admin.js @@ -1,2 +1,2 @@ -module.exports=function(t){var e={};function s(i){if(e[i])return e[i].exports;var a=e[i]={i:i,l:!1,exports:{}};return t[i].call(a.exports,a,a.exports,s),a.l=!0,a.exports}return s.m=t,s.c=e,s.d=function(t,e,i){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(s.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)s.d(i,a,function(e){return t[e]}.bind(null,a));return i},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=8)}([function(t,e){t.exports=flarum.core.compat["utils/abbreviateNumber"]},function(t,e){t.exports=flarum.core.compat.app},function(t,e){t.exports=flarum.core.compat.extend},function(t,e){t.exports=flarum.core.compat["components/DashboardPage"]},function(t,e){t.exports=flarum.core.compat["components/DashboardWidget"]},function(t,e){t.exports=flarum.core.compat["components/SelectDropdown"]},function(t,e){t.exports=flarum.core.compat["components/Button"]},function(t,e){t.exports=flarum.core.compat["helpers/icon"]},function(t,e,s){"use strict";s.r(e);var i=s(1),a=s.n(i),n=s(2),r=s(3),o=s.n(r);var l=s(4),h=s.n(l),d=s(5),c=s.n(d),p=s(6),u=s.n(p),f=s(7),g=s.n(f),y=s(0),b=s.n(y);function x(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function v(t){let e=t.getBoundingClientRect();return{top:e.top+(document.documentElement.scrollTop||document.body.scrollTop),left:e.left+(document.documentElement.scrollLeft||document.body.scrollLeft)}}x.create=(t,e)=>{var s=document.createElement(t);for(var i in e){var a=e[i];if("inside"===i)x(a).appendChild(s);else if("around"===i){var n=x(a);n.parentNode.insertBefore(s,n),s.appendChild(n)}else"styles"===i?"object"==typeof a&&Object.keys(a).map(t=>{s.style[t]=a[t]}):i in s?s[i]=a:s.setAttribute(i,a)}return s};const w={margins:{top:10,bottom:10,left:20,right:20},paddings:{top:20,bottom:40,left:30,right:10},baseHeight:240,titleHeight:20,legendHeight:30,titleFontSize:12};function A(t){return t.titleHeight+t.margins.top+t.paddings.top}function P(t){return t.margins.left+t.paddings.left}function k(t){return t.margins.top+t.margins.bottom+t.paddings.top+t.paddings.bottom+t.titleHeight+t.legendHeight}function C(t){return t.margins.left+t.margins.right+t.paddings.left+t.paddings.right}const D=["line","bar"],L=["light-blue","blue","violet","red","orange","yellow","green","light-green","purple","magenta","light-grey","dark-grey"],T={bar:L,line:L,pie:L,percentage:L,heatmap:["#ebedf0","#c6e48b","#7bc96f","#239a3b","#196127"]},M=Math.PI/180;class N{constructor({parent:t=null,colors:e=[]}){this.parent=t,this.colors=e,this.titleName="",this.titleValue="",this.listValues=[],this.titleValueFirst=0,this.x=0,this.y=0,this.top=0,this.left=0,this.setup()}setup(){this.makeTooltip()}refresh(){this.fill(),this.calcPosition()}makeTooltip(){this.container=x.create("div",{inside:this.parent,className:"graph-svg-tip comparison",innerHTML:'\n\t\t\t\t\n\t\t\t\t
'}),this.hideTip(),this.title=this.container.querySelector(".title"),this.dataPointList=this.container.querySelector(".data-point-list"),this.parent.addEventListener("mouseleave",()=>{this.hideTip()})}fill(){let t;this.index&&this.container.setAttribute("data-point-index",this.index),t=this.titleValueFirst?`${this.titleValue}${this.titleName}`:`${this.titleName}${this.titleValue}`,this.title.innerHTML=t,this.dataPointList.innerHTML="",this.listValues.map((t,e)=>{const s=this.colors[e]||"black";let i=0===t.formatted||t.formatted?t.formatted:t.value,a=x.create("li",{styles:{"border-top":"3px solid "+s},innerHTML:`${0===i||i?i:""}\n\t\t\t\t\t${t.title?t.title:""}`});this.dataPointList.appendChild(a)})}calcPosition(){let t=this.container.offsetWidth;this.top=this.y-this.container.offsetHeight-5,this.left=this.x-t/2;let e=this.parent.offsetWidth-t,s=this.container.querySelector(".svg-pointer");if(this.left<0)s.style.left=`calc(50% - ${-1*this.left}px)`,this.left=0;else if(this.left>e){let t=`calc(50% + ${this.left-e}px)`;s.style.left=t,this.left=e}else s.style.left="50%"}setValues(t,e,s={},i=[],a=-1){this.titleName=s.name,this.titleValue=s.value,this.listValues=i,this.x=t,this.y=e,this.titleValueFirst=s.valueFirst||0,this.index=a,this.refresh()}hideTip(){this.container.style.top="0px",this.container.style.left="0px",this.container.style.opacity="0"}showTip(){this.container.style.top=this.top+"px",this.container.style.left=this.left+"px",this.container.style.opacity="1"}}function O(t){return parseFloat(t.toFixed(2))}function E(t,e,s,i=!1){s||(s=i?t[0]:t[t.length-1]);let a=new Array(Math.abs(e)).fill(s);return t=i?a.concat(t):t.concat(a)}function S(t,e){return(t+"").length*e}function z(t,e){return{x:Math.sin(t*M)*e,y:Math.cos(t*M)*e}}function W(t,e){let s,i;return t<=e?(s=e-t,i=t):(s=t-e,i=e),[s,i]}function $(t,e,s=e.length-t.length){return s>0?t=E(t,s):e=E(e,s),[t,e]}const H={"light-blue":"#7cd6fd",blue:"#5e64ff",violet:"#743ee2",red:"#ff5858",orange:"#ffa00a",yellow:"#feef72",green:"#28a745","light-green":"#98d85b",purple:"#b554ff",magenta:"#ffa3ef",black:"#36114C",grey:"#bdd3e6","light-grey":"#f0f4f7","dark-grey":"#b8c2cc"};function F(t){return t>255?255:t<0?0:t}function j(t,e){let s=I(t),i=!1;"#"==s[0]&&(s=s.slice(1),i=!0);let a=parseInt(s,16),n=F((a>>16)+e),r=F((a>>8&255)+e);return(i?"#":"")+(F((255&a)+e)|r<<8|n<<16).toString(16)}const I=t=>H[t]||t;function R(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function Y(t,e){var s=document.createElementNS("http://www.w3.org/2000/svg",t);for(var i in e){var a=e[i];if("inside"===i)R(a).appendChild(s);else if("around"===i){var n=R(a);n.parentNode.insertBefore(s,n),s.appendChild(n)}else"styles"===i?"object"==typeof a&&Object.keys(a).map(t=>{s.style[t]=a[t]}):("className"===i&&(i="class"),"innerHTML"===i?s.textContent=a:s.setAttribute(i,a))}return s}function _(t,e,s,i){return Y("stop",{inside:t,style:"stop-color: "+s,offset:e,"stop-opacity":i})}function B(t,e="",s){let i={className:t,transform:e};return s&&(i.inside=s),Y("g",i)}function V(t,e="",s="none",i="none"){return Y("path",{className:e,d:t,styles:{stroke:s,fill:i}})}function U(t,e,s=!1){let i="path-fill-gradient-"+e+"-"+(s?"lighter":"default"),a=function(t,e){return Y("linearGradient",{inside:t,id:e,x1:0,x2:0,y1:0,y2:1})}(t,i),n=[1,.6,.2];return s&&(n=[.4,.2,0]),_(a,"0%",e,n[0]),_(a,"50%",e,n[1]),_(a,"100%",e,n[2]),i}function G(t,e,s,i,a="none",n={}){let r={className:t,x:e,y:s,width:i,height:i,fill:a};return Object.keys(n).map(t=>{r[t]=n[t]}),Y("rect",r)}function q(t,e,s,i,a={}){let n=a.fontSize||10;return Y("text",{className:t,x:e,y:s,dy:(void 0!==a.dy?a.dy:n/2)+"px","font-size":n+"px",fill:a.fill||"#555b51","text-anchor":a.textAnchor||"start",innerHTML:i})}function X(t,e,s,i,a={}){a.stroke||(a.stroke="#dadada"),a.lineType||(a.lineType="");let n=Y("line",{className:"line-horizontal "+a.className+("dashed"===a.lineType?"dashed":""),x1:s,x2:i,y1:0,y2:0,styles:{stroke:a.stroke}}),r=Y("text",{x:si?s+4:s-4-10,dy:"10px","font-size":"10px","text-anchor":"middle",innerHTML:e+""}),o=Y("g",{transform:`translate(${t}, 0)`});return o.appendChild(n),o.appendChild(r),o}(t,e,a,n,{stroke:i.stroke,className:i.className,lineType:i.lineType})}let K={bar:t=>{let e;"rect"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);let s=t.cloneNode();return s.style.fill="#000000",s.style.opacity="0.4",e&&s.setAttribute("transform",e),s},dot:t=>{let e;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);let s=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return s.setAttribute("r",parseInt(i)+4),s.setAttribute("fill",a),s.style.opacity="0.6",e&&s.setAttribute("transform",e),s},heat_square:t=>{let e;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);let s=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return s.setAttribute("r",parseInt(i)+4),s.setAttribute("fill",a),s.style.opacity="0.6",e&&s.setAttribute("transform",e),s}},Q={bar:(t,e)=>{let s;"rect"!==t.nodeName&&(s=t.getAttribute("transform"),t=t.childNodes[0]);let i=["x","y","width","height"];Object.values(t.attributes).filter(t=>i.includes(t.name)&&t.specified).map(t=>{e.setAttribute(t.name,t.nodeValue)}),s&&e.setAttribute("transform",s)},dot:(t,e)=>{let s;"circle"!==t.nodeName&&(s=t.getAttribute("transform"),t=t.childNodes[0]);let i=["cx","cy"];Object.values(t.attributes).filter(t=>i.includes(t.name)&&t.specified).map(t=>{e.setAttribute(t.name,t.nodeValue)}),s&&e.setAttribute("transform",s)},heat_square:(t,e)=>{let s;"circle"!==t.nodeName&&(s=t.getAttribute("transform"),t=t.childNodes[0]);let i=["cx","cy"];Object.values(t.attributes).filter(t=>i.includes(t.name)&&t.specified).map(t=>{e.setAttribute(t.name,t.nodeValue)}),s&&e.setAttribute("transform",s)}};function Z(t,e,s,i){let a="string"==typeof e?e:e.join(", ");return[t,{transform:s.join(", ")},i,"easein","translate",{transform:a}]}function tt(t,e,s){return Z(t,[0,s],[0,e],350)}const et={ease:"0.25 0.1 0.25 1",linear:"0 0 1 1",easein:"0.1 0.8 0.2 1",easeout:"0 0 0.58 1",easeinout:"0.42 0 0.58 1"};function st(t,e){t.style.transform=e,t.style.webkitTransform=e,t.style.msTransform=e,t.style.mozTransform=e,t.style.oTransform=e}function it(t,e){let s=[],i=[];e.map(t=>{let e,a,n=t[0],r=n.parentNode;t[0]=n,[e,a]=function(t,e,s,i="linear",a,n={}){let r=t.cloneNode(!0),o=t.cloneNode(!0);for(var l in e){let d;d="transform"===l?document.createElementNS("http://www.w3.org/2000/svg","animateTransform"):document.createElementNS("http://www.w3.org/2000/svg","animate");let c=n[l]||t.getAttribute(l),p=e[l],u={attributeName:l,from:c,to:p,begin:"0s",dur:s/1e3+"s",values:c+";"+p,keySplines:et[i],keyTimes:"0;1",calcMode:"spline",fill:"freeze"};for(var h in a&&(u.type=a),u)d.setAttribute(h,u[h]);r.appendChild(d),a?o.setAttribute(l,`translate(${p})`):o.setAttribute(l,p)}return[r,o]}(...t),s.push(a),i.push([e,r]),r.replaceChild(e,n)});let a=t.cloneNode(!0);return i.map((t,i)=>{t[1].replaceChild(s[i],t[0]),e[i][0]=s[i]}),a}let at;class nt{constructor(t,e){if(this.parent="string"==typeof t?document.querySelector(t):t,!(this.parent instanceof HTMLElement))throw new Error("No `parent` element to render on was provided.");this.rawChartArgs=e,this.title=e.title||"",this.type=e.type||"",this.realData=this.prepareData(e.data),this.data=this.prepareFirstData(this.realData),this.colors=this.validateColors(e.colors,this.type),this.config={showTooltip:1,showLegend:1,isNavigable:e.isNavigable||0,animate:1},this.measures=JSON.parse(JSON.stringify(w));let s=this.measures;this.setMeasures(e),this.title.length||(s.titleHeight=0),this.config.showLegend||(s.legendHeight=0),this.argHeight=e.height||s.baseHeight,this.state={},this.options={},this.initTimeout=700,this.config.isNavigable&&(this.overlays=[]),this.configure(e)}prepareData(t){return t}prepareFirstData(t){return t}validateColors(t,e){const s=[];return(t=(t||[]).concat(T[e])).forEach(t=>{const e=I(t);!function(t){return/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t)}(e)?console.warn('"'+t+'" is not a valid color.'):s.push(e)}),s}setMeasures(){}configure(){let t=this.argHeight;this.baseHeight=t,this.height=t-k(this.measures),at=this.boundDrawFn.bind(this),window.addEventListener("resize",at),window.addEventListener("orientationchange",this.boundDrawFn.bind(this))}boundDrawFn(){this.draw(!0)}unbindWindowEvents(){window.removeEventListener("resize",at),window.removeEventListener("orientationchange",this.boundDrawFn.bind(this))}setup(){this.makeContainer(),this.updateWidth(),this.makeTooltip(),this.draw(!1,!0)}makeContainer(){this.parent.innerHTML="";let t={inside:this.parent,className:"chart-container"};this.independentWidth&&(t.styles={width:this.independentWidth+"px"}),this.container=x.create("div",t)}makeTooltip(){this.tip=new N({parent:this.container,colors:this.colors}),this.bindTooltip()}bindTooltip(){}draw(t=!1,e=!1){this.updateWidth(),this.calc(t),this.makeChartArea(),this.setupComponents(),this.components.forEach(t=>t.setup(this.drawArea)),this.render(this.components,!1),e&&(this.data=this.realData,setTimeout(()=>{this.update(this.data)},this.initTimeout)),this.renderLegend(),this.setupNavigation(e)}calc(){}updateWidth(){var t,e,s;this.baseWidth=(t=this.parent,e=window.getComputedStyle(t),s=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight),t.clientWidth-s),this.width=this.baseWidth-C(this.measures)}makeChartArea(){this.svg&&this.container.removeChild(this.svg);let t=this.measures;var e,s,i,a;this.svg=(e=this.container,s="frappe-chart chart",i=this.baseWidth,a=this.baseHeight,Y("svg",{className:s,inside:e,width:i,height:a})),this.svgDefs=Y("defs",{inside:this.svg}),this.title.length&&(this.titleEL=q("title",t.margins.left,t.margins.top,this.title,{fontSize:t.titleFontSize,fill:"#666666",dy:t.titleFontSize}));let n=A(t);this.drawArea=B(this.type+"-chart chart-draw-area",`translate(${P(t)}, ${n})`),this.config.showLegend&&(n+=this.height+t.paddings.bottom,this.legendArea=B("chart-legend",`translate(${P(t)}, ${n})`)),this.title.length&&this.svg.appendChild(this.titleEL),this.svg.appendChild(this.drawArea),this.config.showLegend&&this.svg.appendChild(this.legendArea),this.updateTipOffset(P(t),A(t))}updateTipOffset(t,e){this.tip.offset={x:t,y:e}}setupComponents(){this.components=new Map}update(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.calc(),this.render()}render(t=this.components,e=!0){this.config.isNavigable&&this.overlays.map(t=>t.parentNode.removeChild(t));let s=[];t.forEach(t=>{s=s.concat(t.update(e))}),s.length>0?(!function(t,e,s){if(0===s.length)return;let i=it(e,s);e.parentNode==t&&(t.removeChild(e),t.appendChild(i)),setTimeout(()=>{i.parentNode==t&&(t.removeChild(i),t.appendChild(e))},250)}(this.container,this.svg,s),setTimeout(()=>{t.forEach(t=>t.make()),this.updateNav()},400)):(t.forEach(t=>t.make()),this.updateNav())}updateNav(){this.config.isNavigable&&(this.makeOverlay(),this.bindUnits())}renderLegend(){}setupNavigation(t=!1){this.config.isNavigable&&t&&(this.bindOverlay(),this.keyActions={13:this.onEnterKey.bind(this),37:this.onLeftArrow.bind(this),38:this.onUpArrow.bind(this),39:this.onRightArrow.bind(this),40:this.onDownArrow.bind(this)},document.addEventListener("keydown",t=>{var e,s;e=this.container,(s=e.getBoundingClientRect()).top>=0&&s.left>=0&&s.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&s.right<=(window.innerWidth||document.documentElement.clientWidth)&&(t=t||window.event,this.keyActions[t.keyCode]&&this.keyActions[t.keyCode]())}))}makeOverlay(){}updateOverlay(){}bindOverlay(){}bindUnits(){}onLeftArrow(){}onRightArrow(){}onUpArrow(){}onDownArrow(){}onEnterKey(){}addDataPoint(){}removeDataPoint(){}getDataPoint(){}setCurrentDataPoint(){}updateDataset(){}export(){let t=function(t){let e=t.cloneNode(!0);e.classList.add("chart-container"),e.setAttribute("xmlns","http://www.w3.org/2000/svg"),e.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");let s=x.create("style",{innerHTML:".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}"});e.insertBefore(s,e.firstChild);let i=x.create("div");return i.appendChild(e),i.innerHTML}(this.svg);!function(t,e){var s=document.createElement("a");s.style="display: none";var i=new Blob(e,{type:"image/svg+xml; charset=utf-8"}),a=window.URL.createObjectURL(i);s.href=a,s.download=t,document.body.appendChild(s),s.click(),setTimeout((function(){document.body.removeChild(s),window.URL.revokeObjectURL(a)}),300)}(this.title||"Chart",[t])}}class rt extends nt{constructor(t,e){super(t,e)}configure(t){super.configure(t),this.config.maxSlices=t.maxSlices||20,this.config.maxLegendPoints=t.maxLegendPoints||20}calc(){let t=this.state,e=this.config.maxSlices;t.sliceTotals=[];let s=this.data.labels.map((t,e)=>{let s=0;return this.data.datasets.map(t=>{s+=t.values[e]}),[s,t]}).filter(t=>t[0]>=0),i=s;if(s.length>e){s.sort((t,e)=>e[0]-t[0]),i=s.slice(0,e-1);let t=s.slice(e-1),a=0;t.map(t=>{a+=t[0]}),i.push([a,"Rest"]),this.colors[e-1]="grey"}t.labels=[],i.map(e=>{t.sliceTotals.push(e[0]),t.labels.push(e[1])}),t.grandTotal=t.sliceTotals.reduce((t,e)=>t+e,0),this.center={x:this.width/2,y:this.height/2}}renderLegend(){let t=this.state;this.legendArea.textContent="",this.legendTotals=t.sliceTotals.slice(0,this.config.maxLegendPoints);let e=0,s=0;this.legendTotals.map((i,a)=>{let n=Math.floor((this.width-C(this.measures))/110);e>n&&(e=0,s+=20);let r=function(t,e,s,i="none",a){let n={className:"legend-dot",cx:0,cy:0,r:s,fill:i},r=Y("text",{className:"legend-dataset-text",x:0,y:0,dx:"10px",dy:10/3+"px","font-size":"12px","text-anchor":"start",fill:"#555b51",innerHTML:a}),o=Y("g",{transform:`translate(${t}, ${e})`});return o.appendChild(Y("circle",n)),o.appendChild(r),o}(110*e+5,s,5,this.colors[a],`${t.labels[a]}: ${i}`);this.legendArea.appendChild(r),e++})}}const ot=["January","February","March","April","May","June","July","August","September","October","November","December"],lt=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function ht(t){let e=new Date(t);return e.setMinutes(e.getMinutes()-e.getTimezoneOffset()),e}function dt(t){let e=t.getDate(),s=t.getMonth()+1;return[t.getFullYear(),(s>9?"":"0")+s,(e>9?"":"0")+e].join("-")}function ct(t){return new Date(t.getTime())}function pt(t,e){let s=gt(t);return Math.ceil(function(t,e){return(ht(e)-ht(t))/864e5}(s,e)/7)}function ut(t,e){return t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}function mt(t,e=!1){let s=ot[t];return e?s.slice(0,3):s}function ft(t,e){return new Date(e,t+1,0)}function gt(t){let e=ct(t);const s=e.getDay();return 0!==s&&yt(e,-1*s),e}function yt(t,e){t.setDate(t.getDate()+e)}class bt{constructor({layerClass:t="",layerTransform:e="",constants:s,getData:i,makeElements:a,animateElements:n}){this.layerTransform=e,this.constants=s,this.makeElements=a,this.getData=i,this.animateElements=n,this.store=[],this.labels=[],this.layerClass=t,this.layerClass="function"==typeof this.layerClass?this.layerClass():this.layerClass,this.refresh()}refresh(t){this.data=t||this.getData()}setup(t){this.layer=B(this.layerClass,this.layerTransform,t)}make(){this.render(this.data),this.oldData=this.data}render(t){this.store=this.makeElements(t),this.layer.textContent="",this.store.forEach(t=>{this.layer.appendChild(t)}),this.labels.forEach(t=>{this.layer.appendChild(t)})}update(t=!0){this.refresh();let e=[];return t&&(e=this.animateElements(this.data)||[]),e}}let xt={pieSlices:{layerClass:"pie-slices",makeElements:t=>t.sliceStrings.map((e,s)=>{let i=V(e,"pie-path","none",t.colors[s]);return i.style.transition="transform .3s;",i}),animateElements(t){return this.store.map((e,s)=>{return i=e,a=t.sliceStrings[s],[i,{d:a},350,"easein"];var i,a})}},percentageBars:{layerClass:"percentage-bars",makeElements(t){return t.xPositions.map((e,s)=>function(t,e,s,i,a=2,n="none"){return Y("rect",{className:"percentage-bar",x:t,y:e,width:s,height:i,fill:n,styles:{stroke:j(n,-25),"stroke-dasharray":`0, ${i+s}, ${s}, ${i}`,"stroke-width":a}})}(e,0,t.widths[s],this.constants.barHeight,this.constants.barDepth,t.colors[s]))},animateElements(t){if(t)return[]}},yAxis:{layerClass:"y axis",makeElements(t){return t.positions.map((e,s)=>function(t,e,s,i={}){i.pos||(i.pos="left"),i.offset||(i.offset=0),i.mode||(i.mode="span"),i.stroke||(i.stroke="#dadada"),i.className||(i.className="");let a=-6,n="span"===i.mode?s+6:0;return"tick"===i.mode&&"right"===i.pos&&(a=s+6,n=s),a+=i.offset,n+=i.offset,X(t,e,a,n,{stroke:i.stroke,className:i.className,lineType:i.lineType})}(e,t.labels[s],this.constants.width,{mode:this.constants.mode,pos:this.constants.pos}))},animateElements(t){let e=t.positions,s=t.labels,i=this.oldData.positions,a=this.oldData.labels;return[i,e]=$(i,e),[a,s]=$(a,s),this.render({positions:i,labels:s}),this.store.map((t,s)=>tt(t,e[s],i[s]))}},xAxis:{layerClass:"x axis",makeElements(t){return t.positions.map((e,s)=>J(e,t.calcLabels[s],this.constants.height,{mode:this.constants.mode,pos:this.constants.pos}))},animateElements(t){let e=t.positions,s=t.calcLabels,i=this.oldData.positions,a=this.oldData.calcLabels;return[i,e]=$(i,e),[a,s]=$(a,s),this.render({positions:i,calcLabels:s}),this.store.map((t,s)=>function(t,e,s){return Z(t,[s,0],[e,0],350)}(t,e[s],i[s]))}},yMarkers:{layerClass:"y-markers",makeElements(t){return t.map(t=>function(t,e,s,i={}){i.labelPos||(i.labelPos="right");let a=Y("text",{className:"chart-label",x:"left"===i.labelPos?4:s-S(e,5)-4,y:0,dy:"-5px","font-size":"10px","text-anchor":"start",innerHTML:e+""}),n=X(t,"",0,s,{stroke:i.stroke||"#dadada",className:i.className||"",lineType:i.lineType});return n.appendChild(a),n}(t.position,t.label,this.constants.width,{labelPos:t.options.labelPos,mode:"span",lineType:"dashed"}))},animateElements(t){[this.oldData,t]=$(this.oldData,t);let e=t.map(t=>t.position),s=t.map(t=>t.label),i=t.map(t=>t.options),a=this.oldData.map(t=>t.position);return this.render(a.map((t,e)=>({position:a[e],label:s[e],options:i[e]}))),this.store.map((t,s)=>tt(t,e[s],a[s]))}},yRegions:{layerClass:"y-regions",makeElements(t){return t.map(t=>function(t,e,s,i,a={}){let n=t-e,r=Y("rect",{className:"bar mini",styles:{fill:"rgba(228, 234, 239, 0.49)",stroke:"#dadada","stroke-dasharray":`${s}, ${n}`},x:0,y:0,width:s,height:n});a.labelPos||(a.labelPos="right");let o=Y("text",{className:"chart-label",x:"left"===a.labelPos?4:s-S(i+"",4.5)-4,y:0,dy:"-5px","font-size":"10px","text-anchor":"start",innerHTML:i+""}),l=Y("g",{transform:`translate(0, ${e})`});return l.appendChild(r),l.appendChild(o),l}(t.startPos,t.endPos,this.constants.width,t.label,{labelPos:t.options.labelPos}))},animateElements(t){[this.oldData,t]=$(this.oldData,t);let e=t.map(t=>t.endPos),s=t.map(t=>t.label),i=t.map(t=>t.startPos),a=t.map(t=>t.options),n=this.oldData.map(t=>t.endPos),r=this.oldData.map(t=>t.startPos);this.render(n.map((t,e)=>({startPos:r[e],endPos:n[e],label:s[e],options:a[e]})));let o=[];return this.store.map((t,s)=>{o=o.concat(function(t,e,s,i){let a=e-s,n=t.childNodes[0],r=n.getAttribute("width");return[[n,{height:a,"stroke-dasharray":`${r}, ${a}`},350,"easein"],Z(t,[0,i],[0,s],350)]}(t,i[s],e[s],n[s]))}),o}},heatDomain:{layerClass:function(){return"heat-domain domain-"+this.constants.index},makeElements(t){let{index:e,colWidth:s,rowHeight:i,squareSize:a,xTranslate:n}=this.constants,r=n,o=0;return this.serializedSubDomains=[],t.cols.map((t,n)=>{1===n&&this.labels.push(q("domain-name",r,-12,mt(e,!0).toUpperCase(),{fontSize:9})),t.map((t,e)=>{if(t.fill){let s={"data-date":t.yyyyMmDd,"data-value":t.dataValue,"data-day":e},i=G("day",r,o,a,t.fill,s);this.serializedSubDomains.push(i)}o+=i}),o=0,r+=s}),this.serializedSubDomains},animateElements(t){if(t)return[]}},barGraph:{layerClass:function(){return"dataset-units dataset-bars dataset-"+this.constants.index},makeElements(t){let e=this.constants;return this.unitType="bar",this.units=t.yPositions.map((s,i)=>function(t,e,s,i,a="",n=0,r=0,o={}){let[l,h]=W(e,o.zeroLine);h-=r,0===l&&(l=o.minHeight,h-=o.minHeight);let d=Y("rect",{className:"bar mini",style:"fill: "+i,"data-point-index":n,x:t,y:h,width:s,height:l});if((a+="")||a.length){d.setAttribute("y",0),d.setAttribute("x",0);let e=Y("text",{className:"data-point-value",x:s/2,y:0,dy:"-5px","font-size":"10px","text-anchor":"middle",innerHTML:a}),i=Y("g",{"data-point-index":n,transform:`translate(${t}, ${h})`});return i.appendChild(d),i.appendChild(e),i}return d}(t.xPositions[i],s,t.barWidth,e.color,t.labels[i],i,t.offsets[i],{zeroLine:t.zeroLine,barsWidth:t.barsWidth,minHeight:e.minHeight})),this.units},animateElements(t){let e=t.xPositions,s=t.yPositions,i=t.offsets,a=t.labels,n=this.oldData.xPositions,r=this.oldData.yPositions,o=this.oldData.offsets,l=this.oldData.labels;[n,e]=$(n,e),[r,s]=$(r,s),[o,i]=$(o,i),[l,a]=$(l,a),this.render({xPositions:n,yPositions:r,offsets:o,labels:a,zeroLine:this.oldData.zeroLine,barsWidth:this.oldData.barsWidth,barWidth:this.oldData.barWidth});let h=[];return this.store.map((a,n)=>{h=h.concat(function(t,e,s,i,a=0,n={}){let[r,o]=W(s,n.zeroLine);if(o-=a,"rect"!==t.nodeName){let s=[t.childNodes[0],{width:i,height:r},350,"easein"],a=t.getAttribute("transform").split("(")[1].slice(0,-1);return[s,Z(t,a,[e,o],350)]}return[[t,{width:i,height:r,x:e,y:o},350,"easein"]]}(a,e[n],s[n],t.barWidth,i[n],{zeroLine:t.zeroLine}))}),h}},lineGraph:{layerClass:function(){return"dataset-units dataset-line dataset-"+this.constants.index},makeElements(t){let e=this.constants;return this.unitType="dot",this.paths={},e.hideLine||(this.paths=function(t,e,s,i={},a={}){let n=e.map((e,s)=>t[s]+","+e).join("L"),r=V("M"+n,"line-graph-path",s);if(i.heatline){let t=U(a.svgDefs,s);r.style.stroke=`url(#${t})`}let o={path:r};if(i.regionFill){let e=U(a.svgDefs,s,!0),i=`M${t[0]},${a.zeroLine}L`+n+`L${t.slice(-1)[0]},${a.zeroLine}`;o.region=V(i,"region-fill","none",`url(#${e})`)}return o}(t.xPositions,t.yPositions,e.color,{heatline:e.heatline,regionFill:e.regionFill},{svgDefs:e.svgDefs,zeroLine:t.zeroLine})),this.units=[],e.hideDots||(this.units=t.yPositions.map((s,i)=>function(t,e,s,i,a="",n=0){let r=Y("circle",{style:"fill: "+i,"data-point-index":n,cx:t,cy:e,r:s});if((a+="")||a.length){r.setAttribute("cy",0),r.setAttribute("cx",0);let i=Y("text",{className:"data-point-value",x:0,y:0,dy:-5-s+"px","font-size":"10px","text-anchor":"middle",innerHTML:a}),o=Y("g",{"data-point-index":n,transform:`translate(${t}, ${e})`});return o.appendChild(r),o.appendChild(i),o}return r}(t.xPositions[i],s,t.radius,e.color,e.valuesOverPoints?t.values[i]:"",i))),Object.values(this.paths).concat(this.units)},animateElements(t){let e=t.xPositions,s=t.yPositions,i=t.values,a=this.oldData.xPositions,n=this.oldData.yPositions,r=this.oldData.values;[a,e]=$(a,e),[n,s]=$(n,s),[r,i]=$(r,i),this.render({xPositions:a,yPositions:n,values:i,zeroLine:this.oldData.zeroLine,radius:this.oldData.radius});let o=[];return Object.keys(this.paths).length&&(o=o.concat(function(t,e,s,i){let a=[],n=s.map((t,s)=>e[s]+","+t).join("L");const r=[t.path,{d:"M"+n},350,"easein"];if(a.push(r),t.region){let s=`${e[0]},${i}L`,r=`L${e.slice(-1)[0]}, ${i}`;const o=[t.region,{d:"M"+s+n+r},350,"easein"];a.push(o)}return a}(this.paths,e,s,t.zeroLine))),this.units.length&&this.units.map((t,i)=>{o=o.concat(function(t,e,s){if("circle"!==t.nodeName){let i=t.getAttribute("transform").split("(")[1].slice(0,-1);return[Z(t,i,[e,s],350)]}return[[t,{cx:e,cy:s},350,"easein"]]}(t,e[i],s[i]))}),o}}};function vt(t,e,s){let i=Object.keys(xt).filter(e=>t.includes(e)),a=xt[i[0]];return Object.assign(a,{constants:e,getData:s}),new bt(a)}function wt(t){if(0===t)return[0,0];if(isNaN(t))return{mantissa:-6755399441055744,exponent:972};var e=t>0?1:-1;if(!isFinite(t))return{mantissa:4503599627370496*e,exponent:972};t=Math.abs(t);var s=Math.floor(Math.log10(t));return[e*(t/Math.pow(10,s)),s]}function At(t,e=0){let[s,i]=wt(t),a=e?e/Math.pow(10,i):0;s=s.toFixed(6);let n=function(t,e=0){let s=Math.ceil(t),i=Math.floor(e),a=s-i,n=a,r=1;a>5&&(a%2!=0&&(s++,a=s-i),n=a/2,r=2),a<=2&&(n=4,r=a/n),0===a&&(n=5,r=1);let o=[];for(var l=0;l<=n;l++)o.push(i+r*l);return o}(s,a);return n=n.map(t=>t*Math.pow(10,i)),n}function Pt(t){return t[1]-t[0]}function kt(t,e){return O(e.zeroLine-t*e.scaleMultiplier)}class Ct extends nt{constructor(t,e){super(t,e),this.barOptions=e.barOptions||{},this.lineOptions=e.lineOptions||{},this.type=e.type||"line",this.init=1,this.setup()}setMeasures(){this.data.datasets.length<=1&&(this.config.showLegend=0,this.measures.paddings.bottom=30)}configure(t){super.configure(t),t.axisOptions=t.axisOptions||{},t.tooltipOptions=t.tooltipOptions||{},this.config.xAxisMode=t.axisOptions.xAxisMode||"span",this.config.yAxisMode=t.axisOptions.yAxisMode||"span",this.config.xIsSeries=t.axisOptions.xIsSeries||0,this.config.formatTooltipX=t.tooltipOptions.formatTooltipX,this.config.formatTooltipY=t.tooltipOptions.formatTooltipY,this.config.valuesOverPoints=t.valuesOverPoints}prepareData(t=this.data){return function(t,e){t.labels=t.labels||[];let s=t.labels.length,i=t.datasets,a=new Array(s).fill(0);return i||(i=[{values:a}]),i.map(t=>{if(t.values){let e=t.values;e=e.map(t=>isNaN(t)?0:t),e=e.length>s?e.slice(0,s):E(e,s-e.length,0)}else t.values=a;t.chartType||(D.includes(e),t.chartType=e)}),t.yRegions&&t.yRegions.map(t=>{t.end({name:"",values:s.slice(0,-1),chartType:t.chartType}))};return t.yMarkers&&(i.yMarkers=[{value:0,label:""}]),t.yRegions&&(i.yRegions=[{start:0,end:0,label:""}]),i}(t)}calc(t=!1){this.calcXPositions(),t||this.calcYAxisParameters(this.getAllYValues(),"line"===this.type),this.makeDataByIndex()}calcXPositions(){let t=this.state,e=this.data.labels;t.datasetLength=e.length,t.unitWidth=this.width/t.datasetLength,t.xOffset=t.unitWidth/2,t.xAxis={labels:e,positions:e.map((e,s)=>O(t.xOffset+s*t.unitWidth))}}calcYAxisParameters(t,e="false"){const s=function(t,e=!1){let s=Math.max(...t),i=Math.min(...t),a=0,n=[];function r(t,e){let s=At(t),i=s[1]-s[0],a=0;for(var n=1;a=0&&i>=0)a=wt(s)[1],n=e?At(s,i):At(s);else if(s>0&&i<0){let t=Math.abs(i);if(s>=t)a=wt(s)[1],n=r(s,t);else{a=wt(t)[1],n=r(t,s).map(t=>-1*t)}}else if(s<=0&&i<=0){let t=Math.abs(i),r=Math.abs(s);a=wt(t)[1],n=e?At(t,r):At(t),n=n.reverse().map(t=>-1*t)}return n}(t,e),i=this.height/((a=s)[a.length-1]-a[0]);var a;const n=Pt(s)*i,r=this.height-function(t){let e,s=Pt(t);if(t.indexOf(0)>=0)e=t.indexOf(0);else if(t[0]>0){e=-1*t[0]/s}else{e=-1*t[t.length-1]/s+(t.length-1)}return e}(s)*n;this.state.yAxis={labels:s,positions:s.map(t=>r-t*i),scaleMultiplier:i,zeroLine:r},this.calcDatasetPoints(),this.calcYExtremes(),this.calcYRegions()}calcDatasetPoints(){let t=this.state,e=e=>e.map(e=>kt(e,t.yAxis));t.datasets=this.data.datasets.map((t,s)=>{let i=t.values,a=t.cumulativeYs||[];return{name:t.name,index:s,chartType:t.chartType,values:i,yPositions:e(i),cumulativeYs:a,cumulativeYPos:e(a)}})}calcYExtremes(){let t=this.state;this.barOptions.stacked?t.yExtremes=t.datasets[t.datasets.length-1].cumulativeYPos:(t.yExtremes=new Array(t.datasetLength).fill(9999),t.datasets.map(e=>{e.yPositions.map((e,s)=>{e(e.position=kt(e.value,t.yAxis),e.options||(e.options={}),e))),this.data.yRegions&&(this.state.yRegions=this.data.yRegions.map(e=>(e.startPos=kt(e.start,t.yAxis),e.endPos=kt(e.end,t.yAxis),e.options||(e.options={}),e)))}getAllYValues(){let t="values";if(this.barOptions.stacked){t="cumulativeYs";let e=new Array(this.state.datasetLength).fill(0);this.data.datasets.map((s,i)=>{let a=this.data.datasets[i].values;s[t]=e=e.map((t,e)=>t+a[e])})}let e=this.data.datasets.map(e=>e[t]);return this.data.yMarkers&&e.push(this.data.yMarkers.map(t=>t.value)),this.data.yRegions&&this.data.yRegions.map(t=>{e.push([t.end,t.start])}),[].concat(...e)}setupComponents(){let t=[["yAxis",{mode:this.config.yAxisMode,width:this.width},function(){return this.state.yAxis}.bind(this)],["xAxis",{mode:this.config.xAxisMode,height:this.height},function(){let t=this.state;return t.xAxis.calcLabels=function(t,e=[],s=!0){let i=t/e.length;i<=0&&(i=1);let a=i/7;return e.map((t,e)=>{if((t+="").length>a)if(s){e%Math.ceil(t.length/a)!=0&&(t="")}else t=a-3>0?t.slice(0,a-3)+" ...":t.slice(0,a)+"..";return t})}(this.width,t.xAxis.labels,this.config.xIsSeries),t.xAxis}.bind(this)],["yRegions",{width:this.width,pos:"right"},function(){return this.state.yRegions}.bind(this)]],e=this.state.datasets.filter(t=>"bar"===t.chartType),s=this.state.datasets.filter(t=>"line"===t.chartType),i=e.map(t=>{let s=t.index;return["barGraph-"+t.index,{index:s,color:this.colors[s],stacked:this.barOptions.stacked,valuesOverPoints:this.config.valuesOverPoints,minHeight:.01*this.height},function(){let t=this.state,i=t.datasets[s],a=this.barOptions.stacked,n=this.barOptions.spaceRatio||.5,r=t.unitWidth*(1-n),o=r/(a?1:e.length),l=t.xAxis.positions.map(t=>t-r/2);a||(l=l.map(t=>t+o*s));let h=new Array(t.datasetLength).fill("");this.config.valuesOverPoints&&(h=a&&i.index===t.datasets.length-1?i.cumulativeYs:i.values);let d=new Array(t.datasetLength).fill(0);return a&&(d=i.yPositions.map((t,e)=>t-i.cumulativeYPos[e])),{xPositions:l,yPositions:i.yPositions,offsets:d,labels:h,zeroLine:t.yAxis.zeroLine,barsWidth:r,barWidth:o}}.bind(this)]}),a=s.map(t=>{let e=t.index;return["lineGraph-"+t.index,{index:e,color:this.colors[e],svgDefs:this.svgDefs,heatline:this.lineOptions.heatline,regionFill:this.lineOptions.regionFill,hideDots:this.lineOptions.hideDots,hideLine:this.lineOptions.hideLine,valuesOverPoints:this.config.valuesOverPoints},function(){let t=this.state,s=t.datasets[e],i=t.yAxis.positions[0]!r.includes(t[0])||this.state[t[0]]).map(t=>{let e=vt(...t);return(t[0].includes("lineGraph")||t[0].includes("barGraph"))&&this.dataUnitComponents.push(e),[t[0],e]}))}makeDataByIndex(){this.dataByIndex={};let t=this.state,e=this.config.formatTooltipX,s=this.config.formatTooltipY;t.xAxis.labels.map((i,a)=>{let n=this.state.datasets.map((t,e)=>{let i=t.values[a];return{title:t.name,value:i,yPos:t.yPositions[a],color:this.colors[e],formatted:s?s(i):i}});this.dataByIndex[a]={label:i,formattedLabel:e?e(i):i,xPos:t.xAxis.positions[a],values:n,yExtreme:t.yExtremes[a]}})}bindTooltip(){this.container.addEventListener("mousemove",t=>{let e=this.measures,s=v(this.container),i=t.pageX-s.left-P(e),a=t.pageY-s.top;aA(e)?this.mapTooltipXPosition(i):this.tip.hideTip()})}mapTooltipXPosition(t){let e=this.state;if(!e.yExtremes)return;let s=function(t,e,s=!1){let i=e.reduce((function(e,s){return Math.abs(s-t)1&&(this.legendArea.textContent="",t.datasets.map((t,e)=>{let s=function(t,e,s,i="none",a){let n={className:"legend-bar",x:0,y:0,width:s,height:"2px",fill:i},r=Y("text",{className:"legend-dataset-text",x:0,y:0,dy:"20px","font-size":"12px","text-anchor":"start",fill:"#555b51",innerHTML:a}),o=Y("g",{transform:`translate(${t}, ${e})`});return o.appendChild(Y("rect",n)),o.appendChild(r),o}(100*e,"0",100,this.colors[e],t.name);this.legendArea.appendChild(s)}))}makeOverlay(){this.init?this.init=0:(this.overlayGuides&&this.overlayGuides.forEach(t=>{let e=t.overlay;e.parentNode.removeChild(e)}),this.overlayGuides=this.dataUnitComponents.map(t=>({type:t.unitType,overlay:void 0,units:t.units})),void 0===this.state.currentIndex&&(this.state.currentIndex=this.state.datasetLength-1),this.overlayGuides.map(t=>{let e=t.units[this.state.currentIndex];t.overlay=K[t.type](e),this.drawArea.appendChild(t.overlay)}))}updateOverlayGuides(){this.overlayGuides&&this.overlayGuides.forEach(t=>{let e=t.overlay;e.parentNode.removeChild(e)})}bindOverlay(){this.parent.addEventListener("data-select",()=>{this.updateOverlay()})}bindUnits(){this.dataUnitComponents.map(t=>{t.units.map(t=>{t.addEventListener("click",()=>{let e=t.getAttribute("data-point-index");this.setCurrentDataPoint(e)})})}),this.tip.container.addEventListener("click",()=>{let t=this.tip.container.getAttribute("data-point-index");this.setCurrentDataPoint(t)})}updateOverlay(){this.overlayGuides.map(t=>{let e=t.units[this.state.currentIndex];Q[t.type](e,t.overlay)})}onLeftArrow(){this.setCurrentDataPoint(this.state.currentIndex-1)}onRightArrow(){this.setCurrentDataPoint(this.state.currentIndex+1)}getDataPoint(t=this.state.currentIndex){let e=this.state;return{index:t,label:e.xAxis.labels[t],values:e.datasets.map(e=>e.values[t])}}setCurrentDataPoint(t){let e=this.state;(t=parseInt(t))<0&&(t=0),t>=e.xAxis.labels.length&&(t=e.xAxis.labels.length-1),t!==e.currentIndex&&(e.currentIndex=t,function(t,e,s){var i=document.createEvent("HTMLEvents");for(var a in i.initEvent(e,!0,!0),s)i[a]=s[a];t.dispatchEvent(i)}(this.parent,"data-select",this.getDataPoint()))}addDataPoint(t,e,s=this.state.datasetLength){super.addDataPoint(t,e,s),this.data.labels.splice(s,0,t),this.data.datasets.map((t,i)=>{t.values.splice(s,0,e[i])}),this.update(this.data)}removeDataPoint(t=this.state.datasetLength-1){this.data.labels.length<=1||(super.removeDataPoint(t),this.data.labels.splice(t,1),this.data.datasets.map(e=>{e.values.splice(t,1)}),this.update(this.data))}updateDataset(t,e=0){this.data.datasets[e].values=t,this.update(this.data)}updateDatasets(t){this.data.datasets.map((e,s)=>{t[s]&&(e.values=t[s])}),this.update(this.data)}}const Dt={bar:Ct,line:Ct,percentage:class extends rt{constructor(t,e){super(t,e),this.type="percentage",this.setup()}setMeasures(t){let e=this.measures;this.barOptions=t.barOptions||{};let s=this.barOptions;s.height=s.height||20,s.depth=s.depth||2,e.paddings.right=30,e.legendHeight=80,e.baseHeight=8*(s.height+.5*s.depth)}setupComponents(){let t=this.state,e=[["percentageBars",{barHeight:this.barOptions.height,barDepth:this.barOptions.depth},function(){return{xPositions:t.xPositions,widths:t.widths,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(t=>{let e=vt(...t);return[t[0],e]}))}calc(){super.calc();let t=this.state;t.xPositions=[],t.widths=[];let e=0;t.sliceTotals.map(s=>{let i=this.width*s/t.grandTotal;t.widths.push(i),t.xPositions.push(e),e+=i})}makeDataByIndex(){}bindTooltip(){let t=this.state;this.container.addEventListener("mousemove",e=>{let s=this.components.get("percentageBars").store,i=e.target;if(s.includes(i)){let e=s.indexOf(i),a=v(this.container),n=v(i),r=n.left-a.left+parseInt(i.getAttribute("width"))/2,o=n.top-a.top,l=(this.formattedLabels&&this.formattedLabels.length>0?this.formattedLabels[e]:this.state.labels[e])+": ",h=t.sliceTotals[e]/t.grandTotal;this.tip.setValues(r,o,{name:l,value:(100*h).toFixed(1)+"%"}),this.tip.showTip()}})}},heatmap:class extends nt{constructor(t,e){super(t,e),this.type="heatmap",this.countLabel=e.countLabel||"";let s=["Sunday","Monday"],i=s.includes(e.startSubDomain)?e.startSubDomain:"Sunday";this.startSubDomainIndex=s.indexOf(i),this.setup()}setMeasures(t){let e=this.measures;this.discreteDomains=0===t.discreteDomains?0:1,e.paddings.top=36,e.paddings.bottom=0,e.legendHeight=24,e.baseHeight=84+k(e);let s=this.data,i=this.discreteDomains?12:0;this.independentWidth=12*(pt(s.start,s.end)+i)+C(e)}updateWidth(){let t=this.discreteDomains?12:0,e=this.state.noOfWeeks?this.state.noOfWeeks:52;this.baseWidth=12*(e+t)+C(this.measures)}prepareData(t=this.data){if(t.start&&t.end&&t.start>t.end)throw new Error("Start date cannot be greater than end date.");if(t.start||(t.start=new Date,t.start.setFullYear(t.start.getFullYear()-1)),t.end||(t.end=new Date),t.dataPoints=t.dataPoints||{},parseInt(Object.keys(t.dataPoints)[0])>1e5){let e={};Object.keys(t.dataPoints).forEach(s=>{let i=new Date(1e3*s);e[dt(i)]=t.dataPoints[s]}),t.dataPoints=e}return t}calc(){let t=this.state;t.start=ct(this.data.start),t.end=ct(this.data.end),t.firstWeekStart=ct(t.start),t.noOfWeeks=pt(t.start,t.end),t.distribution=function(t,e){let s=Math.max(...t),i=1/(e-1),a=[];for(var n=0;n["heatDomain",{index:s.index,colWidth:12,rowHeight:12,squareSize:10,xTranslate:12*t.domainConfigs.filter((t,e)=>et.cols.length-e).reduce((t,e)=>t+e,0)},function(){return t.domainConfigs[i]}.bind(this)]);this.components=new Map(s.map((t,e)=>{let s=vt(...t);return[t[0]+"-"+e,s]}));let i=0;lt.forEach((t,e)=>{if([1,3,5].includes(e)){let e=q("subdomain-name",-6,i,t,{fontSize:10,dy:8,textAnchor:"end"});this.drawArea.appendChild(e)}i+=12})}update(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.draw(),this.bindTooltip()}bindTooltip(){this.container.addEventListener("mousemove",t=>{this.components.forEach(e=>{let s=e.store,i=t.target;if(s.includes(i)){let e=i.getAttribute("data-value"),s=i.getAttribute("data-date").split("-"),a=mt(parseInt(s[1])-1,!0),n=this.container.getBoundingClientRect(),r=i.getBoundingClientRect(),o=parseInt(t.target.getAttribute("width")),l=r.left-n.left+o/2,h=r.top-n.top,d=e+" "+this.countLabel,c=" on "+a+" "+s[0]+", "+s[2];this.tip.setValues(l,h,{name:c,value:d,valueFirst:1},[]),this.tip.showTip()}})})}renderLegend(){this.legendArea.textContent="";let t=0,e=q("subdomain-name",t,12,"Less",{fontSize:11,dy:9});t=30,this.legendArea.appendChild(e),this.colors.slice(0,5).map((e,s)=>{const i=G("heatmap-legend-unit",t+15*s,12,10,e);this.legendArea.appendChild(i)});let s=q("subdomain-name",t+75+3,12,"More",{fontSize:11,dy:9});this.legendArea.appendChild(s)}getDomains(){let t=this.state;const[e,s]=[t.start.getMonth(),t.start.getFullYear()],[i,a]=[t.end.getMonth(),t.end.getFullYear()],n=i-e+1+12*(a-s);let r=[],o=ct(t.start);for(var l=0;l=i.start&&a<=i.end;s||a.getMonth()!==e||!r?t.yyyyMmDd=dt(a):t=this.getSubDomainConfig(a),n.push(t)}return n}getSubDomainConfig(t){let e=dt(t),s=this.data.dataPoints[e];var i,a;return{yyyyMmDd:e,dataValue:s||0,fill:this.colors[(i=s,a=this.state.distribution,a.filter(t=>tthis.width?this.center.x:this.center.y;const{radius:e,clockWise:s}=this,i=t.slicesProperties||[];t.sliceStrings=[],t.slicesProperties=[];let a=180-this.config.startAngle;t.sliceTotals.map((n,r)=>{const o=a,l=n/t.grandTotal*360,h=s?-l:l,d=a+=h,c=z(o,e),p=z(d,e),u=this.init&&i[r];let m,f;this.init?(m=u?u.startPosition:c,f=u?u.endPosition:c):(m=c,f=p);const g=function(t,e,s,i,a=1){let[n,r]=[s.x+t.x,s.y+t.y],[o,l]=[s.x+e.x,s.y+e.y];return`M${s.x} ${s.y}\n\t\tL${n} ${r}\n\t\tA ${i} ${i} 0 0 ${a?1:0}\n\t\t${o} ${l} z`}(m,f,this.center,this.radius,this.clockWise);t.sliceStrings.push(g),t.slicesProperties.push({startPosition:c,endPosition:p,value:n,total:t.grandTotal,startAngle:o,endAngle:d,angle:h})}),this.init=0}setupComponents(){let t=this.state,e=[["pieSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(t=>{let e=vt(...t);return[t[0],e]}))}calTranslateByAngle(t){const{radius:e,hoverRadio:s}=this,i=z(t.startAngle+t.angle/2,e);return`translate3d(${i.x*s}px,${i.y*s}px,0)`}hoverSlice(t,e,s,i){if(!t)return;const a=this.colors[e];if(s){st(t,this.calTranslateByAngle(this.state.slicesProperties[e])),t.style.fill=j(a,50);let s=v(this.svg),n=i.pageX-s.left+10,r=i.pageY-s.top-10,o=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[e]:this.state.labels[e])+": ",l=(100*this.state.sliceTotals[e]/this.state.grandTotal).toFixed(1);this.tip.setValues(n,r,{name:o,value:l+"%"}),this.tip.showTip()}else st(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.fill=a}bindTooltip(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}mouseMove(t){const e=t.target;let s=this.components.get("pieSlices").store,i=this.curActiveSliceIndex,a=this.curActiveSlice;if(s.includes(e)){let n=s.indexOf(e);this.hoverSlice(a,i,!1),this.curActiveSlice=e,this.curActiveSliceIndex=n,this.hoverSlice(e,n,!0,t)}else this.mouseLeave()}mouseLeave(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}};class Lt{constructor(t,e){return function(t="line",e,s){return"axis-mixed"===t?(s.type="line",new Ct(e,s)):Dt[t]?new Dt[t](e,s):void console.error("Undefined chart type: "+t)}(e.type,t,e)}}var Tt=function(t){var e,s;function i(){return t.apply(this,arguments)||this}s=t,(e=i).prototype=Object.create(s.prototype),e.prototype.constructor=e,e.__proto__=s;var a=i.prototype;return a.init=function(){t.prototype.init.call(this);var e=new Date;e.setTime(e.getTime()+1e3*app.data.statistics.timezoneOffset),e.setUTCHours(0,0,0,0),e.setTime(e.getTime()-1e3*app.data.statistics.timezoneOffset),e/=1e3,this.entities=["users","discussions","posts"],this.periods={today:{start:e,end:e+86400,step:3600},last_7_days:{start:e-604800,end:e,step:86400},last_28_days:{start:e-2419200,end:e,step:86400},last_12_months:{start:e-31449600,end:e,step:604800}},this.selectedEntity="users",this.selectedPeriod="last_7_days"},a.className=function(){return"StatisticsWidget"},a.content=function(){var t=this,e=this.periods[this.selectedPeriod];return m("div",{className:"StatisticsWidget-table"},m("div",{className:"StatisticsWidget-labels"},m("div",{className:"StatisticsWidget-label"},app.translator.trans("flarum-statistics.admin.statistics.total_label")),m("div",{className:"StatisticsWidget-label"},m(c.a,{buttonClassName:"Button Button--text",caretIcon:"fas fa-caret-down"},Object.keys(this.periods).map((function(e){return m(u.a,{active:e===t.selectedPeriod,onclick:t.changePeriod.bind(t,e),icon:e!==t.selectedPeriod||"fas fa-check"},app.translator.trans("flarum-statistics.admin.statistics."+e+"_label"))}))))),this.entities.map((function(s){var i=t.getTotalCount(s),a=t.getPeriodCount(s,e),n=t.getPeriodCount(s,t.getLastPeriod(e)),r=n>0&&(a-n)/n*100;return m("a",{className:"StatisticsWidget-entity"+(t.selectedEntity===s?" active":""),onclick:t.changeEntity.bind(t,s)},m("h3",{className:"StatisticsWidget-heading"},app.translator.trans("flarum-statistics.admin.statistics."+s+"_heading")),m("div",{className:"StatisticsWidget-total",title:i},b()(i)),m("div",{className:"StatisticsWidget-period",title:a},b()(a)," ",r?m("span",{className:"StatisticsWidget-change StatisticsWidget-change--"+(r>0?"up":"down")},g()("fas fa-arrow-"+(r>0?"up":"down")),Math.abs(r.toFixed(1)),"%"):""))})),m("div",{className:"StatisticsWidget-chart",config:this.drawChart.bind(this)}))},a.drawChart=function(t,e,s){if(!s.chart||s.entity!==this.selectedEntity||s.period!==this.selectedPeriod){for(var i=app.data.statistics.timezoneOffset,a=this.periods[this.selectedPeriod],n=a.end-a.start,r=[],o=[],l=[],h=a.start;h86400&&(d+=" - "+dayjs.unix(h+i+a.step-1).format("D MMM"))),r.push(d),o.push(this.getPeriodCount(this.selectedEntity,{start:h,end:h+a.step})),l.push(this.getPeriodCount(this.selectedEntity,{start:h-n,end:h-n+a.step}))}var c={labels:r,datasets:[{values:l},{values:o}]};s.chart?s.chart.update(c):s.chart=new Lt(t,{data:c,type:"line",height:280,axisOptions:{xAxisMode:"tick",yAxisMode:"span",xIsSeries:!0},lineOptions:{hideDots:1},colors:["black",app.forum.attribute("themePrimaryColor")]}),s.entity=this.selectedEntity,s.period=this.selectedPeriod}},a.changeEntity=function(t){this.selectedEntity=t},a.changePeriod=function(t){this.selectedPeriod=t},a.getTotalCount=function(t){return app.data.statistics[t].total},a.getPeriodCount=function(t,e){var s=app.data.statistics[t].timed,i=0;for(var a in s)a>=e.start&&a{var s=document.createElement(t);for(var i in e){var a=e[i];if("inside"===i)x(a).appendChild(s);else if("around"===i){var n=x(a);n.parentNode.insertBefore(s,n),s.appendChild(n)}else"styles"===i?"object"==typeof a&&Object.keys(a).map(t=>{s.style[t]=a[t]}):i in s?s[i]=a:s.setAttribute(i,a)}return s};const w={margins:{top:10,bottom:10,left:20,right:20},paddings:{top:20,bottom:40,left:30,right:10},baseHeight:240,titleHeight:20,legendHeight:30,titleFontSize:12};function A(t){return t.titleHeight+t.margins.top+t.paddings.top}function P(t){return t.margins.left+t.paddings.left}function k(t){return t.margins.top+t.margins.bottom+t.paddings.top+t.paddings.bottom+t.titleHeight+t.legendHeight}function C(t){return t.margins.left+t.margins.right+t.paddings.left+t.paddings.right}const D=["line","bar"],L=["light-blue","blue","violet","red","orange","yellow","green","light-green","purple","magenta","light-grey","dark-grey"],T={bar:L,line:L,pie:L,percentage:L,heatmap:["#ebedf0","#c6e48b","#7bc96f","#239a3b","#196127"]},M=Math.PI/180;class N{constructor({parent:t=null,colors:e=[]}){this.parent=t,this.colors=e,this.titleName="",this.titleValue="",this.listValues=[],this.titleValueFirst=0,this.x=0,this.y=0,this.top=0,this.left=0,this.setup()}setup(){this.makeTooltip()}refresh(){this.fill(),this.calcPosition()}makeTooltip(){this.container=x.create("div",{inside:this.parent,className:"graph-svg-tip comparison",innerHTML:'\n\t\t\t\t
    \n\t\t\t\t
    '}),this.hideTip(),this.title=this.container.querySelector(".title"),this.dataPointList=this.container.querySelector(".data-point-list"),this.parent.addEventListener("mouseleave",()=>{this.hideTip()})}fill(){let t;this.index&&this.container.setAttribute("data-point-index",this.index),t=this.titleValueFirst?`${this.titleValue}${this.titleName}`:`${this.titleName}${this.titleValue}`,this.title.innerHTML=t,this.dataPointList.innerHTML="",this.listValues.map((t,e)=>{const s=this.colors[e]||"black";let i=0===t.formatted||t.formatted?t.formatted:t.value,a=x.create("li",{styles:{"border-top":"3px solid "+s},innerHTML:`${0===i||i?i:""}\n\t\t\t\t\t${t.title?t.title:""}`});this.dataPointList.appendChild(a)})}calcPosition(){let t=this.container.offsetWidth;this.top=this.y-this.container.offsetHeight-5,this.left=this.x-t/2;let e=this.parent.offsetWidth-t,s=this.container.querySelector(".svg-pointer");if(this.left<0)s.style.left=`calc(50% - ${-1*this.left}px)`,this.left=0;else if(this.left>e){let t=`calc(50% + ${this.left-e}px)`;s.style.left=t,this.left=e}else s.style.left="50%"}setValues(t,e,s={},i=[],a=-1){this.titleName=s.name,this.titleValue=s.value,this.listValues=i,this.x=t,this.y=e,this.titleValueFirst=s.valueFirst||0,this.index=a,this.refresh()}hideTip(){this.container.style.top="0px",this.container.style.left="0px",this.container.style.opacity="0"}showTip(){this.container.style.top=this.top+"px",this.container.style.left=this.left+"px",this.container.style.opacity="1"}}function O(t){return parseFloat(t.toFixed(2))}function E(t,e,s,i=!1){s||(s=i?t[0]:t[t.length-1]);let a=new Array(Math.abs(e)).fill(s);return t=i?a.concat(t):t.concat(a)}function S(t,e){return(t+"").length*e}function z(t,e){return{x:Math.sin(t*M)*e,y:Math.cos(t*M)*e}}function W(t,e){let s,i;return t<=e?(s=e-t,i=t):(s=t-e,i=e),[s,i]}function $(t,e,s=e.length-t.length){return s>0?t=E(t,s):e=E(e,s),[t,e]}const H={"light-blue":"#7cd6fd",blue:"#5e64ff",violet:"#743ee2",red:"#ff5858",orange:"#ffa00a",yellow:"#feef72",green:"#28a745","light-green":"#98d85b",purple:"#b554ff",magenta:"#ffa3ef",black:"#36114C",grey:"#bdd3e6","light-grey":"#f0f4f7","dark-grey":"#b8c2cc"};function F(t){return t>255?255:t<0?0:t}function j(t,e){let s=I(t),i=!1;"#"==s[0]&&(s=s.slice(1),i=!0);let a=parseInt(s,16),n=F((a>>16)+e),r=F((a>>8&255)+e);return(i?"#":"")+(F((255&a)+e)|r<<8|n<<16).toString(16)}const I=t=>H[t]||t;function R(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function Y(t,e){var s=document.createElementNS("http://www.w3.org/2000/svg",t);for(var i in e){var a=e[i];if("inside"===i)R(a).appendChild(s);else if("around"===i){var n=R(a);n.parentNode.insertBefore(s,n),s.appendChild(n)}else"styles"===i?"object"==typeof a&&Object.keys(a).map(t=>{s.style[t]=a[t]}):("className"===i&&(i="class"),"innerHTML"===i?s.textContent=a:s.setAttribute(i,a))}return s}function _(t,e,s,i){return Y("stop",{inside:t,style:"stop-color: "+s,offset:e,"stop-opacity":i})}function B(t,e="",s){let i={className:t,transform:e};return s&&(i.inside=s),Y("g",i)}function V(t,e="",s="none",i="none"){return Y("path",{className:e,d:t,styles:{stroke:s,fill:i}})}function U(t,e,s=!1){let i="path-fill-gradient-"+e+"-"+(s?"lighter":"default"),a=function(t,e){return Y("linearGradient",{inside:t,id:e,x1:0,x2:0,y1:0,y2:1})}(t,i),n=[1,.6,.2];return s&&(n=[.4,.2,0]),_(a,"0%",e,n[0]),_(a,"50%",e,n[1]),_(a,"100%",e,n[2]),i}function G(t,e,s,i,a="none",n={}){let r={className:t,x:e,y:s,width:i,height:i,fill:a};return Object.keys(n).map(t=>{r[t]=n[t]}),Y("rect",r)}function q(t,e,s,i,a={}){let n=a.fontSize||10;return Y("text",{className:t,x:e,y:s,dy:(void 0!==a.dy?a.dy:n/2)+"px","font-size":n+"px",fill:a.fill||"#555b51","text-anchor":a.textAnchor||"start",innerHTML:i})}function X(t,e,s,i,a={}){a.stroke||(a.stroke="#dadada"),a.lineType||(a.lineType="");let n=Y("line",{className:"line-horizontal "+a.className+("dashed"===a.lineType?"dashed":""),x1:s,x2:i,y1:0,y2:0,styles:{stroke:a.stroke}}),r=Y("text",{x:si?s+4:s-4-10,dy:"10px","font-size":"10px","text-anchor":"middle",innerHTML:e+""}),o=Y("g",{transform:`translate(${t}, 0)`});return o.appendChild(n),o.appendChild(r),o}(t,e,a,n,{stroke:i.stroke,className:i.className,lineType:i.lineType})}let K={bar:t=>{let e;"rect"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);let s=t.cloneNode();return s.style.fill="#000000",s.style.opacity="0.4",e&&s.setAttribute("transform",e),s},dot:t=>{let e;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);let s=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return s.setAttribute("r",parseInt(i)+4),s.setAttribute("fill",a),s.style.opacity="0.6",e&&s.setAttribute("transform",e),s},heat_square:t=>{let e;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);let s=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return s.setAttribute("r",parseInt(i)+4),s.setAttribute("fill",a),s.style.opacity="0.6",e&&s.setAttribute("transform",e),s}},Q={bar:(t,e)=>{let s;"rect"!==t.nodeName&&(s=t.getAttribute("transform"),t=t.childNodes[0]);let i=["x","y","width","height"];Object.values(t.attributes).filter(t=>i.includes(t.name)&&t.specified).map(t=>{e.setAttribute(t.name,t.nodeValue)}),s&&e.setAttribute("transform",s)},dot:(t,e)=>{let s;"circle"!==t.nodeName&&(s=t.getAttribute("transform"),t=t.childNodes[0]);let i=["cx","cy"];Object.values(t.attributes).filter(t=>i.includes(t.name)&&t.specified).map(t=>{e.setAttribute(t.name,t.nodeValue)}),s&&e.setAttribute("transform",s)},heat_square:(t,e)=>{let s;"circle"!==t.nodeName&&(s=t.getAttribute("transform"),t=t.childNodes[0]);let i=["cx","cy"];Object.values(t.attributes).filter(t=>i.includes(t.name)&&t.specified).map(t=>{e.setAttribute(t.name,t.nodeValue)}),s&&e.setAttribute("transform",s)}};function Z(t,e,s,i){let a="string"==typeof e?e:e.join(", ");return[t,{transform:s.join(", ")},i,"easein","translate",{transform:a}]}function tt(t,e,s){return Z(t,[0,s],[0,e],350)}const et={ease:"0.25 0.1 0.25 1",linear:"0 0 1 1",easein:"0.1 0.8 0.2 1",easeout:"0 0 0.58 1",easeinout:"0.42 0 0.58 1"};function st(t,e){t.style.transform=e,t.style.webkitTransform=e,t.style.msTransform=e,t.style.mozTransform=e,t.style.oTransform=e}function it(t,e){let s=[],i=[];e.map(t=>{let e,a,n=t[0],r=n.parentNode;t[0]=n,[e,a]=function(t,e,s,i="linear",a,n={}){let r=t.cloneNode(!0),o=t.cloneNode(!0);for(var l in e){let d;d="transform"===l?document.createElementNS("http://www.w3.org/2000/svg","animateTransform"):document.createElementNS("http://www.w3.org/2000/svg","animate");let c=n[l]||t.getAttribute(l),p=e[l],u={attributeName:l,from:c,to:p,begin:"0s",dur:s/1e3+"s",values:c+";"+p,keySplines:et[i],keyTimes:"0;1",calcMode:"spline",fill:"freeze"};for(var h in a&&(u.type=a),u)d.setAttribute(h,u[h]);r.appendChild(d),a?o.setAttribute(l,`translate(${p})`):o.setAttribute(l,p)}return[r,o]}(...t),s.push(a),i.push([e,r]),r.replaceChild(e,n)});let a=t.cloneNode(!0);return i.map((t,i)=>{t[1].replaceChild(s[i],t[0]),e[i][0]=s[i]}),a}let at;class nt{constructor(t,e){if(this.parent="string"==typeof t?document.querySelector(t):t,!(this.parent instanceof HTMLElement))throw new Error("No `parent` element to render on was provided.");this.rawChartArgs=e,this.title=e.title||"",this.type=e.type||"",this.realData=this.prepareData(e.data),this.data=this.prepareFirstData(this.realData),this.colors=this.validateColors(e.colors,this.type),this.config={showTooltip:1,showLegend:1,isNavigable:e.isNavigable||0,animate:1},this.measures=JSON.parse(JSON.stringify(w));let s=this.measures;this.setMeasures(e),this.title.length||(s.titleHeight=0),this.config.showLegend||(s.legendHeight=0),this.argHeight=e.height||s.baseHeight,this.state={},this.options={},this.initTimeout=700,this.config.isNavigable&&(this.overlays=[]),this.configure(e)}prepareData(t){return t}prepareFirstData(t){return t}validateColors(t,e){const s=[];return(t=(t||[]).concat(T[e])).forEach(t=>{const e=I(t);!function(t){return/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(t)}(e)?console.warn('"'+t+'" is not a valid color.'):s.push(e)}),s}setMeasures(){}configure(){let t=this.argHeight;this.baseHeight=t,this.height=t-k(this.measures),at=this.boundDrawFn.bind(this),window.addEventListener("resize",at),window.addEventListener("orientationchange",this.boundDrawFn.bind(this))}boundDrawFn(){this.draw(!0)}unbindWindowEvents(){window.removeEventListener("resize",at),window.removeEventListener("orientationchange",this.boundDrawFn.bind(this))}setup(){this.makeContainer(),this.updateWidth(),this.makeTooltip(),this.draw(!1,!0)}makeContainer(){this.parent.innerHTML="";let t={inside:this.parent,className:"chart-container"};this.independentWidth&&(t.styles={width:this.independentWidth+"px"}),this.container=x.create("div",t)}makeTooltip(){this.tip=new N({parent:this.container,colors:this.colors}),this.bindTooltip()}bindTooltip(){}draw(t=!1,e=!1){this.updateWidth(),this.calc(t),this.makeChartArea(),this.setupComponents(),this.components.forEach(t=>t.setup(this.drawArea)),this.render(this.components,!1),e&&(this.data=this.realData,setTimeout(()=>{this.update(this.data)},this.initTimeout)),this.renderLegend(),this.setupNavigation(e)}calc(){}updateWidth(){var t,e,s;this.baseWidth=(t=this.parent,e=window.getComputedStyle(t),s=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight),t.clientWidth-s),this.width=this.baseWidth-C(this.measures)}makeChartArea(){this.svg&&this.container.removeChild(this.svg);let t=this.measures;var e,s,i,a;this.svg=(e=this.container,s="frappe-chart chart",i=this.baseWidth,a=this.baseHeight,Y("svg",{className:s,inside:e,width:i,height:a})),this.svgDefs=Y("defs",{inside:this.svg}),this.title.length&&(this.titleEL=q("title",t.margins.left,t.margins.top,this.title,{fontSize:t.titleFontSize,fill:"#666666",dy:t.titleFontSize}));let n=A(t);this.drawArea=B(this.type+"-chart chart-draw-area",`translate(${P(t)}, ${n})`),this.config.showLegend&&(n+=this.height+t.paddings.bottom,this.legendArea=B("chart-legend",`translate(${P(t)}, ${n})`)),this.title.length&&this.svg.appendChild(this.titleEL),this.svg.appendChild(this.drawArea),this.config.showLegend&&this.svg.appendChild(this.legendArea),this.updateTipOffset(P(t),A(t))}updateTipOffset(t,e){this.tip.offset={x:t,y:e}}setupComponents(){this.components=new Map}update(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.calc(),this.render()}render(t=this.components,e=!0){this.config.isNavigable&&this.overlays.map(t=>t.parentNode.removeChild(t));let s=[];t.forEach(t=>{s=s.concat(t.update(e))}),s.length>0?(!function(t,e,s){if(0===s.length)return;let i=it(e,s);e.parentNode==t&&(t.removeChild(e),t.appendChild(i)),setTimeout(()=>{i.parentNode==t&&(t.removeChild(i),t.appendChild(e))},250)}(this.container,this.svg,s),setTimeout(()=>{t.forEach(t=>t.make()),this.updateNav()},400)):(t.forEach(t=>t.make()),this.updateNav())}updateNav(){this.config.isNavigable&&(this.makeOverlay(),this.bindUnits())}renderLegend(){}setupNavigation(t=!1){this.config.isNavigable&&t&&(this.bindOverlay(),this.keyActions={13:this.onEnterKey.bind(this),37:this.onLeftArrow.bind(this),38:this.onUpArrow.bind(this),39:this.onRightArrow.bind(this),40:this.onDownArrow.bind(this)},document.addEventListener("keydown",t=>{var e,s;e=this.container,(s=e.getBoundingClientRect()).top>=0&&s.left>=0&&s.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&s.right<=(window.innerWidth||document.documentElement.clientWidth)&&(t=t||window.event,this.keyActions[t.keyCode]&&this.keyActions[t.keyCode]())}))}makeOverlay(){}updateOverlay(){}bindOverlay(){}bindUnits(){}onLeftArrow(){}onRightArrow(){}onUpArrow(){}onDownArrow(){}onEnterKey(){}addDataPoint(){}removeDataPoint(){}getDataPoint(){}setCurrentDataPoint(){}updateDataset(){}export(){let t=function(t){let e=t.cloneNode(!0);e.classList.add("chart-container"),e.setAttribute("xmlns","http://www.w3.org/2000/svg"),e.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");let s=x.create("style",{innerHTML:".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}"});e.insertBefore(s,e.firstChild);let i=x.create("div");return i.appendChild(e),i.innerHTML}(this.svg);!function(t,e){var s=document.createElement("a");s.style="display: none";var i=new Blob(e,{type:"image/svg+xml; charset=utf-8"}),a=window.URL.createObjectURL(i);s.href=a,s.download=t,document.body.appendChild(s),s.click(),setTimeout((function(){document.body.removeChild(s),window.URL.revokeObjectURL(a)}),300)}(this.title||"Chart",[t])}}class rt extends nt{constructor(t,e){super(t,e)}configure(t){super.configure(t),this.config.maxSlices=t.maxSlices||20,this.config.maxLegendPoints=t.maxLegendPoints||20}calc(){let t=this.state,e=this.config.maxSlices;t.sliceTotals=[];let s=this.data.labels.map((t,e)=>{let s=0;return this.data.datasets.map(t=>{s+=t.values[e]}),[s,t]}).filter(t=>t[0]>=0),i=s;if(s.length>e){s.sort((t,e)=>e[0]-t[0]),i=s.slice(0,e-1);let t=s.slice(e-1),a=0;t.map(t=>{a+=t[0]}),i.push([a,"Rest"]),this.colors[e-1]="grey"}t.labels=[],i.map(e=>{t.sliceTotals.push(e[0]),t.labels.push(e[1])}),t.grandTotal=t.sliceTotals.reduce((t,e)=>t+e,0),this.center={x:this.width/2,y:this.height/2}}renderLegend(){let t=this.state;this.legendArea.textContent="",this.legendTotals=t.sliceTotals.slice(0,this.config.maxLegendPoints);let e=0,s=0;this.legendTotals.map((i,a)=>{let n=Math.floor((this.width-C(this.measures))/110);e>n&&(e=0,s+=20);let r=function(t,e,s,i="none",a){let n={className:"legend-dot",cx:0,cy:0,r:s,fill:i},r=Y("text",{className:"legend-dataset-text",x:0,y:0,dx:"10px",dy:10/3+"px","font-size":"12px","text-anchor":"start",fill:"#555b51",innerHTML:a}),o=Y("g",{transform:`translate(${t}, ${e})`});return o.appendChild(Y("circle",n)),o.appendChild(r),o}(110*e+5,s,5,this.colors[a],`${t.labels[a]}: ${i}`);this.legendArea.appendChild(r),e++})}}const ot=["January","February","March","April","May","June","July","August","September","October","November","December"],lt=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];function ht(t){let e=new Date(t);return e.setMinutes(e.getMinutes()-e.getTimezoneOffset()),e}function dt(t){let e=t.getDate(),s=t.getMonth()+1;return[t.getFullYear(),(s>9?"":"0")+s,(e>9?"":"0")+e].join("-")}function ct(t){return new Date(t.getTime())}function pt(t,e){let s=gt(t);return Math.ceil(function(t,e){return(ht(e)-ht(t))/864e5}(s,e)/7)}function ut(t,e){return t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}function mt(t,e=!1){let s=ot[t];return e?s.slice(0,3):s}function ft(t,e){return new Date(e,t+1,0)}function gt(t){let e=ct(t);const s=e.getDay();return 0!==s&&yt(e,-1*s),e}function yt(t,e){t.setDate(t.getDate()+e)}class bt{constructor({layerClass:t="",layerTransform:e="",constants:s,getData:i,makeElements:a,animateElements:n}){this.layerTransform=e,this.constants=s,this.makeElements=a,this.getData=i,this.animateElements=n,this.store=[],this.labels=[],this.layerClass=t,this.layerClass="function"==typeof this.layerClass?this.layerClass():this.layerClass,this.refresh()}refresh(t){this.data=t||this.getData()}setup(t){this.layer=B(this.layerClass,this.layerTransform,t)}make(){this.render(this.data),this.oldData=this.data}render(t){this.store=this.makeElements(t),this.layer.textContent="",this.store.forEach(t=>{this.layer.appendChild(t)}),this.labels.forEach(t=>{this.layer.appendChild(t)})}update(t=!0){this.refresh();let e=[];return t&&(e=this.animateElements(this.data)||[]),e}}let xt={pieSlices:{layerClass:"pie-slices",makeElements:t=>t.sliceStrings.map((e,s)=>{let i=V(e,"pie-path","none",t.colors[s]);return i.style.transition="transform .3s;",i}),animateElements(t){return this.store.map((e,s)=>{return i=e,a=t.sliceStrings[s],[i,{d:a},350,"easein"];var i,a})}},percentageBars:{layerClass:"percentage-bars",makeElements(t){return t.xPositions.map((e,s)=>function(t,e,s,i,a=2,n="none"){return Y("rect",{className:"percentage-bar",x:t,y:e,width:s,height:i,fill:n,styles:{stroke:j(n,-25),"stroke-dasharray":`0, ${i+s}, ${s}, ${i}`,"stroke-width":a}})}(e,0,t.widths[s],this.constants.barHeight,this.constants.barDepth,t.colors[s]))},animateElements(t){if(t)return[]}},yAxis:{layerClass:"y axis",makeElements(t){return t.positions.map((e,s)=>function(t,e,s,i={}){i.pos||(i.pos="left"),i.offset||(i.offset=0),i.mode||(i.mode="span"),i.stroke||(i.stroke="#dadada"),i.className||(i.className="");let a=-6,n="span"===i.mode?s+6:0;return"tick"===i.mode&&"right"===i.pos&&(a=s+6,n=s),a+=i.offset,n+=i.offset,X(t,e,a,n,{stroke:i.stroke,className:i.className,lineType:i.lineType})}(e,t.labels[s],this.constants.width,{mode:this.constants.mode,pos:this.constants.pos}))},animateElements(t){let e=t.positions,s=t.labels,i=this.oldData.positions,a=this.oldData.labels;return[i,e]=$(i,e),[a,s]=$(a,s),this.render({positions:i,labels:s}),this.store.map((t,s)=>tt(t,e[s],i[s]))}},xAxis:{layerClass:"x axis",makeElements(t){return t.positions.map((e,s)=>J(e,t.calcLabels[s],this.constants.height,{mode:this.constants.mode,pos:this.constants.pos}))},animateElements(t){let e=t.positions,s=t.calcLabels,i=this.oldData.positions,a=this.oldData.calcLabels;return[i,e]=$(i,e),[a,s]=$(a,s),this.render({positions:i,calcLabels:s}),this.store.map((t,s)=>function(t,e,s){return Z(t,[s,0],[e,0],350)}(t,e[s],i[s]))}},yMarkers:{layerClass:"y-markers",makeElements(t){return t.map(t=>function(t,e,s,i={}){i.labelPos||(i.labelPos="right");let a=Y("text",{className:"chart-label",x:"left"===i.labelPos?4:s-S(e,5)-4,y:0,dy:"-5px","font-size":"10px","text-anchor":"start",innerHTML:e+""}),n=X(t,"",0,s,{stroke:i.stroke||"#dadada",className:i.className||"",lineType:i.lineType});return n.appendChild(a),n}(t.position,t.label,this.constants.width,{labelPos:t.options.labelPos,mode:"span",lineType:"dashed"}))},animateElements(t){[this.oldData,t]=$(this.oldData,t);let e=t.map(t=>t.position),s=t.map(t=>t.label),i=t.map(t=>t.options),a=this.oldData.map(t=>t.position);return this.render(a.map((t,e)=>({position:a[e],label:s[e],options:i[e]}))),this.store.map((t,s)=>tt(t,e[s],a[s]))}},yRegions:{layerClass:"y-regions",makeElements(t){return t.map(t=>function(t,e,s,i,a={}){let n=t-e,r=Y("rect",{className:"bar mini",styles:{fill:"rgba(228, 234, 239, 0.49)",stroke:"#dadada","stroke-dasharray":`${s}, ${n}`},x:0,y:0,width:s,height:n});a.labelPos||(a.labelPos="right");let o=Y("text",{className:"chart-label",x:"left"===a.labelPos?4:s-S(i+"",4.5)-4,y:0,dy:"-5px","font-size":"10px","text-anchor":"start",innerHTML:i+""}),l=Y("g",{transform:`translate(0, ${e})`});return l.appendChild(r),l.appendChild(o),l}(t.startPos,t.endPos,this.constants.width,t.label,{labelPos:t.options.labelPos}))},animateElements(t){[this.oldData,t]=$(this.oldData,t);let e=t.map(t=>t.endPos),s=t.map(t=>t.label),i=t.map(t=>t.startPos),a=t.map(t=>t.options),n=this.oldData.map(t=>t.endPos),r=this.oldData.map(t=>t.startPos);this.render(n.map((t,e)=>({startPos:r[e],endPos:n[e],label:s[e],options:a[e]})));let o=[];return this.store.map((t,s)=>{o=o.concat(function(t,e,s,i){let a=e-s,n=t.childNodes[0],r=n.getAttribute("width");return[[n,{height:a,"stroke-dasharray":`${r}, ${a}`},350,"easein"],Z(t,[0,i],[0,s],350)]}(t,i[s],e[s],n[s]))}),o}},heatDomain:{layerClass:function(){return"heat-domain domain-"+this.constants.index},makeElements(t){let{index:e,colWidth:s,rowHeight:i,squareSize:a,xTranslate:n}=this.constants,r=n,o=0;return this.serializedSubDomains=[],t.cols.map((t,n)=>{1===n&&this.labels.push(q("domain-name",r,-12,mt(e,!0).toUpperCase(),{fontSize:9})),t.map((t,e)=>{if(t.fill){let s={"data-date":t.yyyyMmDd,"data-value":t.dataValue,"data-day":e},i=G("day",r,o,a,t.fill,s);this.serializedSubDomains.push(i)}o+=i}),o=0,r+=s}),this.serializedSubDomains},animateElements(t){if(t)return[]}},barGraph:{layerClass:function(){return"dataset-units dataset-bars dataset-"+this.constants.index},makeElements(t){let e=this.constants;return this.unitType="bar",this.units=t.yPositions.map((s,i)=>function(t,e,s,i,a="",n=0,r=0,o={}){let[l,h]=W(e,o.zeroLine);h-=r,0===l&&(l=o.minHeight,h-=o.minHeight);let d=Y("rect",{className:"bar mini",style:"fill: "+i,"data-point-index":n,x:t,y:h,width:s,height:l});if((a+="")||a.length){d.setAttribute("y",0),d.setAttribute("x",0);let e=Y("text",{className:"data-point-value",x:s/2,y:0,dy:"-5px","font-size":"10px","text-anchor":"middle",innerHTML:a}),i=Y("g",{"data-point-index":n,transform:`translate(${t}, ${h})`});return i.appendChild(d),i.appendChild(e),i}return d}(t.xPositions[i],s,t.barWidth,e.color,t.labels[i],i,t.offsets[i],{zeroLine:t.zeroLine,barsWidth:t.barsWidth,minHeight:e.minHeight})),this.units},animateElements(t){let e=t.xPositions,s=t.yPositions,i=t.offsets,a=t.labels,n=this.oldData.xPositions,r=this.oldData.yPositions,o=this.oldData.offsets,l=this.oldData.labels;[n,e]=$(n,e),[r,s]=$(r,s),[o,i]=$(o,i),[l,a]=$(l,a),this.render({xPositions:n,yPositions:r,offsets:o,labels:a,zeroLine:this.oldData.zeroLine,barsWidth:this.oldData.barsWidth,barWidth:this.oldData.barWidth});let h=[];return this.store.map((a,n)=>{h=h.concat(function(t,e,s,i,a=0,n={}){let[r,o]=W(s,n.zeroLine);if(o-=a,"rect"!==t.nodeName){let s=[t.childNodes[0],{width:i,height:r},350,"easein"],a=t.getAttribute("transform").split("(")[1].slice(0,-1);return[s,Z(t,a,[e,o],350)]}return[[t,{width:i,height:r,x:e,y:o},350,"easein"]]}(a,e[n],s[n],t.barWidth,i[n],{zeroLine:t.zeroLine}))}),h}},lineGraph:{layerClass:function(){return"dataset-units dataset-line dataset-"+this.constants.index},makeElements(t){let e=this.constants;return this.unitType="dot",this.paths={},e.hideLine||(this.paths=function(t,e,s,i={},a={}){let n=e.map((e,s)=>t[s]+","+e).join("L"),r=V("M"+n,"line-graph-path",s);if(i.heatline){let t=U(a.svgDefs,s);r.style.stroke=`url(#${t})`}let o={path:r};if(i.regionFill){let e=U(a.svgDefs,s,!0),i=`M${t[0]},${a.zeroLine}L`+n+`L${t.slice(-1)[0]},${a.zeroLine}`;o.region=V(i,"region-fill","none",`url(#${e})`)}return o}(t.xPositions,t.yPositions,e.color,{heatline:e.heatline,regionFill:e.regionFill},{svgDefs:e.svgDefs,zeroLine:t.zeroLine})),this.units=[],e.hideDots||(this.units=t.yPositions.map((s,i)=>function(t,e,s,i,a="",n=0){let r=Y("circle",{style:"fill: "+i,"data-point-index":n,cx:t,cy:e,r:s});if((a+="")||a.length){r.setAttribute("cy",0),r.setAttribute("cx",0);let i=Y("text",{className:"data-point-value",x:0,y:0,dy:-5-s+"px","font-size":"10px","text-anchor":"middle",innerHTML:a}),o=Y("g",{"data-point-index":n,transform:`translate(${t}, ${e})`});return o.appendChild(r),o.appendChild(i),o}return r}(t.xPositions[i],s,t.radius,e.color,e.valuesOverPoints?t.values[i]:"",i))),Object.values(this.paths).concat(this.units)},animateElements(t){let e=t.xPositions,s=t.yPositions,i=t.values,a=this.oldData.xPositions,n=this.oldData.yPositions,r=this.oldData.values;[a,e]=$(a,e),[n,s]=$(n,s),[r,i]=$(r,i),this.render({xPositions:a,yPositions:n,values:i,zeroLine:this.oldData.zeroLine,radius:this.oldData.radius});let o=[];return Object.keys(this.paths).length&&(o=o.concat(function(t,e,s,i){let a=[],n=s.map((t,s)=>e[s]+","+t).join("L");const r=[t.path,{d:"M"+n},350,"easein"];if(a.push(r),t.region){let s=`${e[0]},${i}L`,r=`L${e.slice(-1)[0]}, ${i}`;const o=[t.region,{d:"M"+s+n+r},350,"easein"];a.push(o)}return a}(this.paths,e,s,t.zeroLine))),this.units.length&&this.units.map((t,i)=>{o=o.concat(function(t,e,s){if("circle"!==t.nodeName){let i=t.getAttribute("transform").split("(")[1].slice(0,-1);return[Z(t,i,[e,s],350)]}return[[t,{cx:e,cy:s},350,"easein"]]}(t,e[i],s[i]))}),o}}};function vt(t,e,s){let i=Object.keys(xt).filter(e=>t.includes(e)),a=xt[i[0]];return Object.assign(a,{constants:e,getData:s}),new bt(a)}function wt(t){if(0===t)return[0,0];if(isNaN(t))return{mantissa:-6755399441055744,exponent:972};var e=t>0?1:-1;if(!isFinite(t))return{mantissa:4503599627370496*e,exponent:972};t=Math.abs(t);var s=Math.floor(Math.log10(t));return[e*(t/Math.pow(10,s)),s]}function At(t,e=0){let[s,i]=wt(t),a=e?e/Math.pow(10,i):0;s=s.toFixed(6);let n=function(t,e=0){let s=Math.ceil(t),i=Math.floor(e),a=s-i,n=a,r=1;a>5&&(a%2!=0&&(s++,a=s-i),n=a/2,r=2),a<=2&&(n=4,r=a/n),0===a&&(n=5,r=1);let o=[];for(var l=0;l<=n;l++)o.push(i+r*l);return o}(s,a);return n=n.map(t=>t*Math.pow(10,i)),n}function Pt(t){return t[1]-t[0]}function kt(t,e){return O(e.zeroLine-t*e.scaleMultiplier)}class Ct extends nt{constructor(t,e){super(t,e),this.barOptions=e.barOptions||{},this.lineOptions=e.lineOptions||{},this.type=e.type||"line",this.init=1,this.setup()}setMeasures(){this.data.datasets.length<=1&&(this.config.showLegend=0,this.measures.paddings.bottom=30)}configure(t){super.configure(t),t.axisOptions=t.axisOptions||{},t.tooltipOptions=t.tooltipOptions||{},this.config.xAxisMode=t.axisOptions.xAxisMode||"span",this.config.yAxisMode=t.axisOptions.yAxisMode||"span",this.config.xIsSeries=t.axisOptions.xIsSeries||0,this.config.formatTooltipX=t.tooltipOptions.formatTooltipX,this.config.formatTooltipY=t.tooltipOptions.formatTooltipY,this.config.valuesOverPoints=t.valuesOverPoints}prepareData(t=this.data){return function(t,e){t.labels=t.labels||[];let s=t.labels.length,i=t.datasets,a=new Array(s).fill(0);return i||(i=[{values:a}]),i.map(t=>{if(t.values){let e=t.values;e=e.map(t=>isNaN(t)?0:t),e=e.length>s?e.slice(0,s):E(e,s-e.length,0)}else t.values=a;t.chartType||(D.includes(e),t.chartType=e)}),t.yRegions&&t.yRegions.map(t=>{t.end({name:"",values:s.slice(0,-1),chartType:t.chartType}))};return t.yMarkers&&(i.yMarkers=[{value:0,label:""}]),t.yRegions&&(i.yRegions=[{start:0,end:0,label:""}]),i}(t)}calc(t=!1){this.calcXPositions(),t||this.calcYAxisParameters(this.getAllYValues(),"line"===this.type),this.makeDataByIndex()}calcXPositions(){let t=this.state,e=this.data.labels;t.datasetLength=e.length,t.unitWidth=this.width/t.datasetLength,t.xOffset=t.unitWidth/2,t.xAxis={labels:e,positions:e.map((e,s)=>O(t.xOffset+s*t.unitWidth))}}calcYAxisParameters(t,e="false"){const s=function(t,e=!1){let s=Math.max(...t),i=Math.min(...t),a=0,n=[];function r(t,e){let s=At(t),i=s[1]-s[0],a=0;for(var n=1;a=0&&i>=0)a=wt(s)[1],n=e?At(s,i):At(s);else if(s>0&&i<0){let t=Math.abs(i);if(s>=t)a=wt(s)[1],n=r(s,t);else{a=wt(t)[1],n=r(t,s).map(t=>-1*t)}}else if(s<=0&&i<=0){let t=Math.abs(i),r=Math.abs(s);a=wt(t)[1],n=e?At(t,r):At(t),n=n.reverse().map(t=>-1*t)}return n}(t,e),i=this.height/((a=s)[a.length-1]-a[0]);var a;const n=Pt(s)*i,r=this.height-function(t){let e,s=Pt(t);if(t.indexOf(0)>=0)e=t.indexOf(0);else if(t[0]>0){e=-1*t[0]/s}else{e=-1*t[t.length-1]/s+(t.length-1)}return e}(s)*n;this.state.yAxis={labels:s,positions:s.map(t=>r-t*i),scaleMultiplier:i,zeroLine:r},this.calcDatasetPoints(),this.calcYExtremes(),this.calcYRegions()}calcDatasetPoints(){let t=this.state,e=e=>e.map(e=>kt(e,t.yAxis));t.datasets=this.data.datasets.map((t,s)=>{let i=t.values,a=t.cumulativeYs||[];return{name:t.name,index:s,chartType:t.chartType,values:i,yPositions:e(i),cumulativeYs:a,cumulativeYPos:e(a)}})}calcYExtremes(){let t=this.state;this.barOptions.stacked?t.yExtremes=t.datasets[t.datasets.length-1].cumulativeYPos:(t.yExtremes=new Array(t.datasetLength).fill(9999),t.datasets.map(e=>{e.yPositions.map((e,s)=>{e(e.position=kt(e.value,t.yAxis),e.options||(e.options={}),e))),this.data.yRegions&&(this.state.yRegions=this.data.yRegions.map(e=>(e.startPos=kt(e.start,t.yAxis),e.endPos=kt(e.end,t.yAxis),e.options||(e.options={}),e)))}getAllYValues(){let t="values";if(this.barOptions.stacked){t="cumulativeYs";let e=new Array(this.state.datasetLength).fill(0);this.data.datasets.map((s,i)=>{let a=this.data.datasets[i].values;s[t]=e=e.map((t,e)=>t+a[e])})}let e=this.data.datasets.map(e=>e[t]);return this.data.yMarkers&&e.push(this.data.yMarkers.map(t=>t.value)),this.data.yRegions&&this.data.yRegions.map(t=>{e.push([t.end,t.start])}),[].concat(...e)}setupComponents(){let t=[["yAxis",{mode:this.config.yAxisMode,width:this.width},function(){return this.state.yAxis}.bind(this)],["xAxis",{mode:this.config.xAxisMode,height:this.height},function(){let t=this.state;return t.xAxis.calcLabels=function(t,e=[],s=!0){let i=t/e.length;i<=0&&(i=1);let a=i/7;return e.map((t,e)=>{if((t+="").length>a)if(s){e%Math.ceil(t.length/a)!=0&&(t="")}else t=a-3>0?t.slice(0,a-3)+" ...":t.slice(0,a)+"..";return t})}(this.width,t.xAxis.labels,this.config.xIsSeries),t.xAxis}.bind(this)],["yRegions",{width:this.width,pos:"right"},function(){return this.state.yRegions}.bind(this)]],e=this.state.datasets.filter(t=>"bar"===t.chartType),s=this.state.datasets.filter(t=>"line"===t.chartType),i=e.map(t=>{let s=t.index;return["barGraph-"+t.index,{index:s,color:this.colors[s],stacked:this.barOptions.stacked,valuesOverPoints:this.config.valuesOverPoints,minHeight:.01*this.height},function(){let t=this.state,i=t.datasets[s],a=this.barOptions.stacked,n=this.barOptions.spaceRatio||.5,r=t.unitWidth*(1-n),o=r/(a?1:e.length),l=t.xAxis.positions.map(t=>t-r/2);a||(l=l.map(t=>t+o*s));let h=new Array(t.datasetLength).fill("");this.config.valuesOverPoints&&(h=a&&i.index===t.datasets.length-1?i.cumulativeYs:i.values);let d=new Array(t.datasetLength).fill(0);return a&&(d=i.yPositions.map((t,e)=>t-i.cumulativeYPos[e])),{xPositions:l,yPositions:i.yPositions,offsets:d,labels:h,zeroLine:t.yAxis.zeroLine,barsWidth:r,barWidth:o}}.bind(this)]}),a=s.map(t=>{let e=t.index;return["lineGraph-"+t.index,{index:e,color:this.colors[e],svgDefs:this.svgDefs,heatline:this.lineOptions.heatline,regionFill:this.lineOptions.regionFill,hideDots:this.lineOptions.hideDots,hideLine:this.lineOptions.hideLine,valuesOverPoints:this.config.valuesOverPoints},function(){let t=this.state,s=t.datasets[e],i=t.yAxis.positions[0]!r.includes(t[0])||this.state[t[0]]).map(t=>{let e=vt(...t);return(t[0].includes("lineGraph")||t[0].includes("barGraph"))&&this.dataUnitComponents.push(e),[t[0],e]}))}makeDataByIndex(){this.dataByIndex={};let t=this.state,e=this.config.formatTooltipX,s=this.config.formatTooltipY;t.xAxis.labels.map((i,a)=>{let n=this.state.datasets.map((t,e)=>{let i=t.values[a];return{title:t.name,value:i,yPos:t.yPositions[a],color:this.colors[e],formatted:s?s(i):i}});this.dataByIndex[a]={label:i,formattedLabel:e?e(i):i,xPos:t.xAxis.positions[a],values:n,yExtreme:t.yExtremes[a]}})}bindTooltip(){this.container.addEventListener("mousemove",t=>{let e=this.measures,s=v(this.container),i=t.pageX-s.left-P(e),a=t.pageY-s.top;aA(e)?this.mapTooltipXPosition(i):this.tip.hideTip()})}mapTooltipXPosition(t){let e=this.state;if(!e.yExtremes)return;let s=function(t,e,s=!1){let i=e.reduce((function(e,s){return Math.abs(s-t)1&&(this.legendArea.textContent="",t.datasets.map((t,e)=>{let s=function(t,e,s,i="none",a){let n={className:"legend-bar",x:0,y:0,width:s,height:"2px",fill:i},r=Y("text",{className:"legend-dataset-text",x:0,y:0,dy:"20px","font-size":"12px","text-anchor":"start",fill:"#555b51",innerHTML:a}),o=Y("g",{transform:`translate(${t}, ${e})`});return o.appendChild(Y("rect",n)),o.appendChild(r),o}(100*e,"0",100,this.colors[e],t.name);this.legendArea.appendChild(s)}))}makeOverlay(){this.init?this.init=0:(this.overlayGuides&&this.overlayGuides.forEach(t=>{let e=t.overlay;e.parentNode.removeChild(e)}),this.overlayGuides=this.dataUnitComponents.map(t=>({type:t.unitType,overlay:void 0,units:t.units})),void 0===this.state.currentIndex&&(this.state.currentIndex=this.state.datasetLength-1),this.overlayGuides.map(t=>{let e=t.units[this.state.currentIndex];t.overlay=K[t.type](e),this.drawArea.appendChild(t.overlay)}))}updateOverlayGuides(){this.overlayGuides&&this.overlayGuides.forEach(t=>{let e=t.overlay;e.parentNode.removeChild(e)})}bindOverlay(){this.parent.addEventListener("data-select",()=>{this.updateOverlay()})}bindUnits(){this.dataUnitComponents.map(t=>{t.units.map(t=>{t.addEventListener("click",()=>{let e=t.getAttribute("data-point-index");this.setCurrentDataPoint(e)})})}),this.tip.container.addEventListener("click",()=>{let t=this.tip.container.getAttribute("data-point-index");this.setCurrentDataPoint(t)})}updateOverlay(){this.overlayGuides.map(t=>{let e=t.units[this.state.currentIndex];Q[t.type](e,t.overlay)})}onLeftArrow(){this.setCurrentDataPoint(this.state.currentIndex-1)}onRightArrow(){this.setCurrentDataPoint(this.state.currentIndex+1)}getDataPoint(t=this.state.currentIndex){let e=this.state;return{index:t,label:e.xAxis.labels[t],values:e.datasets.map(e=>e.values[t])}}setCurrentDataPoint(t){let e=this.state;(t=parseInt(t))<0&&(t=0),t>=e.xAxis.labels.length&&(t=e.xAxis.labels.length-1),t!==e.currentIndex&&(e.currentIndex=t,function(t,e,s){var i=document.createEvent("HTMLEvents");for(var a in i.initEvent(e,!0,!0),s)i[a]=s[a];t.dispatchEvent(i)}(this.parent,"data-select",this.getDataPoint()))}addDataPoint(t,e,s=this.state.datasetLength){super.addDataPoint(t,e,s),this.data.labels.splice(s,0,t),this.data.datasets.map((t,i)=>{t.values.splice(s,0,e[i])}),this.update(this.data)}removeDataPoint(t=this.state.datasetLength-1){this.data.labels.length<=1||(super.removeDataPoint(t),this.data.labels.splice(t,1),this.data.datasets.map(e=>{e.values.splice(t,1)}),this.update(this.data))}updateDataset(t,e=0){this.data.datasets[e].values=t,this.update(this.data)}updateDatasets(t){this.data.datasets.map((e,s)=>{t[s]&&(e.values=t[s])}),this.update(this.data)}}const Dt={bar:Ct,line:Ct,percentage:class extends rt{constructor(t,e){super(t,e),this.type="percentage",this.setup()}setMeasures(t){let e=this.measures;this.barOptions=t.barOptions||{};let s=this.barOptions;s.height=s.height||20,s.depth=s.depth||2,e.paddings.right=30,e.legendHeight=80,e.baseHeight=8*(s.height+.5*s.depth)}setupComponents(){let t=this.state,e=[["percentageBars",{barHeight:this.barOptions.height,barDepth:this.barOptions.depth},function(){return{xPositions:t.xPositions,widths:t.widths,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(t=>{let e=vt(...t);return[t[0],e]}))}calc(){super.calc();let t=this.state;t.xPositions=[],t.widths=[];let e=0;t.sliceTotals.map(s=>{let i=this.width*s/t.grandTotal;t.widths.push(i),t.xPositions.push(e),e+=i})}makeDataByIndex(){}bindTooltip(){let t=this.state;this.container.addEventListener("mousemove",e=>{let s=this.components.get("percentageBars").store,i=e.target;if(s.includes(i)){let e=s.indexOf(i),a=v(this.container),n=v(i),r=n.left-a.left+parseInt(i.getAttribute("width"))/2,o=n.top-a.top,l=(this.formattedLabels&&this.formattedLabels.length>0?this.formattedLabels[e]:this.state.labels[e])+": ",h=t.sliceTotals[e]/t.grandTotal;this.tip.setValues(r,o,{name:l,value:(100*h).toFixed(1)+"%"}),this.tip.showTip()}})}},heatmap:class extends nt{constructor(t,e){super(t,e),this.type="heatmap",this.countLabel=e.countLabel||"";let s=["Sunday","Monday"],i=s.includes(e.startSubDomain)?e.startSubDomain:"Sunday";this.startSubDomainIndex=s.indexOf(i),this.setup()}setMeasures(t){let e=this.measures;this.discreteDomains=0===t.discreteDomains?0:1,e.paddings.top=36,e.paddings.bottom=0,e.legendHeight=24,e.baseHeight=84+k(e);let s=this.data,i=this.discreteDomains?12:0;this.independentWidth=12*(pt(s.start,s.end)+i)+C(e)}updateWidth(){let t=this.discreteDomains?12:0,e=this.state.noOfWeeks?this.state.noOfWeeks:52;this.baseWidth=12*(e+t)+C(this.measures)}prepareData(t=this.data){if(t.start&&t.end&&t.start>t.end)throw new Error("Start date cannot be greater than end date.");if(t.start||(t.start=new Date,t.start.setFullYear(t.start.getFullYear()-1)),t.end||(t.end=new Date),t.dataPoints=t.dataPoints||{},parseInt(Object.keys(t.dataPoints)[0])>1e5){let e={};Object.keys(t.dataPoints).forEach(s=>{let i=new Date(1e3*s);e[dt(i)]=t.dataPoints[s]}),t.dataPoints=e}return t}calc(){let t=this.state;t.start=ct(this.data.start),t.end=ct(this.data.end),t.firstWeekStart=ct(t.start),t.noOfWeeks=pt(t.start,t.end),t.distribution=function(t,e){let s=Math.max(...t),i=1/(e-1),a=[];for(var n=0;n["heatDomain",{index:s.index,colWidth:12,rowHeight:12,squareSize:10,xTranslate:12*t.domainConfigs.filter((t,e)=>et.cols.length-e).reduce((t,e)=>t+e,0)},function(){return t.domainConfigs[i]}.bind(this)]);this.components=new Map(s.map((t,e)=>{let s=vt(...t);return[t[0]+"-"+e,s]}));let i=0;lt.forEach((t,e)=>{if([1,3,5].includes(e)){let e=q("subdomain-name",-6,i,t,{fontSize:10,dy:8,textAnchor:"end"});this.drawArea.appendChild(e)}i+=12})}update(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.draw(),this.bindTooltip()}bindTooltip(){this.container.addEventListener("mousemove",t=>{this.components.forEach(e=>{let s=e.store,i=t.target;if(s.includes(i)){let e=i.getAttribute("data-value"),s=i.getAttribute("data-date").split("-"),a=mt(parseInt(s[1])-1,!0),n=this.container.getBoundingClientRect(),r=i.getBoundingClientRect(),o=parseInt(t.target.getAttribute("width")),l=r.left-n.left+o/2,h=r.top-n.top,d=e+" "+this.countLabel,c=" on "+a+" "+s[0]+", "+s[2];this.tip.setValues(l,h,{name:c,value:d,valueFirst:1},[]),this.tip.showTip()}})})}renderLegend(){this.legendArea.textContent="";let t=0,e=q("subdomain-name",t,12,"Less",{fontSize:11,dy:9});t=30,this.legendArea.appendChild(e),this.colors.slice(0,5).map((e,s)=>{const i=G("heatmap-legend-unit",t+15*s,12,10,e);this.legendArea.appendChild(i)});let s=q("subdomain-name",t+75+3,12,"More",{fontSize:11,dy:9});this.legendArea.appendChild(s)}getDomains(){let t=this.state;const[e,s]=[t.start.getMonth(),t.start.getFullYear()],[i,a]=[t.end.getMonth(),t.end.getFullYear()],n=i-e+1+12*(a-s);let r=[],o=ct(t.start);for(var l=0;l=i.start&&a<=i.end;s||a.getMonth()!==e||!r?t.yyyyMmDd=dt(a):t=this.getSubDomainConfig(a),n.push(t)}return n}getSubDomainConfig(t){let e=dt(t),s=this.data.dataPoints[e];var i,a;return{yyyyMmDd:e,dataValue:s||0,fill:this.colors[(i=s,a=this.state.distribution,a.filter(t=>tthis.width?this.center.x:this.center.y;const{radius:e,clockWise:s}=this,i=t.slicesProperties||[];t.sliceStrings=[],t.slicesProperties=[];let a=180-this.config.startAngle;t.sliceTotals.map((n,r)=>{const o=a,l=n/t.grandTotal*360,h=s?-l:l,d=a+=h,c=z(o,e),p=z(d,e),u=this.init&&i[r];let m,f;this.init?(m=u?u.startPosition:c,f=u?u.endPosition:c):(m=c,f=p);const g=function(t,e,s,i,a=1){let[n,r]=[s.x+t.x,s.y+t.y],[o,l]=[s.x+e.x,s.y+e.y];return`M${s.x} ${s.y}\n\t\tL${n} ${r}\n\t\tA ${i} ${i} 0 0 ${a?1:0}\n\t\t${o} ${l} z`}(m,f,this.center,this.radius,this.clockWise);t.sliceStrings.push(g),t.slicesProperties.push({startPosition:c,endPosition:p,value:n,total:t.grandTotal,startAngle:o,endAngle:d,angle:h})}),this.init=0}setupComponents(){let t=this.state,e=[["pieSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(t=>{let e=vt(...t);return[t[0],e]}))}calTranslateByAngle(t){const{radius:e,hoverRadio:s}=this,i=z(t.startAngle+t.angle/2,e);return`translate3d(${i.x*s}px,${i.y*s}px,0)`}hoverSlice(t,e,s,i){if(!t)return;const a=this.colors[e];if(s){st(t,this.calTranslateByAngle(this.state.slicesProperties[e])),t.style.fill=j(a,50);let s=v(this.svg),n=i.pageX-s.left+10,r=i.pageY-s.top-10,o=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[e]:this.state.labels[e])+": ",l=(100*this.state.sliceTotals[e]/this.state.grandTotal).toFixed(1);this.tip.setValues(n,r,{name:o,value:l+"%"}),this.tip.showTip()}else st(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.fill=a}bindTooltip(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}mouseMove(t){const e=t.target;let s=this.components.get("pieSlices").store,i=this.curActiveSliceIndex,a=this.curActiveSlice;if(s.includes(e)){let n=s.indexOf(e);this.hoverSlice(a,i,!1),this.curActiveSlice=e,this.curActiveSliceIndex=n,this.hoverSlice(e,n,!0,t)}else this.mouseLeave()}mouseLeave(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}};class Lt{constructor(t,e){return function(t="line",e,s){return"axis-mixed"===t?(s.type="line",new Ct(e,s)):Dt[t]?new Dt[t](e,s):void console.error("Undefined chart type: "+t)}(e.type,t,e)}}var Tt=function(t){var e,s;function i(){return t.apply(this,arguments)||this}s=t,(e=i).prototype=Object.create(s.prototype),e.prototype.constructor=e,e.__proto__=s;var a=i.prototype;return a.oninit=function(e){t.prototype.oninit.call(this,e);var s=new Date;s.setTime(s.getTime()+1e3*app.data.statistics.timezoneOffset),s.setUTCHours(0,0,0,0),s.setTime(s.getTime()-1e3*app.data.statistics.timezoneOffset),s/=1e3,this.entities=["users","discussions","posts"],this.periods={today:{start:s,end:s+86400,step:3600},last_7_days:{start:s-604800,end:s,step:86400},last_28_days:{start:s-2419200,end:s,step:86400},last_12_months:{start:s-31449600,end:s,step:604800}},this.selectedEntity="users",this.selectedPeriod="last_7_days"},a.className=function(){return"StatisticsWidget"},a.content=function(){var t=this,e=this.periods[this.selectedPeriod];return m("div",{className:"StatisticsWidget-table"},m("div",{className:"StatisticsWidget-labels"},m("div",{className:"StatisticsWidget-label"},app.translator.trans("flarum-statistics.admin.statistics.total_label")),m("div",{className:"StatisticsWidget-label"},m(c.a,{buttonClassName:"Button Button--text",caretIcon:"fas fa-caret-down"},Object.keys(this.periods).map((function(e){return m(u.a,{active:e===t.selectedPeriod,onclick:t.changePeriod.bind(t,e),icon:e!==t.selectedPeriod||"fas fa-check"},app.translator.trans("flarum-statistics.admin.statistics."+e+"_label"))}))))),this.entities.map((function(s){var i=t.getTotalCount(s),a=t.getPeriodCount(s,e),n=t.getPeriodCount(s,t.getLastPeriod(e)),r=n>0&&(a-n)/n*100;return m("a",{className:"StatisticsWidget-entity"+(t.selectedEntity===s?" active":""),onclick:t.changeEntity.bind(t,s)},m("h3",{className:"StatisticsWidget-heading"},app.translator.trans("flarum-statistics.admin.statistics."+s+"_heading")),m("div",{className:"StatisticsWidget-total",title:i},b()(i)),m("div",{className:"StatisticsWidget-period",title:a},b()(a)," ",r?m("span",{className:"StatisticsWidget-change StatisticsWidget-change--"+(r>0?"up":"down")},g()("fas fa-arrow-"+(r>0?"up":"down")),Math.abs(r.toFixed(1)),"%"):""))})),m("div",{className:"StatisticsWidget-chart",oncreate:this.drawChart.bind(this),onupdate:this.drawChart.bind(this)}))},a.drawChart=function(t){if(!this.chart||this.entity!==this.selectedEntity||this.period!==this.selectedPeriod){for(var e=app.data.statistics.timezoneOffset,s=this.periods[this.selectedPeriod],i=s.end-s.start,a=[],n=[],r=[],o=s.start;o86400&&(l+=" - "+dayjs.unix(o+e+s.step-1).format("D MMM"))),a.push(l),n.push(this.getPeriodCount(this.selectedEntity,{start:o,end:o+s.step})),r.push(this.getPeriodCount(this.selectedEntity,{start:o-i,end:o-i+s.step}))}var h={labels:a,datasets:[{values:r},{values:n}]};this.chart?this.chart.update(h):this.chart=new Lt(t.dom,{data:h,type:"line",height:280,axisOptions:{xAxisMode:"tick",yAxisMode:"span",xIsSeries:!0},lineOptions:{hideDots:1},colors:["black",app.forum.attribute("themePrimaryColor")]}),this.entity=this.selectedEntity,this.period=this.selectedPeriod}},a.changeEntity=function(t){this.selectedEntity=t},a.changePeriod=function(t){this.selectedPeriod=t},a.getTotalCount=function(t){return app.data.statistics[t].total},a.getPeriodCount=function(t,e){var s=app.data.statistics[t].timed,i=0;for(var a in s)a>=e.start&&a {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (i in element ) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\nfunction getOffset(element) {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n}\n\nfunction isElementInViewport(el) {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n}\n\nfunction getElementContentWidth(element) {\n\tvar styles = window.getComputedStyle(element);\n\tvar padding = parseFloat(styles.paddingLeft) +\n\t\tparseFloat(styles.paddingRight);\n\n\treturn element.clientWidth - padding;\n}\n\n\n\n\n\nfunction fire(target, type, properties) {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n}\n\n// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/\n\nconst BASE_MEASURES = {\n\tmargins: {\n\t\ttop: 10,\n\t\tbottom: 10,\n\t\tleft: 20,\n\t\tright: 20\n\t},\n\tpaddings: {\n\t\ttop: 20,\n\t\tbottom: 40,\n\t\tleft: 30,\n\t\tright: 10\n\t},\n\n\tbaseHeight: 240,\n\ttitleHeight: 20,\n\tlegendHeight: 30,\n\n\ttitleFontSize: 12,\n};\n\nfunction getTopOffset(m) {\n\treturn m.titleHeight + m.margins.top + m.paddings.top;\n}\n\nfunction getLeftOffset(m) {\n\treturn m.margins.left + m.paddings.left;\n}\n\nfunction getExtraHeight(m) {\n\tlet totalExtraHeight = m.margins.top + m.margins.bottom\n\t\t+ m.paddings.top + m.paddings.bottom\n\t\t+ m.titleHeight + m.legendHeight;\n\treturn totalExtraHeight;\n}\n\nfunction getExtraWidth(m) {\n\tlet totalExtraWidth = m.margins.left + m.margins.right\n\t\t+ m.paddings.left + m.paddings.right;\n\n\treturn totalExtraWidth;\n}\n\nconst INIT_CHART_UPDATE_TIMEOUT = 700;\nconst CHART_POST_ANIMATE_TIMEOUT = 400;\n\nconst DEFAULT_AXIS_CHART_TYPE = 'line';\nconst AXIS_DATASET_CHART_TYPES = ['line', 'bar'];\n\nconst AXIS_LEGEND_BAR_SIZE = 100;\n\nconst BAR_CHART_SPACE_RATIO = 0.5;\nconst MIN_BAR_PERCENT_HEIGHT = 0.01;\n\nconst LINE_CHART_DOT_SIZE = 4;\nconst DOT_OVERLAY_SIZE_INCR = 4;\n\nconst PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;\nconst PERCENTAGE_BAR_DEFAULT_DEPTH = 2;\n\n// Fixed 5-color theme,\n// More colors are difficult to parse visually\nconst HEATMAP_DISTRIBUTION_SIZE = 5;\n\nconst HEATMAP_SQUARE_SIZE = 10;\nconst HEATMAP_GUTTER_SIZE = 2;\n\nconst DEFAULT_CHAR_WIDTH = 7;\n\nconst TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5;\n\nconst DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];\nconst HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\n\n\n\nconst DEFAULT_COLORS = {\n\tbar: DEFAULT_CHART_COLORS,\n\tline: DEFAULT_CHART_COLORS,\n\tpie: DEFAULT_CHART_COLORS,\n\tpercentage: DEFAULT_CHART_COLORS,\n\theatmap: HEATMAP_COLORS_GREEN\n};\n\n// Universal constants\nconst ANGLE_RATIO = Math.PI / 180;\nconst FULL_ANGLE = 360;\n\nclass SvgTip {\n\tconstructor({\n\t\tparent = null,\n\t\tcolors = []\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.colors = colors;\n\t\tthis.titleName = '';\n\t\tthis.titleValue = '';\n\t\tthis.listValues = [];\n\t\tthis.titleValueFirst = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.makeTooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calcPosition();\n\t}\n\n\tmakeTooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t
      \n\t\t\t\t
      `\n\t\t});\n\t\tthis.hideTip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.dataPointList = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hideTip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.index) {\n\t\t\tthis.container.setAttribute('data-point-index', this.index);\n\t\t}\n\t\tif(this.titleValueFirst) {\n\t\t\ttitle = `${this.titleValue}${this.titleName}`;\n\t\t} else {\n\t\t\ttitle = `${this.titleName}${this.titleValue}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.dataPointList.innerHTML = '';\n\n\t\tthis.listValues.map((set, i) => {\n\t\t\tconst color = this.colors[i] || 'black';\n\t\t\tlet value = set.formatted === 0 || set.formatted ? set.formatted : set.value;\n\n\t\t\tlet li = $.create('li', {\n\t\t\t\tstyles: {\n\t\t\t\t\t'border-top': `3px solid ${color}`\n\t\t\t\t},\n\t\t\t\tinnerHTML: `${ value === 0 || value ? value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.dataPointList.appendChild(li);\n\t\t});\n\t}\n\n\tcalcPosition() {\n\t\tlet width = this.container.offsetWidth;\n\n\t\tthis.top = this.y - this.container.offsetHeight\n\t\t\t- TOOLTIP_POINTER_TRIANGLE_HEIGHT;\n\t\tthis.left = this.x - width/2;\n\t\tlet maxLeft = this.parent.offsetWidth - width;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > maxLeft) {\n\t\t\tlet delta = this.left - maxLeft;\n\t\t\tlet pointerOffset = `calc(50% + ${delta}px)`;\n\t\t\tpointer.style.left = pointerOffset;\n\n\t\t\tthis.left = maxLeft;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tsetValues(x, y, title = {}, listValues = [], index = -1) {\n\t\tthis.titleName = title.name;\n\t\tthis.titleValue = title.value;\n\t\tthis.listValues = listValues;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.titleValueFirst = title.valueFirst || 0;\n\t\tthis.index = index;\n\t\tthis.refresh();\n\t}\n\n\thideTip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshowTip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n\nfunction floatTwo(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\n/**\n * Returns whether or not two given arrays are equal.\n * @param {Array} arr1 First array\n * @param {Array} arr2 Second array\n */\n\n\n/**\n * Shuffles array in place. ES6 version\n * @param {Array} array An array containing the items.\n */\n\n\n/**\n * Fill an array with extra points\n * @param {Array} array Array\n * @param {Number} count number of filler elements\n * @param {Object} element element to fill with\n * @param {Boolean} start fill at start?\n */\nfunction fillArray(array, count, element, start=false) {\n\tif(!element) {\n\t\telement = start ? array[0] : array[array.length - 1];\n\t}\n\tlet fillerArray = new Array(Math.abs(count)).fill(element);\n\tarray = start ? fillerArray.concat(array) : array.concat(fillerArray);\n\treturn array;\n}\n\n/**\n * Returns pixel width of string.\n * @param {String} string\n * @param {Number} charWidth Width of single char in pixels\n */\nfunction getStringWidth(string, charWidth) {\n\treturn (string+\"\").length * charWidth;\n}\n\n\n\n// https://stackoverflow.com/a/29325222\n\n\nfunction getPositionByAngle(angle, radius) {\n\treturn {\n\t\tx: Math.sin(angle * ANGLE_RATIO) * radius,\n\t\ty: Math.cos(angle * ANGLE_RATIO) * radius,\n\t};\n}\n\nfunction getBarHeightAndYAttr(yTop, zeroLine) {\n\tlet height, y;\n\tif (yTop <= zeroLine) {\n\t\theight = zeroLine - yTop;\n\t\ty = yTop;\n\t} else {\n\t\theight = yTop - zeroLine;\n\t\ty = zeroLine;\n\t}\n\n\treturn [height, y];\n}\n\nfunction equilizeNoOfElements(array1, array2,\n\textraCount = array2.length - array1.length) {\n\n\t// Doesn't work if either has zero elements.\n\tif(extraCount > 0) {\n\t\tarray1 = fillArray(array1, extraCount);\n\t} else {\n\t\tarray2 = fillArray(array2, extraCount);\n\t}\n\treturn [array1, array2];\n}\n\nconst PRESET_COLOR_MAP = {\n\t'light-blue': '#7cd6fd',\n\t'blue': '#5e64ff',\n\t'violet': '#743ee2',\n\t'red': '#ff5858',\n\t'orange': '#ffa00a',\n\t'yellow': '#feef72',\n\t'green': '#28a745',\n\t'light-green': '#98d85b',\n\t'purple': '#b554ff',\n\t'magenta': '#ffa3ef',\n\t'black': '#36114C',\n\t'grey': '#bdd3e6',\n\t'light-grey': '#f0f4f7',\n\t'dark-grey': '#b8c2cc'\n};\n\nfunction limitColor(r){\n\tif (r > 255) return 255;\n\telse if (r < 0) return 0;\n\treturn r;\n}\n\nfunction lightenDarkenColor(color, amt) {\n\tlet col = getColor(color);\n\tlet usePound = false;\n\tif (col[0] == \"#\") {\n\t\tcol = col.slice(1);\n\t\tusePound = true;\n\t}\n\tlet num = parseInt(col,16);\n\tlet r = limitColor((num >> 16) + amt);\n\tlet b = limitColor(((num >> 8) & 0x00FF) + amt);\n\tlet g = limitColor((num & 0x0000FF) + amt);\n\treturn (usePound?\"#\":\"\") + (g | (b << 8) | (r << 16)).toString(16);\n}\n\nfunction isValidColor(string) {\n\t// https://stackoverflow.com/a/8027444/6495043\n\treturn /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);\n}\n\nconst getColor = (color) => {\n\treturn PRESET_COLOR_MAP[color] || color;\n};\n\nconst AXIS_TICK_LENGTH = 6;\nconst LABEL_MARGIN = 4;\nconst FONT_SIZE = 10;\nconst BASE_LINE_COLOR = '#dadada';\nconst FONT_FILL = '#555b51';\n\nfunction $$1(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nfunction createSVG(tag, o) {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$$1(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $$1(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction renderVerticalGradient(svgDefElem, gradientId) {\n\treturn createSVG('linearGradient', {\n\t\tinside: svgDefElem,\n\t\tid: gradientId,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: 0,\n\t\ty2: 1\n\t});\n}\n\nfunction setGradientStop(gradElem, offset, color, opacity) {\n\treturn createSVG('stop', {\n\t\t'inside': gradElem,\n\t\t'style': `stop-color: ${color}`,\n\t\t'offset': offset,\n\t\t'stop-opacity': opacity\n\t});\n}\n\nfunction makeSVGContainer(parent, className, width, height) {\n\treturn createSVG('svg', {\n\t\tclassName: className,\n\t\tinside: parent,\n\t\twidth: width,\n\t\theight: height\n\t});\n}\n\nfunction makeSVGDefs(svgContainer) {\n\treturn createSVG('defs', {\n\t\tinside: svgContainer,\n\t});\n}\n\nfunction makeSVGGroup(className, transform='', parent=undefined) {\n\tlet args = {\n\t\tclassName: className,\n\t\ttransform: transform\n\t};\n\tif(parent) args.inside = parent;\n\treturn createSVG('g', args);\n}\n\n\n\nfunction makePath(pathStr, className='', stroke='none', fill='none') {\n\treturn createSVG('path', {\n\t\tclassName: className,\n\t\td: pathStr,\n\t\tstyles: {\n\t\t\tstroke: stroke,\n\t\t\tfill: fill\n\t\t}\n\t});\n}\n\nfunction makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 0 ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nfunction makeGradient(svgDefElem, color, lighter = false) {\n\tlet gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');\n\tlet gradientDef = renderVerticalGradient(svgDefElem, gradientId);\n\tlet opacities = [1, 0.6, 0.2];\n\tif(lighter) {\n\t\topacities = [0.4, 0.2, 0];\n\t}\n\n\tsetGradientStop(gradientDef, \"0%\", color, opacities[0]);\n\tsetGradientStop(gradientDef, \"50%\", color, opacities[1]);\n\tsetGradientStop(gradientDef, \"100%\", color, opacities[2]);\n\n\treturn gradientId;\n}\n\nfunction percentageBar(x, y, width, height,\n\tdepth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {\n\n\tlet args = {\n\t\tclassName: 'percentage-bar',\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height,\n\t\tfill: fill,\n\t\tstyles: {\n\t\t\t'stroke': lightenDarkenColor(fill, -25),\n\t\t\t// Diabolically good: https://stackoverflow.com/a/9000859\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\n\t\t\t'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,\n\t\t\t'stroke-width': depth\n\t\t},\n\t};\n\n\treturn createSVG(\"rect\", args);\n}\n\nfunction heatSquare(className, x, y, size, fill='none', data={}) {\n\tlet args = {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: size,\n\t\theight: size,\n\t\tfill: fill\n\t};\n\n\tObject.keys(data).map(key => {\n\t\targs[key] = data[key];\n\t});\n\n\treturn createSVG(\"rect\", args);\n}\n\nfunction legendBar(x, y, size, fill='none', label) {\n\tlet args = {\n\t\tclassName: 'legend-bar',\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: size,\n\t\theight: '2px',\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE * 2) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"rect\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nfunction legendDot(x, y, size, fill='none', label) {\n\tlet args = {\n\t\tclassName: 'legend-dot',\n\t\tcx: 0,\n\t\tcy: 0,\n\t\tr: size,\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdx: (FONT_SIZE) + 'px',\n\t\tdy: (FONT_SIZE/3) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"circle\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nfunction makeText(className, x, y, content, options = {}) {\n\tlet fontSize = options.fontSize || FONT_SIZE;\n\tlet dy = options.dy !== undefined ? options.dy : (fontSize / 2);\n\tlet fill = options.fill || FONT_FILL;\n\tlet textAnchor = options.textAnchor || 'start';\n\treturn createSVG('text', {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\tdy: dy + 'px',\n\t\t'font-size': fontSize + 'px',\n\t\tfill: fill,\n\t\t'text-anchor': textAnchor,\n\t\tinnerHTML: content\n\t});\n}\n\nfunction makeVertLine(x, label, y1, y2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tlet l = createSVG('line', {\n\t\tclassName: 'line-vertical ' + options.className,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: y1,\n\t\ty2: y2,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: 0,\n\t\ty: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE,\n\t\tdy: FONT_SIZE + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'middle',\n\t\tinnerHTML: label + \"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(${ x }, 0)`\n\t});\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction makeHoriLine(y, label, x1, x2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.lineType) options.lineType = '';\n\tlet className = 'line-horizontal ' + options.className +\n\t\t(options.lineType === \"dashed\" ? \"dashed\": \"\");\n\n\tlet l = createSVG('line', {\n\t\tclassName: className,\n\t\tx1: x1,\n\t\tx2: x2,\n\t\ty1: 0,\n\t\ty2: 0,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / 2 - 2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': x1 < x2 ? 'end' : 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(0, ${y})`,\n\t\t'stroke-opacity': 1\n\t});\n\n\tif(text === 0 || text === '0') {\n\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t}\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction yLine(y, label, width, options={}) {\n\tif(!options.pos) options.pos = 'left';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\tlet x1 = -1 * AXIS_TICK_LENGTH;\n\tlet x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;\n\n\tif(options.mode === 'tick' && options.pos === 'right') {\n\t\tx1 = width + AXIS_TICK_LENGTH;\n\t\tx2 = width;\n\t}\n\n\t// let offset = options.pos === 'left' ? -1 * options.offset : options.offset;\n\n\tx1 += options.offset;\n\tx2 += options.offset;\n\n\treturn makeHoriLine(y, label, x1, x2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nfunction xLine(x, label, height, options={}) {\n\tif(!options.pos) options.pos = 'bottom';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\t// Draw X axis line in span/tick mode with optional label\n\t// \ty2(span)\n\t// \t\t\t\t\t\t|\n\t// \t\t\t\t\t\t|\n\t//\t\t\t\tx line\t|\n\t//\t\t\t\t\t\t|\n\t// \t\t\t\t\t \t|\n\t// ---------------------+-- y2(tick)\n\t//\t\t\t\t\t\t|\n\t//\t\t\t\t\t\t\ty1\n\n\tlet y1 = height + AXIS_TICK_LENGTH;\n\tlet y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;\n\n\tif(options.mode === 'tick' && options.pos === 'top') {\n\t\t// top axis ticks\n\t\ty1 = -1 * AXIS_TICK_LENGTH;\n\t\ty2 = 0;\n\t}\n\n\treturn makeVertLine(x, label, y1, y2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nfunction yMarker(y, label, width, options={}) {\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label, 5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = makeHoriLine(y, '', 0, width, {\n\t\tstroke: options.stroke || BASE_LINE_COLOR,\n\t\tclassName: options.className || '',\n\t\tlineType: options.lineType\n\t});\n\n\tline.appendChild(labelSvg);\n\n\treturn line;\n}\n\nfunction yRegion(y1, y2, width, label, options={}) {\n\t// return a group\n\tlet height = y1 - y2;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`, // remove class\n\t\tstyles: {\n\t\t\tfill: `rgba(228, 234, 239, 0.49)`,\n\t\t\tstroke: BASE_LINE_COLOR,\n\t\t\t'stroke-dasharray': `${width}, ${height}`\n\t\t},\n\t\t// 'data-point-index': index,\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label+\"\", 4.5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet region = createSVG('g', {\n\t\ttransform: `translate(0, ${y2})`\n\t});\n\n\tregion.appendChild(rect);\n\tregion.appendChild(labelSvg);\n\n\treturn region;\n}\n\nfunction datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\n\tif(height === 0) {\n\t\theight = meta.minHeight;\n\t\ty -= meta.minHeight;\n\t}\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`,\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn rect;\n\t} else {\n\t\trect.setAttribute('y', 0);\n\t\trect.setAttribute('x', 0);\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: width/2,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(rect);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nfunction datasetDot(x, y, radius, color, label='', index=0) {\n\tlet dot = createSVG('circle', {\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tcx: x,\n\t\tcy: y,\n\t\tr: radius\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn dot;\n\t} else {\n\t\tdot.setAttribute('cy', 0);\n\t\tdot.setAttribute('cx', 0);\n\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1 - radius) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(dot);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nfunction getPaths(xList, yList, color, options={}, meta={}) {\n\tlet pointsList = yList.map((y, i) => (xList[i] + ',' + y));\n\tlet pointsStr = pointsList.join(\"L\");\n\tlet path = makePath(\"M\"+pointsStr, 'line-graph-path', color);\n\n\t// HeatLine\n\tif(options.heatline) {\n\t\tlet gradient_id = makeGradient(meta.svgDefs, color);\n\t\tpath.style.stroke = `url(#${gradient_id})`;\n\t}\n\n\tlet paths = {\n\t\tpath: path\n\t};\n\n\t// Region\n\tif(options.regionFill) {\n\t\tlet gradient_id_region = makeGradient(meta.svgDefs, color, true);\n\n\t\tlet pathStr = \"M\" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;\n\t\tpaths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`);\n\t}\n\n\treturn paths;\n}\n\nlet makeOverlay = {\n\t'bar': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\toverlay.style.fill = '#000000';\n\t\toverlay.style.opacity = '0.4';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'dot': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'heat_square': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t}\n};\n\nlet updateOverlay = {\n\t'bar': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['x', 'y', 'width', 'height'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'dot': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'heat_square': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n};\n\nconst UNIT_ANIM_DUR = 350;\nconst PATH_ANIM_DUR = 350;\nconst MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;\nconst REPLACE_ALL_NEW_DUR = 250;\n\nconst STD_EASING = 'easein';\n\nfunction translate(unit, oldCoord, newCoord, duration) {\n\tlet old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');\n\treturn [\n\t\tunit,\n\t\t{transform: newCoord.join(', ')},\n\t\tduration,\n\t\tSTD_EASING,\n\t\t\"translate\",\n\t\t{transform: old}\n\t];\n}\n\nfunction translateVertLine(xLine, newX, oldX) {\n\treturn translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR);\n}\n\nfunction translateHoriLine(yLine, newY, oldY) {\n\treturn translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR);\n}\n\nfunction animateRegion(rectGroup, newY1, newY2, oldY2) {\n\tlet newHeight = newY1 - newY2;\n\tlet rect = rectGroup.childNodes[0];\n\tlet width = rect.getAttribute(\"width\");\n\tlet rectAnim = [\n\t\trect,\n\t\t{ height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` },\n\t\tMARKER_LINE_ANIM_DUR,\n\t\tSTD_EASING\n\t];\n\n\tlet groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR);\n\treturn [rectAnim, groupAnim];\n}\n\nfunction animateBar(bar, x, yTop, width, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\tif(bar.nodeName !== 'rect') {\n\t\tlet rect = bar.childNodes[0];\n\t\tlet rectAnim = [\n\t\t\trect,\n\t\t\t{width: width, height: height},\n\t\t\tUNIT_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\n\t\tlet oldCoordStr = bar.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [rectAnim, groupAnim];\n\t} else {\n\t\treturn [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nfunction animateDot(dot, x, y) {\n\tif(dot.nodeName !== 'circle') {\n\t\tlet oldCoordStr = dot.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [groupAnim];\n\t} else {\n\t\treturn [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nfunction animatePath(paths, newXList, newYList, zeroLine) {\n\tlet pathComponents = [];\n\n\tlet pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y));\n\tlet pathStr = pointsStr.join(\"L\");\n\n\tconst animPath = [paths.path, {d:\"M\"+pathStr}, PATH_ANIM_DUR, STD_EASING];\n\tpathComponents.push(animPath);\n\n\tif(paths.region) {\n\t\tlet regStartPt = `${newXList[0]},${zeroLine}L`;\n\t\tlet regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;\n\n\t\tconst animRegion = [\n\t\t\tpaths.region,\n\t\t\t{d:\"M\" + regStartPt + pathStr + regEndPt},\n\t\t\tPATH_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\t\tpathComponents.push(animRegion);\n\t}\n\n\treturn pathComponents;\n}\n\nfunction animatePathStr(oldPath, pathStr) {\n\treturn [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];\n}\n\n// Leveraging SMIL Animations\n\nconst EASING = {\n\tease: \"0.25 0.1 0.25 1\",\n\tlinear: \"0 0 1 1\",\n\t// easein: \"0.42 0 1 1\",\n\teasein: \"0.1 0.8 0.2 1\",\n\teaseout: \"0 0 0.58 1\",\n\teaseinout: \"0.42 0 0.58 1\"\n};\n\nfunction animateSVGElement(element, props, dur, easingType=\"linear\", type=undefined, oldValues={}) {\n\n\tlet animElement = element.cloneNode(true);\n\tlet newElement = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animateElement;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet currentValue = oldValues[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet animAttr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: currentValue,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: currentValue + \";\" + value,\n\t\t\tkeySplines: EASING[easingType],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanimAttr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in animAttr) {\n\t\t\tanimateElement.setAttribute(i, animAttr[i]);\n\t\t}\n\n\t\tanimElement.appendChild(animateElement);\n\n\t\tif(type) {\n\t\t\tnewElement.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnewElement.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [animElement, newElement];\n}\n\nfunction transform(element, style) { // eslint-disable-line no-unused-vars\n\telement.style.transform = style;\n\telement.style.webkitTransform = style;\n\telement.style.msTransform = style;\n\telement.style.mozTransform = style;\n\telement.style.oTransform = style;\n}\n\nfunction animateSVG(svgContainer, elements) {\n\tlet newElements = [];\n\tlet animElements = [];\n\n\telements.map(element => {\n\t\tlet unit = element[0];\n\t\tlet parent = unit.parentNode;\n\n\t\tlet animElement, newElement;\n\n\t\telement[0] = unit;\n\t\t[animElement, newElement] = animateSVGElement(...element);\n\n\t\tnewElements.push(newElement);\n\t\tanimElements.push([animElement, parent]);\n\n\t\tparent.replaceChild(animElement, unit);\n\t});\n\n\tlet animSvg = svgContainer.cloneNode(true);\n\n\tanimElements.map((animElement, i) => {\n\t\tanimElement[1].replaceChild(newElements[i], animElement[0]);\n\t\telements[i][0] = newElements[i];\n\t});\n\n\treturn animSvg;\n}\n\nfunction runSMILAnimation(parent, svgElement, elementsToAnimate) {\n\tif(elementsToAnimate.length === 0) return;\n\n\tlet animSvgElement = animateSVG(svgElement, elementsToAnimate);\n\tif(svgElement.parentNode == parent) {\n\t\tparent.removeChild(svgElement);\n\t\tparent.appendChild(animSvgElement);\n\n\t}\n\n\t// Replace the new svgElement (data has already been replaced)\n\tsetTimeout(() => {\n\t\tif(animSvgElement.parentNode == parent) {\n\t\t\tparent.removeChild(animSvgElement);\n\t\t\tparent.appendChild(svgElement);\n\t\t}\n\t}, REPLACE_ALL_NEW_DUR);\n}\n\nconst CSSTEXT = \".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}\";\n\nfunction downloadFile(filename, data) {\n\tvar a = document.createElement('a');\n\ta.style = \"display: none\";\n\tvar blob = new Blob(data, {type: \"image/svg+xml; charset=utf-8\"});\n\tvar url = window.URL.createObjectURL(blob);\n\ta.href = url;\n\ta.download = filename;\n\tdocument.body.appendChild(a);\n\ta.click();\n\tsetTimeout(function(){\n\t\tdocument.body.removeChild(a);\n\t\twindow.URL.revokeObjectURL(url);\n\t}, 300);\n}\n\nfunction prepareForExport(svg) {\n\tlet clone = svg.cloneNode(true);\n\tclone.classList.add('chart-container');\n\tclone.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n\tclone.setAttribute('xmlns:xlink', \"http://www.w3.org/1999/xlink\");\n\tlet styleEl = $.create('style', {\n\t\t'innerHTML': CSSTEXT\n\t});\n\tclone.insertBefore(styleEl, clone.firstChild);\n\n\tlet container = $.create('div');\n\tcontainer.appendChild(clone);\n\n\treturn container.innerHTML;\n}\n\nlet BOUND_DRAW_FN;\n\nclass BaseChart {\n\tconstructor(parent, options) {\n\n\t\tthis.parent = typeof parent === 'string'\n\t\t\t? document.querySelector(parent)\n\t\t\t: parent;\n\n\t\tif (!(this.parent instanceof HTMLElement)) {\n\t\t\tthrow new Error('No `parent` element to render on was provided.');\n\t\t}\n\n\t\tthis.rawChartArgs = options;\n\n\t\tthis.title = options.title || '';\n\t\tthis.type = options.type || '';\n\n\t\tthis.realData = this.prepareData(options.data);\n\t\tthis.data = this.prepareFirstData(this.realData);\n\n\t\tthis.colors = this.validateColors(options.colors, this.type);\n\n\t\tthis.config = {\n\t\t\tshowTooltip: 1, // calculate\n\t\t\tshowLegend: 1, // calculate\n\t\t\tisNavigable: options.isNavigable || 0,\n\t\t\tanimate: 1\n\t\t};\n\n\t\tthis.measures = JSON.parse(JSON.stringify(BASE_MEASURES));\n\t\tlet m = this.measures;\n\t\tthis.setMeasures(options);\n\t\tif(!this.title.length) { m.titleHeight = 0; }\n\t\tif(!this.config.showLegend) m.legendHeight = 0;\n\t\tthis.argHeight = options.height || m.baseHeight;\n\n\t\tthis.state = {};\n\t\tthis.options = {};\n\n\t\tthis.initTimeout = INIT_CHART_UPDATE_TIMEOUT;\n\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.overlays = [];\n\t\t}\n\n\t\tthis.configure(options);\n\t}\n\n\tprepareData(data) {\n\t\treturn data;\n\t}\n\n\tprepareFirstData(data) {\n\t\treturn data;\n\t}\n\n\tvalidateColors(colors, type) {\n\t\tconst validColors = [];\n\t\tcolors = (colors || []).concat(DEFAULT_COLORS[type]);\n\t\tcolors.forEach((string) => {\n\t\t\tconst color = getColor(string);\n\t\t\tif(!isValidColor(color)) {\n\t\t\t\tconsole.warn('\"' + string + '\" is not a valid color.');\n\t\t\t} else {\n\t\t\t\tvalidColors.push(color);\n\t\t\t}\n\t\t});\n\t\treturn validColors;\n\t}\n\n\tsetMeasures() {\n\t\t// Override measures, including those for title and legend\n\t\t// set config for legend and title\n\t}\n\n\tconfigure() {\n\t\tlet height = this.argHeight;\n\t\tthis.baseHeight = height;\n\t\tthis.height = height - getExtraHeight(this.measures);\n\n\t\t// Bind window events\n\t\tBOUND_DRAW_FN = this.boundDrawFn.bind(this);\n\t\twindow.addEventListener('resize', BOUND_DRAW_FN);\n\t\twindow.addEventListener('orientationchange', this.boundDrawFn.bind(this));\n\t}\n\n\tboundDrawFn() {\n\t\tthis.draw(true);\n\t}\n\n\tunbindWindowEvents() {\n\t\twindow.removeEventListener('resize', BOUND_DRAW_FN);\n\t\twindow.removeEventListener('orientationchange', this.boundDrawFn.bind(this));\n\t}\n\n\t// Has to be called manually\n\tsetup() {\n\t\tthis.makeContainer();\n\t\tthis.updateWidth();\n\t\tthis.makeTooltip();\n\n\t\tthis.draw(false, true);\n\t}\n\n\tmakeContainer() {\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\n\t\tlet args = {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'chart-container'\n\t\t};\n\n\t\tif(this.independentWidth) {\n\t\t\targs.styles = { width: this.independentWidth + 'px' };\n\t\t}\n\n\t\tthis.container = $.create('div', args);\n\t}\n\n\tmakeTooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.container,\n\t\t\tcolors: this.colors\n\t\t});\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {}\n\n\tdraw(onlyWidthChange=false, init=false) {\n\t\tthis.updateWidth();\n\n\t\tthis.calc(onlyWidthChange);\n\t\tthis.makeChartArea();\n\t\tthis.setupComponents();\n\n\t\tthis.components.forEach(c => c.setup(this.drawArea));\n\t\t// this.components.forEach(c => c.make());\n\t\tthis.render(this.components, false);\n\n\t\tif(init) {\n\t\t\tthis.data = this.realData;\n\t\t\tsetTimeout(() => {this.update(this.data);}, this.initTimeout);\n\t\t}\n\n\t\tthis.renderLegend();\n\n\t\tthis.setupNavigation(init);\n\t}\n\n\tcalc() {} // builds state\n\n\tupdateWidth() {\n\t\tthis.baseWidth = getElementContentWidth(this.parent);\n\t\tthis.width = this.baseWidth - getExtraWidth(this.measures);\n\t}\n\n\tmakeChartArea() {\n\t\tif(this.svg) {\n\t\t\tthis.container.removeChild(this.svg);\n\t\t}\n\t\tlet m = this.measures;\n\n\t\tthis.svg = makeSVGContainer(\n\t\t\tthis.container,\n\t\t\t'frappe-chart chart',\n\t\t\tthis.baseWidth,\n\t\t\tthis.baseHeight\n\t\t);\n\t\tthis.svgDefs = makeSVGDefs(this.svg);\n\n\t\tif(this.title.length) {\n\t\t\tthis.titleEL = makeText(\n\t\t\t\t'title',\n\t\t\t\tm.margins.left,\n\t\t\t\tm.margins.top,\n\t\t\t\tthis.title,\n\t\t\t\t{\n\t\t\t\t\tfontSize: m.titleFontSize,\n\t\t\t\t\tfill: '#666666',\n\t\t\t\t\tdy: m.titleFontSize\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tlet top = getTopOffset(m);\n\t\tthis.drawArea = makeSVGGroup(\n\t\t\tthis.type + '-chart chart-draw-area',\n\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t);\n\n\t\tif(this.config.showLegend) {\n\t\t\ttop += this.height + m.paddings.bottom;\n\t\t\tthis.legendArea = makeSVGGroup(\n\t\t\t\t'chart-legend',\n\t\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t\t);\n\t\t}\n\n\t\tif(this.title.length) { this.svg.appendChild(this.titleEL); }\n\t\tthis.svg.appendChild(this.drawArea);\n\t\tif(this.config.showLegend) { this.svg.appendChild(this.legendArea); }\n\n\t\tthis.updateTipOffset(getLeftOffset(m), getTopOffset(m));\n\t}\n\n\tupdateTipOffset(x, y) {\n\t\tthis.tip.offset = {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t}\n\n\tsetupComponents() { this.components = new Map(); }\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\t\tthis.data = this.prepareData(data);\n\t\tthis.calc(); // builds state\n\t\tthis.render();\n\t}\n\n\trender(components=this.components, animate=true) {\n\t\tif(this.config.isNavigable) {\n\t\t\t// Remove all existing overlays\n\t\t\tthis.overlays.map(o => o.parentNode.removeChild(o));\n\t\t\t// ref.parentNode.insertBefore(element, ref);\n\t\t}\n\t\tlet elementsToAnimate = [];\n\t\t// Can decouple to this.refreshComponents() first to save animation timeout\n\t\tcomponents.forEach(c => {\n\t\t\telementsToAnimate = elementsToAnimate.concat(c.update(animate));\n\t\t});\n\t\tif(elementsToAnimate.length > 0) {\n\t\t\trunSMILAnimation(this.container, this.svg, elementsToAnimate);\n\t\t\tsetTimeout(() => {\n\t\t\t\tcomponents.forEach(c => c.make());\n\t\t\t\tthis.updateNav();\n\t\t\t}, CHART_POST_ANIMATE_TIMEOUT);\n\t\t} else {\n\t\t\tcomponents.forEach(c => c.make());\n\t\t\tthis.updateNav();\n\t\t}\n\t}\n\n\tupdateNav() {\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.makeOverlay();\n\t\t\tthis.bindUnits();\n\t\t}\n\t}\n\n\trenderLegend() {}\n\n\tsetupNavigation(init=false) {\n\t\tif(!this.config.isNavigable) return;\n\n\t\tif(init) {\n\t\t\tthis.bindOverlay();\n\n\t\t\tthis.keyActions = {\n\t\t\t\t'13': this.onEnterKey.bind(this),\n\t\t\t\t'37': this.onLeftArrow.bind(this),\n\t\t\t\t'38': this.onUpArrow.bind(this),\n\t\t\t\t'39': this.onRightArrow.bind(this),\n\t\t\t\t'40': this.onDownArrow.bind(this),\n\t\t\t};\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif(isElementInViewport(this.container)) {\n\t\t\t\t\te = e || window.event;\n\t\t\t\t\tif(this.keyActions[e.keyCode]) {\n\t\t\t\t\t\tthis.keyActions[e.keyCode]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmakeOverlay() {}\n\tupdateOverlay() {}\n\tbindOverlay() {}\n\tbindUnits() {}\n\n\tonLeftArrow() {}\n\tonRightArrow() {}\n\tonUpArrow() {}\n\tonDownArrow() {}\n\tonEnterKey() {}\n\n\taddDataPoint() {}\n\tremoveDataPoint() {}\n\n\tgetDataPoint() {}\n\tsetCurrentDataPoint() {}\n\n\tupdateDataset() {}\n\n\texport() {\n\t\tlet chartSvg = prepareForExport(this.svg);\n\t\tdownloadFile(this.title || 'Chart', [chartSvg]);\n\t}\n}\n\nclass AggregationChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\n\t\tthis.config.maxSlices = args.maxSlices || 20;\n\t\tthis.config.maxLegendPoints = args.maxLegendPoints || 20;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\t\tlet maxSlices = this.config.maxSlices;\n\t\ts.sliceTotals = [];\n\n\t\tlet allTotals = this.data.labels.map((label, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, label];\n\t\t}).filter(d => { return d[0] >= 0; }); // keep only positive results\n\n\t\tlet totals = allTotals;\n\t\tif(allTotals.length > maxSlices) {\n\t\t\t// Prune and keep a grey area for rest as per maxSlices\n\t\t\tallTotals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = allTotals.slice(0, maxSlices-1);\n\t\t\tlet remaining = allTotals.slice(maxSlices-1);\n\n\t\t\tlet sumOfRemaining = 0;\n\t\t\tremaining.map(d => {sumOfRemaining += d[0];});\n\t\t\ttotals.push([sumOfRemaining, 'Rest']);\n\t\t\tthis.colors[maxSlices-1] = 'grey';\n\t\t}\n\n\t\ts.labels = [];\n\t\ttotals.map(d => {\n\t\t\ts.sliceTotals.push(d[0]);\n\t\t\ts.labels.push(d[1]);\n\t\t});\n\n\t\ts.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);\n\n\t\tthis.center = {\n\t\t\tx: this.width / 2,\n\t\t\ty: this.height / 2\n\t\t};\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.state;\n\t\tthis.legendArea.textContent = '';\n\t\tthis.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);\n\n\t\tlet count = 0;\n\t\tlet y = 0;\n\t\tthis.legendTotals.map((d, i) => {\n\t\t\tlet barWidth = 110;\n\t\t\tlet divisor = Math.floor(\n\t\t\t\t(this.width - getExtraWidth(this.measures))/barWidth\n\t\t\t);\n\t\t\tif(count > divisor) {\n\t\t\t\tcount = 0;\n\t\t\t\ty += 20;\n\t\t\t}\n\t\t\tlet x = barWidth * count + 5;\n\t\t\tlet dot = legendDot(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\t5,\n\t\t\t\tthis.colors[i],\n\t\t\t\t`${s.labels[i]}: ${d}`\n\t\t\t);\n\t\t\tthis.legendArea.appendChild(dot);\n\t\t\tcount++;\n\t\t});\n\t}\n}\n\n// Playing around with dates\n\nconst NO_OF_YEAR_MONTHS = 12;\nconst NO_OF_DAYS_IN_WEEK = 7;\n\nconst NO_OF_MILLIS = 1000;\nconst SEC_IN_DAY = 86400;\n\nconst MONTH_NAMES = [\"January\", \"February\", \"March\", \"April\", \"May\",\n\t\"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\n\n\nconst DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\n\n// https://stackoverflow.com/a/11252167/6495043\nfunction treatAsUtc(date) {\n\tlet result = new Date(date);\n\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\treturn result;\n}\n\nfunction getYyyyMmDd(date) {\n\tlet dd = date.getDate();\n\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\treturn [\n\t\tdate.getFullYear(),\n\t\t(mm>9 ? '' : '0') + mm,\n\t\t(dd>9 ? '' : '0') + dd\n\t].join('-');\n}\n\nfunction clone(date) {\n\treturn new Date(date.getTime());\n}\n\n\n\n\n\n// export function getMonthsBetween(startDate, endDate) {}\n\nfunction getWeeksBetween(startDate, endDate) {\n\tlet weekStartDate = setDayToSunday(startDate);\n\treturn Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);\n}\n\nfunction getDaysBetween(startDate, endDate) {\n\tlet millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;\n\treturn (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;\n}\n\nfunction areInSameMonth(startDate, endDate) {\n\treturn startDate.getMonth() === endDate.getMonth()\n\t\t&& startDate.getFullYear() === endDate.getFullYear();\n}\n\nfunction getMonthName(i, short=false) {\n\tlet monthName = MONTH_NAMES[i];\n\treturn short ? monthName.slice(0, 3) : monthName;\n}\n\nfunction getLastDateInMonth (month, year) {\n\treturn new Date(year, month + 1, 0); // 0: last day in previous month\n}\n\n// mutates\nfunction setDayToSunday(date) {\n\tlet newDate = clone(date);\n\tconst day = newDate.getDay();\n\tif(day !== 0) {\n\t\taddDays(newDate, (-1) * day);\n\t}\n\treturn newDate;\n}\n\n// mutates\nfunction addDays(date, numberOfDays) {\n\tdate.setDate(date.getDate() + numberOfDays);\n}\n\nclass ChartComponent {\n\tconstructor({\n\t\tlayerClass = '',\n\t\tlayerTransform = '',\n\t\tconstants,\n\n\t\tgetData,\n\t\tmakeElements,\n\t\tanimateElements\n\t}) {\n\t\tthis.layerTransform = layerTransform;\n\t\tthis.constants = constants;\n\n\t\tthis.makeElements = makeElements;\n\t\tthis.getData = getData;\n\n\t\tthis.animateElements = animateElements;\n\n\t\tthis.store = [];\n\t\tthis.labels = [];\n\n\t\tthis.layerClass = layerClass;\n\t\tthis.layerClass = typeof(this.layerClass) === 'function'\n\t\t\t? this.layerClass() : this.layerClass;\n\n\t\tthis.refresh();\n\t}\n\n\trefresh(data) {\n\t\tthis.data = data || this.getData();\n\t}\n\n\tsetup(parent) {\n\t\tthis.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent);\n\t}\n\n\tmake() {\n\t\tthis.render(this.data);\n\t\tthis.oldData = this.data;\n\t}\n\n\trender(data) {\n\t\tthis.store = this.makeElements(data);\n\n\t\tthis.layer.textContent = '';\n\t\tthis.store.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t\tthis.labels.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t}\n\n\tupdate(animate = true) {\n\t\tthis.refresh();\n\t\tlet animateElements = [];\n\t\tif(animate) {\n\t\t\tanimateElements = this.animateElements(this.data) || [];\n\t\t}\n\t\treturn animateElements;\n\t}\n}\n\nlet componentConfigs = {\n\tpieSlices: {\n\t\tlayerClass: 'pie-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) =>{\n\t\t\t\tlet slice = makePath(s, 'pie-path', 'none', data.colors[i]);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) =>\n\t\t\t\tanimatePathStr(slice, newData.sliceStrings[i])\n\t\t\t);\n\t\t}\n\t},\n\tpercentageBars: {\n\t\tlayerClass: 'percentage-bars',\n\t\tmakeElements(data) {\n\t\t\treturn data.xPositions.map((x, i) =>{\n\t\t\t\tlet y = 0;\n\t\t\t\tlet bar = percentageBar(x, y, data.widths[i],\n\t\t\t\t\tthis.constants.barHeight, this.constants.barDepth, data.colors[i]);\n\t\t\t\treturn bar;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\tyAxis: {\n\t\tlayerClass: 'y axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\tyLine(position, data.labels[i], this.constants.width,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.labels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tlabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\txAxis: {\n\t\tlayerClass: 'x axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\txLine(position, data.calcLabels[i], this.constants.height,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.calcLabels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.calcLabels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tcalcLabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateVertLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyMarkers: {\n\t\tlayerClass: 'y-markers',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(m =>\n\t\t\t\tyMarker(m.position, m.label, this.constants.width,\n\t\t\t\t\t{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.position);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.position);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tposition: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyRegions: {\n\t\tlayerClass: 'y-regions',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(r =>\n\t\t\t\tyRegion(r.startPos, r.endPos, this.constants.width,\n\t\t\t\t\tr.label, {labelPos: r.options.labelPos})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.endPos);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newStarts = newData.map(d => d.startPos);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.endPos);\n\t\t\tlet oldStarts = this.oldData.map(d => d.startPos);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tstartPos: oldStarts[i],\n\t\t\t\t\tendPos: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((rectGroup, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateRegion(\n\t\t\t\t\trectGroup, newStarts[i], newPos[i], oldPos[i]\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\theatDomain: {\n\t\tlayerClass: function() { return 'heat-domain domain-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet {index, colWidth, rowHeight, squareSize, xTranslate} = this.constants;\n\t\t\tlet monthNameHeight = -12;\n\t\t\tlet x = xTranslate, y = 0;\n\n\t\t\tthis.serializedSubDomains = [];\n\n\t\t\tdata.cols.map((week, weekNo) => {\n\t\t\t\tif(weekNo === 1) {\n\t\t\t\t\tthis.labels.push(\n\t\t\t\t\t\tmakeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfontSize: 9\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tweek.map((day, i) => {\n\t\t\t\t\tif(day.fill) {\n\t\t\t\t\t\tlet data = {\n\t\t\t\t\t\t\t'data-date': day.yyyyMmDd,\n\t\t\t\t\t\t\t'data-value': day.dataValue,\n\t\t\t\t\t\t\t'data-day': i\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet square = heatSquare('day', x, y, squareSize, day.fill, data);\n\t\t\t\t\t\tthis.serializedSubDomains.push(square);\n\t\t\t\t\t}\n\t\t\t\t\ty += rowHeight;\n\t\t\t\t});\n\t\t\t\ty = 0;\n\t\t\t\tx += colWidth;\n\t\t\t});\n\n\t\t\treturn this.serializedSubDomains;\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\n\tbarGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'bar';\n\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\treturn datasetBar(\n\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\ty,\n\t\t\t\t\tdata.barWidth,\n\t\t\t\t\tc.color,\n\t\t\t\t\tdata.labels[j],\n\t\t\t\t\tj,\n\t\t\t\t\tdata.offsets[j],\n\t\t\t\t\t{\n\t\t\t\t\t\tzeroLine: data.zeroLine,\n\t\t\t\t\t\tbarsWidth: data.barsWidth,\n\t\t\t\t\t\tminHeight: c.minHeight\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn this.units;\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newOffsets = newData.offsets;\n\t\t\tlet newLabels = newData.labels;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldOffsets = this.oldData.offsets;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\toffsets: oldOffsets,\n\t\t\t\tlabels: newLabels,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tbarsWidth: this.oldData.barsWidth,\n\t\t\t\tbarWidth: this.oldData.barWidth,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((bar, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateBar(\n\t\t\t\t\tbar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],\n\t\t\t\t\t{zeroLine: newData.zeroLine}\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\tlineGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'dot';\n\t\t\tthis.paths = {};\n\t\t\tif(!c.hideLine) {\n\t\t\t\tthis.paths = getPaths(\n\t\t\t\t\tdata.xPositions,\n\t\t\t\t\tdata.yPositions,\n\t\t\t\t\tc.color,\n\t\t\t\t\t{\n\t\t\t\t\t\theatline: c.heatline,\n\t\t\t\t\t\tregionFill: c.regionFill\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsvgDefs: c.svgDefs,\n\t\t\t\t\t\tzeroLine: data.zeroLine\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.units = [];\n\t\t\tif(!c.hideDots) {\n\t\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\t\treturn datasetDot(\n\t\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\t\ty,\n\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\tc.color,\n\t\t\t\t\t\t(c.valuesOverPoints ? data.values[j] : ''),\n\t\t\t\t\t\tj\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Object.values(this.paths).concat(this.units);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newValues = newData.values;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldValues = this.oldData.values;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\tvalues: newValues,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tradius: this.oldData.radius,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tif(Object.keys(this.paths).length) {\n\t\t\t\tanimateElements = animateElements.concat(animatePath(\n\t\t\t\t\tthis.paths, newXPos, newYPos, newData.zeroLine));\n\t\t\t}\n\n\t\t\tif(this.units.length) {\n\t\t\t\tthis.units.map((dot, i) => {\n\t\t\t\t\tanimateElements = animateElements.concat(animateDot(\n\t\t\t\t\t\tdot, newXPos[i], newYPos[i]));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn animateElements;\n\t\t}\n\t}\n};\n\nfunction getComponent(name, constants, getData) {\n\tlet keys = Object.keys(componentConfigs).filter(k => name.includes(k));\n\tlet config = componentConfigs[keys[0]];\n\tObject.assign(config, {\n\t\tconstants: constants,\n\t\tgetData: getData\n\t});\n\treturn new ChartComponent(config);\n}\n\nclass PercentageChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'percentage';\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.barOptions = options.barOptions || {};\n\n\t\tlet b = this.barOptions;\n\t\tb.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;\n\t\tb.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;\n\n\t\tm.paddings.right = 30;\n\t\tm.legendHeight = 80;\n\t\tm.baseHeight = (b.height + b.depth * 0.5) * 8;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'percentageBars',\n\t\t\t\t{\n\t\t\t\t\tbarHeight: this.barOptions.height,\n\t\t\t\t\tbarDepth: this.barOptions.depth,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xPositions,\n\t\t\t\t\t\twidths: s.widths,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\n\t\ts.xPositions = [];\n\t\ts.widths = [];\n\n\t\tlet xPos = 0;\n\t\ts.sliceTotals.map((value) => {\n\t\t\tlet width = this.width * value / s.grandTotal;\n\t\t\ts.widths.push(width);\n\t\t\ts.xPositions.push(xPos);\n\t\t\txPos += width;\n\t\t});\n\t}\n\n\tmakeDataByIndex() { }\n\n\tbindTooltip() {\n\t\tlet s = this.state;\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet bars = this.components.get('percentageBars').store;\n\t\t\tlet bar = e.target;\n\t\t\tif(bars.includes(bar)) {\n\n\t\t\t\tlet i = bars.indexOf(bar);\n\t\t\t\tlet gOff = getOffset(this.container), pOff = getOffset(bar);\n\n\t\t\t\tlet x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;\n\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\tlet title = (this.formattedLabels && this.formattedLabels.length>0\n\t\t\t\t\t? this.formattedLabels[i] : this.state.labels[i]) + ': ';\n\t\t\t\tlet fraction = s.sliceTotals[i]/s.grandTotal;\n\n\t\t\t\tthis.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + \"%\"});\n\t\t\t\tthis.tip.showTip();\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass PieChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'pie';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius = (this.height > this.width ? this.center.x : this.center.y);\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath = makeArcPathStr(curStart, curEnd, this.center, this.radius, this.clockWise);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'pieSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{radius,hoverRadio} = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.fill = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.fill = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('pieSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n\nfunction normalize(x) {\n\t// Calculates mantissa and exponent of a number\n\t// Returns normalized number and exponent\n\t// https://stackoverflow.com/q/9383593/6495043\n\n\tif(x===0) {\n\t\treturn [0, 0];\n\t}\n\tif(isNaN(x)) {\n\t\treturn {mantissa: -6755399441055744, exponent: 972};\n\t}\n\tvar sig = x > 0 ? 1 : -1;\n\tif(!isFinite(x)) {\n\t\treturn {mantissa: sig * 4503599627370496, exponent: 972};\n\t}\n\n\tx = Math.abs(x);\n\tvar exp = Math.floor(Math.log10(x));\n\tvar man = x/Math.pow(10, exp);\n\n\treturn [sig * man, exp];\n}\n\nfunction getChartRangeIntervals(max, min=0) {\n\tlet upperBound = Math.ceil(max);\n\tlet lowerBound = Math.floor(min);\n\tlet range = upperBound - lowerBound;\n\n\tlet noOfParts = range;\n\tlet partSize = 1;\n\n\t// To avoid too many partitions\n\tif(range > 5) {\n\t\tif(range % 2 !== 0) {\n\t\t\tupperBound++;\n\t\t\t// Recalc range\n\t\t\trange = upperBound - lowerBound;\n\t\t}\n\t\tnoOfParts = range/2;\n\t\tpartSize = 2;\n\t}\n\n\t// Special case: 1 and 2\n\tif(range <= 2) {\n\t\tnoOfParts = 4;\n\t\tpartSize = range/noOfParts;\n\t}\n\n\t// Special case: 0\n\tif(range === 0) {\n\t\tnoOfParts = 5;\n\t\tpartSize = 1;\n\t}\n\n\tlet intervals = [];\n\tfor(var i = 0; i <= noOfParts; i++){\n\t\tintervals.push(lowerBound + partSize * i);\n\t}\n\treturn intervals;\n}\n\nfunction getChartIntervals(maxValue, minValue=0) {\n\tlet [normalMaxValue, exponent] = normalize(maxValue);\n\tlet normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;\n\n\t// Allow only 7 significant digits\n\tnormalMaxValue = normalMaxValue.toFixed(6);\n\n\tlet intervals = getChartRangeIntervals(normalMaxValue, normalMinValue);\n\tintervals = intervals.map(value => value * Math.pow(10, exponent));\n\treturn intervals;\n}\n\nfunction calcChartIntervals(values, withMinimum=false) {\n\t//*** Where the magic happens ***\n\n\t// Calculates best-fit y intervals from given values\n\t// and returns the interval array\n\n\tlet maxValue = Math.max(...values);\n\tlet minValue = Math.min(...values);\n\n\t// Exponent to be used for pretty print\n\tlet exponent = 0, intervals = []; // eslint-disable-line no-unused-vars\n\n\tfunction getPositiveFirstIntervals(maxValue, absMinValue) {\n\t\tlet intervals = getChartIntervals(maxValue);\n\n\t\tlet intervalSize = intervals[1] - intervals[0];\n\n\t\t// Then unshift the negative values\n\t\tlet value = 0;\n\t\tfor(var i = 1; value < absMinValue; i++) {\n\t\t\tvalue += intervalSize;\n\t\t\tintervals.unshift((-1) * value);\n\t\t}\n\t\treturn intervals;\n\t}\n\n\t// CASE I: Both non-negative\n\n\tif(maxValue >= 0 && minValue >= 0) {\n\t\texponent = normalize(maxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(maxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(maxValue, minValue);\n\t\t}\n\t}\n\n\t// CASE II: Only minValue negative\n\n\telse if(maxValue > 0 && minValue < 0) {\n\t\t// `withMinimum` irrelevant in this case,\n\t\t// We'll be handling both sides of zero separately\n\t\t// (both starting from zero)\n\t\t// Because ceil() and floor() behave differently\n\t\t// in those two regions\n\n\t\tlet absMinValue = Math.abs(minValue);\n\n\t\tif(maxValue >= absMinValue) {\n\t\t\texponent = normalize(maxValue)[1];\n\t\t\tintervals = getPositiveFirstIntervals(maxValue, absMinValue);\n\t\t} else {\n\t\t\t// Mirror: maxValue => absMinValue, then change sign\n\t\t\texponent = normalize(absMinValue)[1];\n\t\t\tlet posIntervals = getPositiveFirstIntervals(absMinValue, maxValue);\n\t\t\tintervals = posIntervals.map(d => d * (-1));\n\t\t}\n\n\t}\n\n\t// CASE III: Both non-positive\n\n\telse if(maxValue <= 0 && minValue <= 0) {\n\t\t// Mirrored Case I:\n\t\t// Work with positives, then reverse the sign and array\n\n\t\tlet pseudoMaxValue = Math.abs(minValue);\n\t\tlet pseudoMinValue = Math.abs(maxValue);\n\n\t\texponent = normalize(pseudoMaxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);\n\t\t}\n\n\t\tintervals = intervals.reverse().map(d => d * (-1));\n\t}\n\n\treturn intervals;\n}\n\nfunction getZeroIndex(yPts) {\n\tlet zeroIndex;\n\tlet interval = getIntervalSize(yPts);\n\tif(yPts.indexOf(0) >= 0) {\n\t\t// the range has a given zero\n\t\t// zero-line on the chart\n\t\tzeroIndex = yPts.indexOf(0);\n\t} else if(yPts[0] > 0) {\n\t\t// Minimum value is positive\n\t\t// zero-line is off the chart: below\n\t\tlet min = yPts[0];\n\t\tzeroIndex = (-1) * min / interval;\n\t} else {\n\t\t// Maximum value is negative\n\t\t// zero-line is off the chart: above\n\t\tlet max = yPts[yPts.length - 1];\n\t\tzeroIndex = (-1) * max / interval + (yPts.length - 1);\n\t}\n\treturn zeroIndex;\n}\n\n\n\nfunction getIntervalSize(orderedArray) {\n\treturn orderedArray[1] - orderedArray[0];\n}\n\nfunction getValueRange(orderedArray) {\n\treturn orderedArray[orderedArray.length-1] - orderedArray[0];\n}\n\nfunction scale(val, yAxis) {\n\treturn floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier);\n}\n\n\n\n\n\nfunction getClosestInArray(goal, arr, index = false) {\n\tlet closest = arr.reduce(function(prev, curr) {\n\t\treturn (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);\n\t});\n\n\treturn index ? arr.indexOf(closest) : closest;\n}\n\nfunction calcDistribution(values, distributionSize) {\n\t// Assume non-negative values,\n\t// implying distribution minimum at zero\n\n\tlet dataMaxValue = Math.max(...values);\n\n\tlet distributionStep = 1 / (distributionSize - 1);\n\tlet distribution = [];\n\n\tfor(var i = 0; i < distributionSize; i++) {\n\t\tlet checkpoint = dataMaxValue * (distributionStep * i);\n\t\tdistribution.push(checkpoint);\n\t}\n\n\treturn distribution;\n}\n\nfunction getMaxCheckpoint(value, distribution) {\n\treturn distribution.filter(d => d < value).length;\n}\n\nconst COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;\nconst ROW_HEIGHT = COL_WIDTH;\n// const DAY_INCR = 1;\n\nclass Heatmap extends BaseChart {\n\tconstructor(parent, options) {\n\t\tsuper(parent, options);\n\t\tthis.type = 'heatmap';\n\n\t\tthis.countLabel = options.countLabel || '';\n\n\t\tlet validStarts = ['Sunday', 'Monday'];\n\t\tlet startSubDomain = validStarts.includes(options.startSubDomain)\n\t\t\t? options.startSubDomain : 'Sunday';\n\t\tthis.startSubDomainIndex = validStarts.indexOf(startSubDomain);\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.discreteDomains = options.discreteDomains === 0 ? 0 : 1;\n\n\t\tm.paddings.top = ROW_HEIGHT * 3;\n\t\tm.paddings.bottom = 0;\n\t\tm.legendHeight = ROW_HEIGHT * 2;\n\t\tm.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK\n\t\t\t+ getExtraHeight(m);\n\n\t\tlet d = this.data;\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tthis.independentWidth = (getWeeksBetween(d.start, d.end)\n\t\t\t+ spacing) * COL_WIDTH + getExtraWidth(m);\n\t}\n\n\tupdateWidth() {\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tlet noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52;\n\t\tthis.baseWidth = (noOfWeeks + spacing) * COL_WIDTH\n\t\t\t+ getExtraWidth(this.measures);\n\t}\n\n\tprepareData(data=this.data) {\n\t\tif(data.start && data.end && data.start > data.end) {\n\t\t\tthrow new Error('Start date cannot be greater than end date.');\n\t\t}\n\n\t\tif(!data.start) {\n\t\t\tdata.start = new Date();\n\t\t\tdata.start.setFullYear( data.start.getFullYear() - 1 );\n\t\t}\n\t\tif(!data.end) { data.end = new Date(); }\n\t\tdata.dataPoints = data.dataPoints || {};\n\n\t\tif(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {\n\t\t\tlet points = {};\n\t\t\tObject.keys(data.dataPoints).forEach(timestampSec$$1 => {\n\t\t\t\tlet date = new Date(timestampSec$$1 * NO_OF_MILLIS);\n\t\t\t\tpoints[getYyyyMmDd(date)] = data.dataPoints[timestampSec$$1];\n\t\t\t});\n\t\t\tdata.dataPoints = points;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\n\t\ts.start = clone(this.data.start);\n\t\ts.end = clone(this.data.end);\n\n\t\ts.firstWeekStart = clone(s.start);\n\t\ts.noOfWeeks = getWeeksBetween(s.start, s.end);\n\t\ts.distribution = calcDistribution(\n\t\t\tObject.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE);\n\n\t\ts.domainConfigs = this.getDomains();\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\t\tlet lessCol = this.discreteDomains ? 0 : 1;\n\n\t\tlet componentConfigs = s.domainConfigs.map((config, i) => [\n\t\t\t'heatDomain',\n\t\t\t{\n\t\t\t\tindex: config.index,\n\t\t\t\tcolWidth: COL_WIDTH,\n\t\t\t\trowHeight: ROW_HEIGHT,\n\t\t\t\tsquareSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\txTranslate: s.domainConfigs\n\t\t\t\t\t.filter((config, j) => j < i)\n\t\t\t\t\t.map(config => config.cols.length - lessCol)\n\t\t\t\t\t.reduce((a, b) => a + b, 0)\n\t\t\t\t\t* COL_WIDTH\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\treturn s.domainConfigs[i];\n\t\t\t}.bind(this)\n\n\t\t]);\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map((args, i) => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0] + '-' + i, component];\n\t\t\t})\n\t\t);\n\n\t\tlet y = 0;\n\t\tDAY_NAMES_SHORT.forEach((dayName, i) => {\n\t\t\tif([1, 3, 5].includes(i)) {\n\t\t\t\tlet dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,\n\t\t\t\t\t{\n\t\t\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\t\t\tdy: 8,\n\t\t\t\t\t\ttextAnchor: 'end'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.drawArea.appendChild(dayText);\n\t\t\t}\n\t\t\ty += ROW_HEIGHT;\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\n\t\tthis.data = this.prepareData(data);\n\t\tthis.draw();\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tthis.components.forEach(comp => {\n\t\t\t\tlet daySquares = comp.store;\n\t\t\t\tlet daySquare = e.target;\n\t\t\t\tif(daySquares.includes(daySquare)) {\n\n\t\t\t\t\tlet count = daySquare.getAttribute('data-value');\n\t\t\t\t\tlet dateParts = daySquare.getAttribute('data-date').split('-');\n\n\t\t\t\t\tlet month = getMonthName(parseInt(dateParts[1])-1, true);\n\n\t\t\t\t\tlet gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();\n\n\t\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\t\tlet x = pOff.left - gOff.left + width/2;\n\t\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\t\tlet value = count + ' ' + this.countLabel;\n\t\t\t\t\tlet name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];\n\n\t\t\t\t\tthis.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);\n\t\t\t\t\tthis.tip.showTip();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\trenderLegend() {\n\t\tthis.legendArea.textContent = '';\n\t\tlet x = 0;\n\t\tlet y = ROW_HEIGHT;\n\n\t\tlet lessText = makeText('subdomain-name', x, y, 'Less',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tx = (COL_WIDTH * 2) + COL_WIDTH/2;\n\t\tthis.legendArea.appendChild(lessText);\n\n\t\tthis.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {\n\t\t\tconst square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i,\n\t\t\t\ty, HEATMAP_SQUARE_SIZE, color);\n\t\t\tthis.legendArea.appendChild(square);\n\t\t});\n\n\t\tlet moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;\n\t\tlet moreText = makeText('subdomain-name', moreTextX, y, 'More',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tthis.legendArea.appendChild(moreText);\n\t}\n\n\tgetDomains() {\n\t\tlet s = this.state;\n\t\tconst [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()];\n\t\tconst [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()];\n\n\t\tconst noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12;\n\n\t\tlet domainConfigs = [];\n\n\t\tlet startOfMonth = clone(s.start);\n\t\tfor(var i = 0; i < noOfMonths; i++) {\n\t\t\tlet endDate = s.end;\n\t\t\tif(!areInSameMonth(startOfMonth, s.end)) {\n\t\t\t\tlet [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];\n\t\t\t\tendDate = getLastDateInMonth(month, year);\n\t\t\t}\n\t\t\tdomainConfigs.push(this.getDomainConfig(startOfMonth, endDate));\n\n\t\t\taddDays(endDate, 1);\n\t\t\tstartOfMonth = endDate;\n\t\t}\n\n\t\treturn domainConfigs;\n\t}\n\n\tgetDomainConfig(startDate, endDate='') {\n\t\tlet [month, year] = [startDate.getMonth(), startDate.getFullYear()];\n\t\tlet startOfWeek = setDayToSunday(startDate); // TODO: Monday as well\n\t\tendDate = clone(endDate) || getLastDateInMonth(month, year);\n\n\t\tlet domainConfig = {\n\t\t\tindex: month,\n\t\t\tcols: []\n\t\t};\n\n\t\taddDays(endDate, 1);\n\t\tlet noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);\n\n\t\tlet cols = [], col;\n\t\tfor(var i = 0; i < noOfMonthWeeks; i++) {\n\t\t\tcol = this.getCol(startOfWeek, month);\n\t\t\tcols.push(col);\n\n\t\t\tstartOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);\n\t\t\taddDays(startOfWeek, 1);\n\t\t}\n\n\t\tif(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {\n\t\t\taddDays(startOfWeek, 1);\n\t\t\tcols.push(this.getCol(startOfWeek, month, true));\n\t\t}\n\n\t\tdomainConfig.cols = cols;\n\n\t\treturn domainConfig;\n\t}\n\n\tgetCol(startDate, month, empty = false) {\n\t\tlet s = this.state;\n\n\t\t// startDate is the start of week\n\t\tlet currentDate = clone(startDate);\n\t\tlet col = [];\n\n\t\tfor(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {\n\t\t\tlet config = {};\n\n\t\t\t// Non-generic adjustment for entire heatmap, needs state\n\t\t\tlet currentDateWithinData = currentDate >= s.start && currentDate <= s.end;\n\n\t\t\tif(empty || currentDate.getMonth() !== month || !currentDateWithinData) {\n\t\t\t\tconfig.yyyyMmDd = getYyyyMmDd(currentDate);\n\t\t\t} else {\n\t\t\t\tconfig = this.getSubDomainConfig(currentDate);\n\t\t\t}\n\t\t\tcol.push(config);\n\t\t}\n\n\t\treturn col;\n\t}\n\n\tgetSubDomainConfig(date) {\n\t\tlet yyyyMmDd = getYyyyMmDd(date);\n\t\tlet dataValue = this.data.dataPoints[yyyyMmDd];\n\t\tlet config = {\n\t\t\tyyyyMmDd: yyyyMmDd,\n\t\t\tdataValue: dataValue || 0,\n\t\t\tfill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]\n\t\t};\n\t\treturn config;\n\t}\n}\n\nfunction dataPrep(data, type) {\n\tdata.labels = data.labels || [];\n\n\tlet datasetLength = data.labels.length;\n\n\t// Datasets\n\tlet datasets = data.datasets;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\tif(!datasets) {\n\t\t// default\n\t\tdatasets = [{\n\t\t\tvalues: zeroArray\n\t\t}];\n\t}\n\n\tdatasets.map(d=> {\n\t\t// Set values\n\t\tif(!d.values) {\n\t\t\td.values = zeroArray;\n\t\t} else {\n\t\t\t// Check for non values\n\t\t\tlet vals = d.values;\n\t\t\tvals = vals.map(val => (!isNaN(val) ? val : 0));\n\n\t\t\t// Trim or extend\n\t\t\tif(vals.length > datasetLength) {\n\t\t\t\tvals = vals.slice(0, datasetLength);\n\t\t\t} else {\n\t\t\t\tvals = fillArray(vals, datasetLength - vals.length, 0);\n\t\t\t}\n\t\t}\n\n\t\t// Set labels\n\t\t//\n\n\t\t// Set type\n\t\tif(!d.chartType ) {\n\t\t\tif(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;\n\t\t\td.chartType = type;\n\t\t}\n\n\t});\n\n\t// Markers\n\n\t// Regions\n\t// data.yRegions = data.yRegions || [];\n\tif(data.yRegions) {\n\t\tdata.yRegions.map(d => {\n\t\t\tif(d.end < d.start) {\n\t\t\t\t[d.start, d.end] = [d.end, d.start];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn data;\n}\n\nfunction zeroDataPrep(realData) {\n\tlet datasetLength = realData.labels.length;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\n\tlet zeroData = {\n\t\tlabels: realData.labels.slice(0, -1),\n\t\tdatasets: realData.datasets.map(d => {\n\t\t\treturn {\n\t\t\t\tname: '',\n\t\t\t\tvalues: zeroArray.slice(0, -1),\n\t\t\t\tchartType: d.chartType\n\t\t\t};\n\t\t}),\n\t};\n\n\tif(realData.yMarkers) {\n\t\tzeroData.yMarkers = [\n\t\t\t{\n\t\t\t\tvalue: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\tif(realData.yRegions) {\n\t\tzeroData.yRegions = [\n\t\t\t{\n\t\t\t\tstart: 0,\n\t\t\t\tend: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\treturn zeroData;\n}\n\nfunction getShortenedLabels(chartWidth, labels=[], isSeries=true) {\n\tlet allowedSpace = chartWidth / labels.length;\n\tif(allowedSpace <= 0) allowedSpace = 1;\n\tlet allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;\n\n\tlet calcLabels = labels.map((label, i) => {\n\t\tlabel += \"\";\n\t\tif(label.length > allowedLetters) {\n\n\t\t\tif(!isSeries) {\n\t\t\t\tif(allowedLetters-3 > 0) {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters-3) + \" ...\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters) + '..';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlet multiple = Math.ceil(label.length/allowedLetters);\n\t\t\t\tif(i % multiple !== 0) {\n\t\t\t\t\tlabel = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn label;\n\t});\n\n\treturn calcLabels;\n}\n\nclass AxisChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\n\t\tthis.barOptions = args.barOptions || {};\n\t\tthis.lineOptions = args.lineOptions || {};\n\n\t\tthis.type = args.type || 'line';\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures() {\n\t\tif(this.data.datasets.length <= 1) {\n\t\t\tthis.config.showLegend = 0;\n\t\t\tthis.measures.paddings.bottom = 30;\n\t\t}\n\t}\n\n\tconfigure(options) {\n\t\tsuper.configure(options);\n\n\t\toptions.axisOptions = options.axisOptions || {};\n\t\toptions.tooltipOptions = options.tooltipOptions || {};\n\n\t\tthis.config.xAxisMode = options.axisOptions.xAxisMode || 'span';\n\t\tthis.config.yAxisMode = options.axisOptions.yAxisMode || 'span';\n\t\tthis.config.xIsSeries = options.axisOptions.xIsSeries || 0;\n\n\t\tthis.config.formatTooltipX = options.tooltipOptions.formatTooltipX;\n\t\tthis.config.formatTooltipY = options.tooltipOptions.formatTooltipY;\n\n\t\tthis.config.valuesOverPoints = options.valuesOverPoints;\n\t}\n\n\tprepareData(data=this.data) {\n\t\treturn dataPrep(data, this.type);\n\t}\n\n\tprepareFirstData(data=this.data) {\n\t\treturn zeroDataPrep(data);\n\t}\n\n\tcalc(onlyWidthChange = false) {\n\t\tthis.calcXPositions();\n\t\tif(!onlyWidthChange) {\n\t\t\tthis.calcYAxisParameters(this.getAllYValues(), this.type === 'line');\n\t\t}\n\t\tthis.makeDataByIndex();\n\t}\n\n\tcalcXPositions() {\n\t\tlet s = this.state;\n\t\tlet labels = this.data.labels;\n\t\ts.datasetLength = labels.length;\n\n\t\ts.unitWidth = this.width/(s.datasetLength);\n\t\t// Default, as per bar, and mixed. Only line will be a special case\n\t\ts.xOffset = s.unitWidth/2;\n\n\t\t// // For a pure Line Chart\n\t\t// s.unitWidth = this.width/(s.datasetLength - 1);\n\t\t// s.xOffset = 0;\n\n\t\ts.xAxis = {\n\t\t\tlabels: labels,\n\t\t\tpositions: labels.map((d, i) =>\n\t\t\t\tfloatTwo(s.xOffset + i * s.unitWidth)\n\t\t\t)\n\t\t};\n\t}\n\n\tcalcYAxisParameters(dataValues, withMinimum = 'false') {\n\t\tconst yPts = calcChartIntervals(dataValues, withMinimum);\n\t\tconst scaleMultiplier = this.height / getValueRange(yPts);\n\t\tconst intervalHeight = getIntervalSize(yPts) * scaleMultiplier;\n\t\tconst zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);\n\n\t\tthis.state.yAxis = {\n\t\t\tlabels: yPts,\n\t\t\tpositions: yPts.map(d => zeroLine - d * scaleMultiplier),\n\t\t\tscaleMultiplier: scaleMultiplier,\n\t\t\tzeroLine: zeroLine,\n\t\t};\n\n\t\t// Dependent if above changes\n\t\tthis.calcDatasetPoints();\n\t\tthis.calcYExtremes();\n\t\tthis.calcYRegions();\n\t}\n\n\tcalcDatasetPoints() {\n\t\tlet s = this.state;\n\t\tlet scaleAll = values => values.map(val => scale(val, s.yAxis));\n\n\t\ts.datasets = this.data.datasets.map((d, i) => {\n\t\t\tlet values = d.values;\n\t\t\tlet cumulativeYs = d.cumulativeYs || [];\n\t\t\treturn {\n\t\t\t\tname: d.name,\n\t\t\t\tindex: i,\n\t\t\t\tchartType: d.chartType,\n\n\t\t\t\tvalues: values,\n\t\t\t\tyPositions: scaleAll(values),\n\n\t\t\t\tcumulativeYs: cumulativeYs,\n\t\t\t\tcumulativeYPos: scaleAll(cumulativeYs),\n\t\t\t};\n\t\t});\n\t}\n\n\tcalcYExtremes() {\n\t\tlet s = this.state;\n\t\tif(this.barOptions.stacked) {\n\t\t\ts.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;\n\t\t\treturn;\n\t\t}\n\t\ts.yExtremes = new Array(s.datasetLength).fill(9999);\n\t\ts.datasets.map(d => {\n\t\t\td.yPositions.map((pos, j) => {\n\t\t\t\tif(pos < s.yExtremes[j]) {\n\t\t\t\t\ts.yExtremes[j] = pos;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tcalcYRegions() {\n\t\tlet s = this.state;\n\t\tif(this.data.yMarkers) {\n\t\t\tthis.state.yMarkers = this.data.yMarkers.map(d => {\n\t\t\t\td.position = scale(d.value, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\t// if(!d.label.includes(':')) {\n\t\t\t\t// \td.label += ': ' + d.value;\n\t\t\t\t// }\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.state.yRegions = this.data.yRegions.map(d => {\n\t\t\t\td.startPos = scale(d.start, s.yAxis);\n\t\t\t\td.endPos = scale(d.end, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t}\n\n\tgetAllYValues() {\n\t\tlet key = 'values';\n\n\t\tif(this.barOptions.stacked) {\n\t\t\tkey = 'cumulativeYs';\n\t\t\tlet cumulative = new Array(this.state.datasetLength).fill(0);\n\t\t\tthis.data.datasets.map((d, i) => {\n\t\t\t\tlet values = this.data.datasets[i].values;\n\t\t\t\td[key] = cumulative = cumulative.map((c, i) => c + values[i]);\n\t\t\t});\n\t\t}\n\n\t\tlet allValueLists = this.data.datasets.map(d => d[key]);\n\t\tif(this.data.yMarkers) {\n\t\t\tallValueLists.push(this.data.yMarkers.map(d => d.value));\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.data.yRegions.map(d => {\n\t\t\t\tallValueLists.push([d.end, d.start]);\n\t\t\t});\n\t\t}\n\n\t\treturn [].concat(...allValueLists);\n\t}\n\n\tsetupComponents() {\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'yAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.yAxisMode,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'xAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.xAxisMode,\n\t\t\t\t\theight: this.height,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\ts.xAxis.calcLabels = getShortenedLabels(this.width,\n\t\t\t\t\t\ts.xAxis.labels, this.config.xIsSeries);\n\n\t\t\t\t\treturn s.xAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'yRegions',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yRegions;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\t\t];\n\n\t\tlet barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');\n\t\tlet lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');\n\n\t\tlet barsConfigs = barDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'barGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tstacked: this.barOptions.stacked,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t\tminHeight: this.height * MIN_BAR_PERCENT_HEIGHT,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet stacked = this.barOptions.stacked;\n\n\t\t\t\t\tlet spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;\n\t\t\t\t\tlet barsWidth = s.unitWidth * (1 - spaceRatio);\n\t\t\t\t\tlet barWidth = barsWidth/(stacked ? 1 : barDatasets.length);\n\n\t\t\t\t\tlet xPositions = s.xAxis.positions.map(x => x - barsWidth/2);\n\t\t\t\t\tif(!stacked) {\n\t\t\t\t\t\txPositions = xPositions.map(p => p + barWidth * index);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet labels = new Array(s.datasetLength).fill('');\n\t\t\t\t\tif(this.config.valuesOverPoints) {\n\t\t\t\t\t\tif(stacked && d.index === s.datasets.length - 1) {\n\t\t\t\t\t\t\tlabels = d.cumulativeYs;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabels = d.values;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet offsets = new Array(s.datasetLength).fill(0);\n\t\t\t\t\tif(stacked) {\n\t\t\t\t\t\toffsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: xPositions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\t\t\t\t\t\toffsets: offsets,\n\t\t\t\t\t\t// values: d.values,\n\t\t\t\t\t\tlabels: labels,\n\n\t\t\t\t\t\tzeroLine: s.yAxis.zeroLine,\n\t\t\t\t\t\tbarsWidth: barsWidth,\n\t\t\t\t\t\tbarWidth: barWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet lineConfigs = lineDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'lineGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tsvgDefs: this.svgDefs,\n\t\t\t\t\theatline: this.lineOptions.heatline,\n\t\t\t\t\tregionFill: this.lineOptions.regionFill,\n\t\t\t\t\thideDots: this.lineOptions.hideDots,\n\t\t\t\t\thideLine: this.lineOptions.hideLine,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet minLine = s.yAxis.positions[0] < s.yAxis.zeroLine\n\t\t\t\t\t\t? s.yAxis.positions[0] : s.yAxis.zeroLine;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xAxis.positions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\n\t\t\t\t\t\tvalues: d.values,\n\n\t\t\t\t\t\tzeroLine: minLine,\n\t\t\t\t\t\tradius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet markerConfigs = [\n\t\t\t[\n\t\t\t\t'yMarkers',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yMarkers;\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tcomponentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);\n\n\t\tlet optionals = ['yMarkers', 'yRegions'];\n\t\tthis.dataUnitComponents = [];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.filter(args => !optionals.includes(args[0]) || this.state[args[0]])\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\tif(args[0].includes('lineGraph') || args[0].includes('barGraph')) {\n\t\t\t\t\tthis.dataUnitComponents.push(component);\n\t\t\t\t}\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tmakeDataByIndex() {\n\t\tthis.dataByIndex = {};\n\n\t\tlet s = this.state;\n\t\tlet formatX = this.config.formatTooltipX;\n\t\tlet formatY = this.config.formatTooltipY;\n\t\tlet titles = s.xAxis.labels;\n\n\t\ttitles.map((label, index) => {\n\t\t\tlet values = this.state.datasets.map((set, i) => {\n\t\t\t\tlet value = set.values[index];\n\t\t\t\treturn {\n\t\t\t\t\ttitle: set.name,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tyPos: set.yPositions[index],\n\t\t\t\t\tcolor: this.colors[i],\n\t\t\t\t\tformatted: formatY ? formatY(value) : value,\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tthis.dataByIndex[index] = {\n\t\t\t\tlabel: label,\n\t\t\t\tformattedLabel: formatX ? formatX(label) : label,\n\t\t\t\txPos: s.xAxis.positions[index],\n\t\t\t\tvalues: values,\n\t\t\t\tyExtreme: s.yExtremes[index],\n\t\t\t};\n\t\t});\n\t}\n\n\tbindTooltip() {\n\t\t// NOTE: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet m = this.measures;\n\t\t\tlet o = getOffset(this.container);\n\t\t\tlet relX = e.pageX - o.left - getLeftOffset(m);\n\t\t\tlet relY = e.pageY - o.top;\n\n\t\t\tif(relY < this.height + getTopOffset(m)\n\t\t\t\t&& relY > getTopOffset(m)) {\n\t\t\t\tthis.mapTooltipXPosition(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hideTip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmapTooltipXPosition(relX) {\n\t\tlet s = this.state;\n\t\tif(!s.yExtremes) return;\n\n\t\tlet index = getClosestInArray(relX, s.xAxis.positions, true);\n\t\tlet dbi = this.dataByIndex[index];\n\n\t\tthis.tip.setValues(\n\t\t\tdbi.xPos + this.tip.offset.x,\n\t\t\tdbi.yExtreme + this.tip.offset.y,\n\t\t\t{name: dbi.formattedLabel, value: ''},\n\t\t\tdbi.values,\n\t\t\tindex\n\t\t);\n\n\t\tthis.tip.showTip();\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.data;\n\t\tif(s.datasets.length > 1) {\n\t\t\tthis.legendArea.textContent = '';\n\t\t\ts.datasets.map((d, i) => {\n\t\t\t\tlet barWidth = AXIS_LEGEND_BAR_SIZE;\n\t\t\t\t// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;\n\t\t\t\t// let multiplier = s.datasets.length - i;\n\t\t\t\tlet rect = legendBar(\n\t\t\t\t\t// rightEndPoint - multiplier * barWidth,\t// To right align\n\t\t\t\t\tbarWidth * i,\n\t\t\t\t\t'0',\n\t\t\t\t\tbarWidth,\n\t\t\t\t\tthis.colors[i],\n\t\t\t\t\td.name);\n\t\t\t\tthis.legendArea.appendChild(rect);\n\t\t\t});\n\t\t}\n\t}\n\n\n\n\t// Overlay\n\tmakeOverlay() {\n\t\tif(this.init) {\n\t\t\tthis.init = 0;\n\t\t\treturn;\n\t\t}\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\n\t\tthis.overlayGuides = this.dataUnitComponents.map(c => {\n\t\t\treturn {\n\t\t\t\ttype: c.unitType,\n\t\t\t\toverlay: undefined,\n\t\t\t\tunits: c.units,\n\t\t\t};\n\t\t});\n\n\t\tif(this.state.currentIndex === undefined) {\n\t\t\tthis.state.currentIndex = this.state.datasetLength - 1;\n\t\t}\n\n\t\t// Render overlays\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\n\t\t\td.overlay = makeOverlay[d.type](currentUnit);\n\t\t\tthis.drawArea.appendChild(d.overlay);\n\t\t});\n\t}\n\n\tupdateOverlayGuides() {\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\t}\n\n\tbindOverlay() {\n\t\tthis.parent.addEventListener('data-select', () => {\n\t\t\tthis.updateOverlay();\n\t\t});\n\t}\n\n\tbindUnits() {\n\t\tthis.dataUnitComponents.map(c => {\n\t\t\tc.units.map(unit => {\n\t\t\t\tunit.addEventListener('click', () => {\n\t\t\t\t\tlet index = unit.getAttribute('data-point-index');\n\t\t\t\t\tthis.setCurrentDataPoint(index);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\t// Note: Doesn't work as tooltip is absolutely positioned\n\t\tthis.tip.container.addEventListener('click', () => {\n\t\t\tlet index = this.tip.container.getAttribute('data-point-index');\n\t\t\tthis.setCurrentDataPoint(index);\n\t\t});\n\t}\n\n\tupdateOverlay() {\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\t\t\tupdateOverlay[d.type](currentUnit, d.overlay);\n\t\t});\n\t}\n\n\tonLeftArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex - 1);\n\t}\n\n\tonRightArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex + 1);\n\t}\n\n\tgetDataPoint(index=this.state.currentIndex) {\n\t\tlet s = this.state;\n\t\tlet data_point = {\n\t\t\tindex: index,\n\t\t\tlabel: s.xAxis.labels[index],\n\t\t\tvalues: s.datasets.map(d => d.values[index])\n\t\t};\n\t\treturn data_point;\n\t}\n\n\tsetCurrentDataPoint(index) {\n\t\tlet s = this.state;\n\t\tindex = parseInt(index);\n\t\tif(index < 0) index = 0;\n\t\tif(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;\n\t\tif(index === s.currentIndex) return;\n\t\ts.currentIndex = index;\n\t\tfire(this.parent, \"data-select\", this.getDataPoint());\n\t}\n\n\n\n\t// API\n\taddDataPoint(label, datasetValues, index=this.state.datasetLength) {\n\t\tsuper.addDataPoint(label, datasetValues, index);\n\t\tthis.data.labels.splice(index, 0, label);\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\td.values.splice(index, 0, datasetValues[i]);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tremoveDataPoint(index = this.state.datasetLength-1) {\n\t\tif (this.data.labels.length <= 1) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.removeDataPoint(index);\n\t\tthis.data.labels.splice(index, 1);\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values.splice(index, 1);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tupdateDataset(datasetValues, index=0) {\n\t\tthis.data.datasets[index].values = datasetValues;\n\t\tthis.update(this.data);\n\t}\n\t// addDataset(dataset, index) {}\n\t// removeDataset(index = 0) {}\n\n\tupdateDatasets(datasets) {\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\tif(datasets[i]) {\n\t\t\t\td.values = datasets[i];\n\t\t\t}\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\t// updateDataPoint(dataPoint, index = 0) {}\n\t// addDataPoint(dataPoint, index = 0) {}\n\t// removeDataPoint(index = 0) {}\n}\n\nconst chartTypes = {\n\tbar: AxisChart,\n\tline: AxisChart,\n\t// multiaxis: MultiAxisChart,\n\tpercentage: PercentageChart,\n\theatmap: Heatmap,\n\tpie: PieChart\n};\n\nfunction getChartByType(chartType = 'line', parent, options) {\n\tif (chartType === 'axis-mixed') {\n\t\toptions.type = 'line';\n\t\treturn new AxisChart(parent, options);\n\t}\n\n\tif (!chartTypes[chartType]) {\n\t\tconsole.error(\"Undefined chart type: \" + chartType);\n\t\treturn;\n\t}\n\n\treturn new chartTypes[chartType](parent, options);\n}\n\nclass Chart {\n\tconstructor(parent, options) {\n\t\treturn getChartByType(options.type, parent, options);\n\t}\n}\n\nexport { Chart, PercentageChart, PieChart, Heatmap, AxisChart };\n","/*\n * This file is part of Flarum.\n *\n * (c) Toby Zerner \n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport DashboardWidget from 'flarum/components/DashboardWidget';\nimport SelectDropdown from 'flarum/components/SelectDropdown';\nimport Button from 'flarum/components/Button';\nimport icon from 'flarum/helpers/icon';\nimport abbreviateNumber from 'flarum/utils/abbreviateNumber';\n\nimport { Chart } from 'frappe-charts/dist/frappe-charts.esm.js';\n\nexport default class StatisticsWidget extends DashboardWidget {\n init() {\n super.init();\n\n // Create a Date object which represents the start of the day in the\n // configured timezone. To do this we convert a UTC time into that timezone,\n // reset to the first hour of the day, and then convert back into UTC time.\n // We'll be working with seconds rather than milliseconds throughout too.\n let today = new Date();\n today.setTime(today.getTime() + app.data.statistics.timezoneOffset * 1000);\n today.setUTCHours(0, 0, 0, 0);\n today.setTime(today.getTime() - app.data.statistics.timezoneOffset * 1000);\n today = today / 1000;\n\n this.entities = ['users', 'discussions', 'posts'];\n this.periods = {\n today: {start: today, end: today + 86400, step: 3600},\n last_7_days: {start: today - 86400 * 7, end: today, step: 86400},\n last_28_days: {start: today - 86400 * 28, end: today, step: 86400},\n last_12_months: {start: today - 86400 * 364, end: today, step: 86400 * 7}\n };\n\n this.selectedEntity = 'users';\n this.selectedPeriod = 'last_7_days';\n }\n\n className() {\n return 'StatisticsWidget';\n }\n\n content() {\n const thisPeriod = this.periods[this.selectedPeriod];\n\n return (\n
      \n
      \n
      {app.translator.trans('flarum-statistics.admin.statistics.total_label')}
      \n
      \n \n {Object.keys(this.periods).map(period => (\n \n {app.translator.trans(`flarum-statistics.admin.statistics.${period}_label`)}\n \n ))}\n \n
      \n
      \n\n {this.entities.map(entity => {\n const totalCount = this.getTotalCount(entity);\n const thisPeriodCount = this.getPeriodCount(entity, thisPeriod);\n const lastPeriodCount = this.getPeriodCount(entity, this.getLastPeriod(thisPeriod));\n const periodChange = lastPeriodCount > 0 && (thisPeriodCount - lastPeriodCount) / lastPeriodCount * 100;\n\n return (\n \n

      {app.translator.trans('flarum-statistics.admin.statistics.'+entity+'_heading')}

      \n
      {abbreviateNumber(totalCount)}
      \n
      \n {abbreviateNumber(thisPeriodCount)}{' '}\n {periodChange ? (\n 0 ? 'up' : 'down')}>\n {icon('fas fa-arrow-'+(periodChange > 0 ? 'up' : 'down'))}\n {Math.abs(periodChange.toFixed(1))}%\n \n ) : ''}\n
      \n
      \n );\n })}\n\n
      \n
      \n );\n }\n\n drawChart(elm, isInitialized, context) {\n if (context.chart && context.entity === this.selectedEntity && context.period === this.selectedPeriod) {\n return;\n }\n\n const offset = app.data.statistics.timezoneOffset;\n const period = this.periods[this.selectedPeriod];\n const periodLength = period.end - period.start;\n const labels = [];\n const thisPeriod = [];\n const lastPeriod = [];\n\n for (let i = period.start; i < period.end; i += period.step) {\n let label;\n\n if (period.step < 86400) {\n label = dayjs.unix(i + offset).format('h A');\n } else {\n label = dayjs.unix(i + offset).format('D MMM');\n\n if (period.step > 86400) {\n label += ' - ' + dayjs.unix(i + offset + period.step - 1).format('D MMM');\n }\n }\n\n labels.push(label);\n\n thisPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i, end: i + period.step}));\n\n lastPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i - periodLength, end: i - periodLength + period.step}));\n }\n\n const datasets = [\n {values: lastPeriod},\n {values: thisPeriod}\n ];\n const data = {\n labels,\n datasets\n };\n\n if (!context.chart) {\n context.chart = new Chart(elm, {\n data,\n type: 'line',\n height: 280,\n axisOptions: {\n xAxisMode: 'tick',\n yAxisMode: 'span',\n xIsSeries: true\n },\n lineOptions: {\n hideDots: 1\n },\n colors: ['black', app.forum.attribute('themePrimaryColor')]\n });\n } else {\n context.chart.update(data);\n }\n\n context.entity = this.selectedEntity;\n context.period = this.selectedPeriod;\n }\n\n changeEntity(entity) {\n this.selectedEntity = entity;\n }\n\n changePeriod(period) {\n this.selectedPeriod = period;\n }\n\n getTotalCount(entity) {\n return app.data.statistics[entity].total;\n }\n\n getPeriodCount(entity, period) {\n const timed = app.data.statistics[entity].timed;\n let count = 0;\n\n for (const time in timed) {\n if (time >= period.start && time < period.end) {\n count += timed[time];\n }\n }\n\n return count;\n }\n\n getLastPeriod(thisPeriod) {\n return {\n start: thisPeriod.start - (thisPeriod.end - thisPeriod.start),\n end: thisPeriod.start\n };\n }\n}\n","export default function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n subClass.__proto__ = superClass;\n}","import app from 'flarum/app';\nimport { extend } from 'flarum/extend';\n\nimport DashboardPage from 'flarum/components/DashboardPage';\n\nimport StatisticsWidget from './components/StatisticsWidget';\n\napp.initializers.add('flarum-statistics', () => {\n extend(DashboardPage.prototype, 'availableWidgets', widgets => {\n widgets.push();\n });\n});\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://@flarum/statistics/webpack/bootstrap","webpack://@flarum/statistics/external \"flarum.core.compat['utils/abbreviateNumber']\"","webpack://@flarum/statistics/external \"flarum.core.compat['app']\"","webpack://@flarum/statistics/external \"flarum.core.compat['extend']\"","webpack://@flarum/statistics/external \"flarum.core.compat['components/DashboardPage']\"","webpack://@flarum/statistics/external \"flarum.core.compat['components/DashboardWidget']\"","webpack://@flarum/statistics/external \"flarum.core.compat['components/SelectDropdown']\"","webpack://@flarum/statistics/external \"flarum.core.compat['components/Button']\"","webpack://@flarum/statistics/external \"flarum.core.compat['helpers/icon']\"","webpack://@flarum/statistics/./node_modules/frappe-charts/dist/frappe-charts.esm.js","webpack://@flarum/statistics/./src/admin/components/StatisticsWidget.js","webpack://@flarum/statistics/./node_modules/@babel/runtime/helpers/esm/inheritsLoose.js","webpack://@flarum/statistics/./src/admin/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","flarum","core","compat","$","expr","con","document","querySelector","getOffset","element","rect","getBoundingClientRect","top","documentElement","scrollTop","body","left","scrollLeft","tag","createElement","val","appendChild","ref","parentNode","insertBefore","keys","map","prop","style","setAttribute","BASE_MEASURES","margins","bottom","right","paddings","baseHeight","titleHeight","legendHeight","titleFontSize","getTopOffset","getLeftOffset","getExtraHeight","getExtraWidth","AXIS_DATASET_CHART_TYPES","DEFAULT_CHART_COLORS","DEFAULT_COLORS","bar","line","pie","percentage","heatmap","ANGLE_RATIO","Math","PI","SvgTip","parent","colors","this","titleName","titleValue","listValues","titleValueFirst","x","y","setup","makeTooltip","fill","calcPosition","container","inside","className","innerHTML","hideTip","title","dataPointList","addEventListener","index","set","color","formatted","li","styles","width","offsetWidth","offsetHeight","maxLeft","pointer","pointerOffset","valueFirst","refresh","opacity","floatTwo","parseFloat","toFixed","fillArray","array","count","start","length","fillerArray","Array","abs","concat","getStringWidth","string","charWidth","getPositionByAngle","angle","radius","sin","cos","getBarHeightAndYAttr","yTop","zeroLine","height","equilizeNoOfElements","array1","array2","extraCount","PRESET_COLOR_MAP","limitColor","lightenDarkenColor","amt","col","getColor","usePound","slice","num","parseInt","b","toString","$$1","createSVG","createElementNS","setGradientStop","gradElem","offset","makeSVGGroup","transform","args","makePath","pathStr","stroke","makeGradient","svgDefElem","lighter","gradientId","gradientDef","id","x1","x2","y1","y2","renderVerticalGradient","opacities","heatSquare","size","data","makeText","content","options","fontSize","dy","undefined","textAnchor","makeHoriLine","label","lineType","text","FONT_SIZE","xLine","pos","makeVertLine","makeOverlay","unit","transformValue","nodeName","getAttribute","childNodes","overlay","cloneNode","updateOverlay","attributes","values","filter","attr","includes","specified","nodeValue","translate","oldCoord","newCoord","duration","old","join","translateHoriLine","yLine","newY","oldY","EASING","ease","linear","easein","easeout","easeinout","webkitTransform","msTransform","mozTransform","oTransform","animateSVG","svgContainer","elements","newElements","animElements","animElement","newElement","props","dur","easingType","type","oldValues","attributeName","animateElement","currentValue","animAttr","from","to","begin","keySplines","keyTimes","calcMode","animateSVGElement","push","replaceChild","animSvg","BOUND_DRAW_FN","BaseChart","HTMLElement","Error","rawChartArgs","realData","prepareData","prepareFirstData","validateColors","config","showTooltip","showLegend","isNavigable","animate","measures","JSON","parse","stringify","setMeasures","argHeight","state","initTimeout","overlays","configure","validColors","forEach","test","isValidColor","console","warn","boundDrawFn","window","draw","removeEventListener","makeContainer","updateWidth","independentWidth","tip","bindTooltip","onlyWidthChange","init","calc","makeChartArea","setupComponents","components","drawArea","render","setTimeout","update","renderLegend","setupNavigation","padding","baseWidth","getComputedStyle","paddingLeft","paddingRight","clientWidth","svg","removeChild","svgDefs","titleEL","legendArea","updateTipOffset","Map","error","elementsToAnimate","svgElement","animSvgElement","runSMILAnimation","make","updateNav","bindUnits","bindOverlay","keyActions","onEnterKey","onLeftArrow","onUpArrow","onRightArrow","onDownArrow","e","el","innerHeight","clientHeight","innerWidth","event","keyCode","chartSvg","clone","classList","add","styleEl","firstChild","prepareForExport","filename","a","blob","Blob","url","URL","createObjectURL","href","download","click","revokeObjectURL","downloadFile","AggregationChart","super","maxSlices","maxLegendPoints","sliceTotals","allTotals","labels","total","datasets","totals","sort","remaining","sumOfRemaining","grandTotal","reduce","center","textContent","legendTotals","divisor","floor","dot","cx","cy","dx","group","legendDot","MONTH_NAMES","DAY_NAMES_SHORT","treatAsUtc","date","result","Date","setMinutes","getMinutes","getTimezoneOffset","getYyyyMmDd","dd","getDate","mm","getMonth","getFullYear","getTime","getWeeksBetween","startDate","endDate","weekStartDate","setDayToSunday","ceil","SEC_IN_DAY","getDaysBetween","areInSameMonth","getMonthName","short","monthName","getLastDateInMonth","month","year","newDate","day","getDay","addDays","numberOfDays","setDate","ChartComponent","layerClass","layerTransform","constants","getData","makeElements","animateElements","store","layer","oldData","componentConfigs","pieSlices","sliceStrings","transition","newData","animatePathStr","oldPath","percentageBars","xPositions","depth","percentageBar","widths","barHeight","barDepth","yAxis","positions","position","newPos","newLabels","oldPos","oldLabels","xAxis","calcLabels","newX","oldX","translateVertLine","yMarkers","labelPos","labelSvg","yMarker","newOptions","yRegions","region","yRegion","startPos","endPos","newStarts","oldStarts","rectGroup","newY1","newY2","oldY2","newHeight","animateRegion","heatDomain","colWidth","rowHeight","squareSize","xTranslate","serializedSubDomains","cols","week","weekNo","toUpperCase","yyyyMmDd","dataValue","square","barGraph","unitType","units","yPositions","j","meta","minHeight","datasetBar","barWidth","offsets","barsWidth","newXPos","newYPos","newOffsets","oldXPos","oldYPos","oldOffsets","rectAnim","oldCoordStr","split","animateBar","lineGraph","paths","hideLine","xList","yList","pointsStr","path","heatline","gradient_id","regionFill","gradient_id_region","getPaths","hideDots","datasetDot","valuesOverPoints","newValues","newXList","newYList","pathComponents","animPath","regStartPt","regEndPt","animRegion","animatePath","animateDot","getComponent","k","assign","normalize","isNaN","mantissa","exponent","sig","isFinite","exp","log10","pow","getChartIntervals","maxValue","minValue","normalMaxValue","normalMinValue","intervals","max","min","upperBound","lowerBound","range","noOfParts","partSize","getChartRangeIntervals","getIntervalSize","orderedArray","scale","scaleMultiplier","AxisChart","barOptions","lineOptions","axisOptions","tooltipOptions","xAxisMode","yAxisMode","xIsSeries","formatTooltipX","formatTooltipY","datasetLength","zeroArray","vals","chartType","end","dataPrep","zeroData","zeroDataPrep","calcXPositions","calcYAxisParameters","getAllYValues","makeDataByIndex","unitWidth","xOffset","dataValues","withMinimum","yPts","getPositiveFirstIntervals","absMinValue","intervalSize","unshift","pseudoMaxValue","pseudoMinValue","reverse","calcChartIntervals","intervalHeight","zeroIndex","interval","indexOf","getZeroIndex","calcDatasetPoints","calcYExtremes","calcYRegions","scaleAll","cumulativeYs","cumulativeYPos","stacked","yExtremes","cumulative","allValueLists","chartWidth","isSeries","allowedSpace","allowedLetters","getShortenedLabels","barDatasets","lineDatasets","barsConfigs","spaceRatio","lineConfigs","minLine","dotSize","markerConfigs","optionals","dataUnitComponents","component","dataByIndex","formatX","formatY","yPos","formattedLabel","xPos","yExtreme","relX","pageX","relY","pageY","mapTooltipXPosition","goal","arr","closest","prev","curr","getClosestInArray","dbi","setValues","showTip","legendBar","overlayGuides","g","currentIndex","currentUnit","setCurrentDataPoint","target","properties","evt","createEvent","initEvent","dispatchEvent","fire","getDataPoint","datasetValues","addDataPoint","splice","removeDataPoint","chartTypes","bars","gOff","pOff","formattedLabels","fraction","countLabel","validStarts","startSubDomain","startSubDomainIndex","discreteDomains","ROW_HEIGHT","spacing","HEATMAP_SQUARE_SIZE","noOfWeeks","setFullYear","dataPoints","points","timestampSec$$1","firstWeekStart","distribution","distributionSize","dataMaxValue","distributionStep","checkpoint","calcDistribution","domainConfigs","getDomains","lessCol","dayName","dayText","comp","daySquares","daySquare","dateParts","lessText","moreText","HEATMAP_DISTRIBUTION_SIZE","COL_WIDTH","startMonth","startYear","endMonth","endYear","noOfMonths","startOfMonth","getDomainConfig","startOfWeek","domainConfig","noOfMonthWeeks","getCol","NO_OF_DAYS_IN_WEEK","empty","currentDate","currentDateWithinData","getSubDomainConfig","mouseMove","mouseLeave","hoverRadio","startAngle","clockWise","prevSlicesProperties","slicesProperties","curAngle","originDiffAngle","diffAngle","endAngle","startPosition","endPosition","prevProperty","curStart","curEnd","curPath","arcStartX","arcStartY","arcEndX","arcEndY","makeArcPathStr","flag","calTranslateByAngle","g_off","formatted_labels","percent","slices","prevIndex","curActiveSliceIndex","prevAcitve","curActiveSlice","hoverSlice","Chart","getChartByType","StatisticsWidget","subClass","superClass","constructor","__proto__","oninit","vnode","today","setTime","app","statistics","timezoneOffset","setUTCHours","entities","periods","step","last_7_days","last_28_days","last_12_months","selectedEntity","selectedPeriod","thisPeriod","translator","trans","buttonClassName","caretIcon","period","active","onclick","changePeriod","icon","entity","totalCount","getTotalCount","thisPeriodCount","getPeriodCount","lastPeriodCount","getLastPeriod","periodChange","changeEntity","abbreviateNumber","oncreate","drawChart","onupdate","chart","periodLength","lastPeriod","dayjs","unix","format","dom","forum","attribute","timed","time","DashboardWidget","initializers","extend","DashboardPage","widgets"],"mappings":"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","file":"admin.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 8);\n","module.exports = flarum.core.compat['utils/abbreviateNumber'];","module.exports = flarum.core.compat['app'];","module.exports = flarum.core.compat['extend'];","module.exports = flarum.core.compat['components/DashboardPage'];","module.exports = flarum.core.compat['components/DashboardWidget'];","module.exports = flarum.core.compat['components/SelectDropdown'];","module.exports = flarum.core.compat['components/Button'];","module.exports = flarum.core.compat['helpers/icon'];","function $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\n\n\n$.create = (tag, o) => {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (i in element ) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\nfunction getOffset(element) {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n}\n\nfunction isElementInViewport(el) {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n}\n\nfunction getElementContentWidth(element) {\n\tvar styles = window.getComputedStyle(element);\n\tvar padding = parseFloat(styles.paddingLeft) +\n\t\tparseFloat(styles.paddingRight);\n\n\treturn element.clientWidth - padding;\n}\n\n\n\n\n\nfunction fire(target, type, properties) {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n}\n\n// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/\n\nconst BASE_MEASURES = {\n\tmargins: {\n\t\ttop: 10,\n\t\tbottom: 10,\n\t\tleft: 20,\n\t\tright: 20\n\t},\n\tpaddings: {\n\t\ttop: 20,\n\t\tbottom: 40,\n\t\tleft: 30,\n\t\tright: 10\n\t},\n\n\tbaseHeight: 240,\n\ttitleHeight: 20,\n\tlegendHeight: 30,\n\n\ttitleFontSize: 12,\n};\n\nfunction getTopOffset(m) {\n\treturn m.titleHeight + m.margins.top + m.paddings.top;\n}\n\nfunction getLeftOffset(m) {\n\treturn m.margins.left + m.paddings.left;\n}\n\nfunction getExtraHeight(m) {\n\tlet totalExtraHeight = m.margins.top + m.margins.bottom\n\t\t+ m.paddings.top + m.paddings.bottom\n\t\t+ m.titleHeight + m.legendHeight;\n\treturn totalExtraHeight;\n}\n\nfunction getExtraWidth(m) {\n\tlet totalExtraWidth = m.margins.left + m.margins.right\n\t\t+ m.paddings.left + m.paddings.right;\n\n\treturn totalExtraWidth;\n}\n\nconst INIT_CHART_UPDATE_TIMEOUT = 700;\nconst CHART_POST_ANIMATE_TIMEOUT = 400;\n\nconst DEFAULT_AXIS_CHART_TYPE = 'line';\nconst AXIS_DATASET_CHART_TYPES = ['line', 'bar'];\n\nconst AXIS_LEGEND_BAR_SIZE = 100;\n\nconst BAR_CHART_SPACE_RATIO = 0.5;\nconst MIN_BAR_PERCENT_HEIGHT = 0.01;\n\nconst LINE_CHART_DOT_SIZE = 4;\nconst DOT_OVERLAY_SIZE_INCR = 4;\n\nconst PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;\nconst PERCENTAGE_BAR_DEFAULT_DEPTH = 2;\n\n// Fixed 5-color theme,\n// More colors are difficult to parse visually\nconst HEATMAP_DISTRIBUTION_SIZE = 5;\n\nconst HEATMAP_SQUARE_SIZE = 10;\nconst HEATMAP_GUTTER_SIZE = 2;\n\nconst DEFAULT_CHAR_WIDTH = 7;\n\nconst TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5;\n\nconst DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];\nconst HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\n\n\n\nconst DEFAULT_COLORS = {\n\tbar: DEFAULT_CHART_COLORS,\n\tline: DEFAULT_CHART_COLORS,\n\tpie: DEFAULT_CHART_COLORS,\n\tpercentage: DEFAULT_CHART_COLORS,\n\theatmap: HEATMAP_COLORS_GREEN\n};\n\n// Universal constants\nconst ANGLE_RATIO = Math.PI / 180;\nconst FULL_ANGLE = 360;\n\nclass SvgTip {\n\tconstructor({\n\t\tparent = null,\n\t\tcolors = []\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.colors = colors;\n\t\tthis.titleName = '';\n\t\tthis.titleValue = '';\n\t\tthis.listValues = [];\n\t\tthis.titleValueFirst = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.makeTooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calcPosition();\n\t}\n\n\tmakeTooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t
        \n\t\t\t\t
        `\n\t\t});\n\t\tthis.hideTip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.dataPointList = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hideTip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.index) {\n\t\t\tthis.container.setAttribute('data-point-index', this.index);\n\t\t}\n\t\tif(this.titleValueFirst) {\n\t\t\ttitle = `${this.titleValue}${this.titleName}`;\n\t\t} else {\n\t\t\ttitle = `${this.titleName}${this.titleValue}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.dataPointList.innerHTML = '';\n\n\t\tthis.listValues.map((set, i) => {\n\t\t\tconst color = this.colors[i] || 'black';\n\t\t\tlet value = set.formatted === 0 || set.formatted ? set.formatted : set.value;\n\n\t\t\tlet li = $.create('li', {\n\t\t\t\tstyles: {\n\t\t\t\t\t'border-top': `3px solid ${color}`\n\t\t\t\t},\n\t\t\t\tinnerHTML: `${ value === 0 || value ? value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.dataPointList.appendChild(li);\n\t\t});\n\t}\n\n\tcalcPosition() {\n\t\tlet width = this.container.offsetWidth;\n\n\t\tthis.top = this.y - this.container.offsetHeight\n\t\t\t- TOOLTIP_POINTER_TRIANGLE_HEIGHT;\n\t\tthis.left = this.x - width/2;\n\t\tlet maxLeft = this.parent.offsetWidth - width;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > maxLeft) {\n\t\t\tlet delta = this.left - maxLeft;\n\t\t\tlet pointerOffset = `calc(50% + ${delta}px)`;\n\t\t\tpointer.style.left = pointerOffset;\n\n\t\t\tthis.left = maxLeft;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tsetValues(x, y, title = {}, listValues = [], index = -1) {\n\t\tthis.titleName = title.name;\n\t\tthis.titleValue = title.value;\n\t\tthis.listValues = listValues;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.titleValueFirst = title.valueFirst || 0;\n\t\tthis.index = index;\n\t\tthis.refresh();\n\t}\n\n\thideTip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshowTip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n\nfunction floatTwo(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\n/**\n * Returns whether or not two given arrays are equal.\n * @param {Array} arr1 First array\n * @param {Array} arr2 Second array\n */\n\n\n/**\n * Shuffles array in place. ES6 version\n * @param {Array} array An array containing the items.\n */\n\n\n/**\n * Fill an array with extra points\n * @param {Array} array Array\n * @param {Number} count number of filler elements\n * @param {Object} element element to fill with\n * @param {Boolean} start fill at start?\n */\nfunction fillArray(array, count, element, start=false) {\n\tif(!element) {\n\t\telement = start ? array[0] : array[array.length - 1];\n\t}\n\tlet fillerArray = new Array(Math.abs(count)).fill(element);\n\tarray = start ? fillerArray.concat(array) : array.concat(fillerArray);\n\treturn array;\n}\n\n/**\n * Returns pixel width of string.\n * @param {String} string\n * @param {Number} charWidth Width of single char in pixels\n */\nfunction getStringWidth(string, charWidth) {\n\treturn (string+\"\").length * charWidth;\n}\n\n\n\n// https://stackoverflow.com/a/29325222\n\n\nfunction getPositionByAngle(angle, radius) {\n\treturn {\n\t\tx: Math.sin(angle * ANGLE_RATIO) * radius,\n\t\ty: Math.cos(angle * ANGLE_RATIO) * radius,\n\t};\n}\n\nfunction getBarHeightAndYAttr(yTop, zeroLine) {\n\tlet height, y;\n\tif (yTop <= zeroLine) {\n\t\theight = zeroLine - yTop;\n\t\ty = yTop;\n\t} else {\n\t\theight = yTop - zeroLine;\n\t\ty = zeroLine;\n\t}\n\n\treturn [height, y];\n}\n\nfunction equilizeNoOfElements(array1, array2,\n\textraCount = array2.length - array1.length) {\n\n\t// Doesn't work if either has zero elements.\n\tif(extraCount > 0) {\n\t\tarray1 = fillArray(array1, extraCount);\n\t} else {\n\t\tarray2 = fillArray(array2, extraCount);\n\t}\n\treturn [array1, array2];\n}\n\nconst PRESET_COLOR_MAP = {\n\t'light-blue': '#7cd6fd',\n\t'blue': '#5e64ff',\n\t'violet': '#743ee2',\n\t'red': '#ff5858',\n\t'orange': '#ffa00a',\n\t'yellow': '#feef72',\n\t'green': '#28a745',\n\t'light-green': '#98d85b',\n\t'purple': '#b554ff',\n\t'magenta': '#ffa3ef',\n\t'black': '#36114C',\n\t'grey': '#bdd3e6',\n\t'light-grey': '#f0f4f7',\n\t'dark-grey': '#b8c2cc'\n};\n\nfunction limitColor(r){\n\tif (r > 255) return 255;\n\telse if (r < 0) return 0;\n\treturn r;\n}\n\nfunction lightenDarkenColor(color, amt) {\n\tlet col = getColor(color);\n\tlet usePound = false;\n\tif (col[0] == \"#\") {\n\t\tcol = col.slice(1);\n\t\tusePound = true;\n\t}\n\tlet num = parseInt(col,16);\n\tlet r = limitColor((num >> 16) + amt);\n\tlet b = limitColor(((num >> 8) & 0x00FF) + amt);\n\tlet g = limitColor((num & 0x0000FF) + amt);\n\treturn (usePound?\"#\":\"\") + (g | (b << 8) | (r << 16)).toString(16);\n}\n\nfunction isValidColor(string) {\n\t// https://stackoverflow.com/a/8027444/6495043\n\treturn /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(string);\n}\n\nconst getColor = (color) => {\n\treturn PRESET_COLOR_MAP[color] || color;\n};\n\nconst AXIS_TICK_LENGTH = 6;\nconst LABEL_MARGIN = 4;\nconst FONT_SIZE = 10;\nconst BASE_LINE_COLOR = '#dadada';\nconst FONT_FILL = '#555b51';\n\nfunction $$1(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nfunction createSVG(tag, o) {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$$1(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $$1(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction renderVerticalGradient(svgDefElem, gradientId) {\n\treturn createSVG('linearGradient', {\n\t\tinside: svgDefElem,\n\t\tid: gradientId,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: 0,\n\t\ty2: 1\n\t});\n}\n\nfunction setGradientStop(gradElem, offset, color, opacity) {\n\treturn createSVG('stop', {\n\t\t'inside': gradElem,\n\t\t'style': `stop-color: ${color}`,\n\t\t'offset': offset,\n\t\t'stop-opacity': opacity\n\t});\n}\n\nfunction makeSVGContainer(parent, className, width, height) {\n\treturn createSVG('svg', {\n\t\tclassName: className,\n\t\tinside: parent,\n\t\twidth: width,\n\t\theight: height\n\t});\n}\n\nfunction makeSVGDefs(svgContainer) {\n\treturn createSVG('defs', {\n\t\tinside: svgContainer,\n\t});\n}\n\nfunction makeSVGGroup(className, transform='', parent=undefined) {\n\tlet args = {\n\t\tclassName: className,\n\t\ttransform: transform\n\t};\n\tif(parent) args.inside = parent;\n\treturn createSVG('g', args);\n}\n\n\n\nfunction makePath(pathStr, className='', stroke='none', fill='none') {\n\treturn createSVG('path', {\n\t\tclassName: className,\n\t\td: pathStr,\n\t\tstyles: {\n\t\t\tstroke: stroke,\n\t\t\tfill: fill\n\t\t}\n\t});\n}\n\nfunction makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 0 ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nfunction makeGradient(svgDefElem, color, lighter = false) {\n\tlet gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');\n\tlet gradientDef = renderVerticalGradient(svgDefElem, gradientId);\n\tlet opacities = [1, 0.6, 0.2];\n\tif(lighter) {\n\t\topacities = [0.4, 0.2, 0];\n\t}\n\n\tsetGradientStop(gradientDef, \"0%\", color, opacities[0]);\n\tsetGradientStop(gradientDef, \"50%\", color, opacities[1]);\n\tsetGradientStop(gradientDef, \"100%\", color, opacities[2]);\n\n\treturn gradientId;\n}\n\nfunction percentageBar(x, y, width, height,\n\tdepth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {\n\n\tlet args = {\n\t\tclassName: 'percentage-bar',\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height,\n\t\tfill: fill,\n\t\tstyles: {\n\t\t\t'stroke': lightenDarkenColor(fill, -25),\n\t\t\t// Diabolically good: https://stackoverflow.com/a/9000859\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\n\t\t\t'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,\n\t\t\t'stroke-width': depth\n\t\t},\n\t};\n\n\treturn createSVG(\"rect\", args);\n}\n\nfunction heatSquare(className, x, y, size, fill='none', data={}) {\n\tlet args = {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: size,\n\t\theight: size,\n\t\tfill: fill\n\t};\n\n\tObject.keys(data).map(key => {\n\t\targs[key] = data[key];\n\t});\n\n\treturn createSVG(\"rect\", args);\n}\n\nfunction legendBar(x, y, size, fill='none', label) {\n\tlet args = {\n\t\tclassName: 'legend-bar',\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: size,\n\t\theight: '2px',\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE * 2) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"rect\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nfunction legendDot(x, y, size, fill='none', label) {\n\tlet args = {\n\t\tclassName: 'legend-dot',\n\t\tcx: 0,\n\t\tcy: 0,\n\t\tr: size,\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdx: (FONT_SIZE) + 'px',\n\t\tdy: (FONT_SIZE/3) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"circle\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nfunction makeText(className, x, y, content, options = {}) {\n\tlet fontSize = options.fontSize || FONT_SIZE;\n\tlet dy = options.dy !== undefined ? options.dy : (fontSize / 2);\n\tlet fill = options.fill || FONT_FILL;\n\tlet textAnchor = options.textAnchor || 'start';\n\treturn createSVG('text', {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\tdy: dy + 'px',\n\t\t'font-size': fontSize + 'px',\n\t\tfill: fill,\n\t\t'text-anchor': textAnchor,\n\t\tinnerHTML: content\n\t});\n}\n\nfunction makeVertLine(x, label, y1, y2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tlet l = createSVG('line', {\n\t\tclassName: 'line-vertical ' + options.className,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: y1,\n\t\ty2: y2,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: 0,\n\t\ty: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE,\n\t\tdy: FONT_SIZE + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'middle',\n\t\tinnerHTML: label + \"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(${ x }, 0)`\n\t});\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction makeHoriLine(y, label, x1, x2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.lineType) options.lineType = '';\n\tlet className = 'line-horizontal ' + options.className +\n\t\t(options.lineType === \"dashed\" ? \"dashed\": \"\");\n\n\tlet l = createSVG('line', {\n\t\tclassName: className,\n\t\tx1: x1,\n\t\tx2: x2,\n\t\ty1: 0,\n\t\ty2: 0,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / 2 - 2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': x1 < x2 ? 'end' : 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(0, ${y})`,\n\t\t'stroke-opacity': 1\n\t});\n\n\tif(text === 0 || text === '0') {\n\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t}\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction yLine(y, label, width, options={}) {\n\tif(!options.pos) options.pos = 'left';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\tlet x1 = -1 * AXIS_TICK_LENGTH;\n\tlet x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;\n\n\tif(options.mode === 'tick' && options.pos === 'right') {\n\t\tx1 = width + AXIS_TICK_LENGTH;\n\t\tx2 = width;\n\t}\n\n\t// let offset = options.pos === 'left' ? -1 * options.offset : options.offset;\n\n\tx1 += options.offset;\n\tx2 += options.offset;\n\n\treturn makeHoriLine(y, label, x1, x2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nfunction xLine(x, label, height, options={}) {\n\tif(!options.pos) options.pos = 'bottom';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\t// Draw X axis line in span/tick mode with optional label\n\t// \ty2(span)\n\t// \t\t\t\t\t\t|\n\t// \t\t\t\t\t\t|\n\t//\t\t\t\tx line\t|\n\t//\t\t\t\t\t\t|\n\t// \t\t\t\t\t \t|\n\t// ---------------------+-- y2(tick)\n\t//\t\t\t\t\t\t|\n\t//\t\t\t\t\t\t\ty1\n\n\tlet y1 = height + AXIS_TICK_LENGTH;\n\tlet y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;\n\n\tif(options.mode === 'tick' && options.pos === 'top') {\n\t\t// top axis ticks\n\t\ty1 = -1 * AXIS_TICK_LENGTH;\n\t\ty2 = 0;\n\t}\n\n\treturn makeVertLine(x, label, y1, y2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nfunction yMarker(y, label, width, options={}) {\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label, 5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = makeHoriLine(y, '', 0, width, {\n\t\tstroke: options.stroke || BASE_LINE_COLOR,\n\t\tclassName: options.className || '',\n\t\tlineType: options.lineType\n\t});\n\n\tline.appendChild(labelSvg);\n\n\treturn line;\n}\n\nfunction yRegion(y1, y2, width, label, options={}) {\n\t// return a group\n\tlet height = y1 - y2;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`, // remove class\n\t\tstyles: {\n\t\t\tfill: `rgba(228, 234, 239, 0.49)`,\n\t\t\tstroke: BASE_LINE_COLOR,\n\t\t\t'stroke-dasharray': `${width}, ${height}`\n\t\t},\n\t\t// 'data-point-index': index,\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label+\"\", 4.5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet region = createSVG('g', {\n\t\ttransform: `translate(0, ${y2})`\n\t});\n\n\tregion.appendChild(rect);\n\tregion.appendChild(labelSvg);\n\n\treturn region;\n}\n\nfunction datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\n\tif(height === 0) {\n\t\theight = meta.minHeight;\n\t\ty -= meta.minHeight;\n\t}\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`,\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn rect;\n\t} else {\n\t\trect.setAttribute('y', 0);\n\t\trect.setAttribute('x', 0);\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: width/2,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(rect);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nfunction datasetDot(x, y, radius, color, label='', index=0) {\n\tlet dot = createSVG('circle', {\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tcx: x,\n\t\tcy: y,\n\t\tr: radius\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn dot;\n\t} else {\n\t\tdot.setAttribute('cy', 0);\n\t\tdot.setAttribute('cx', 0);\n\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1 - radius) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(dot);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nfunction getPaths(xList, yList, color, options={}, meta={}) {\n\tlet pointsList = yList.map((y, i) => (xList[i] + ',' + y));\n\tlet pointsStr = pointsList.join(\"L\");\n\tlet path = makePath(\"M\"+pointsStr, 'line-graph-path', color);\n\n\t// HeatLine\n\tif(options.heatline) {\n\t\tlet gradient_id = makeGradient(meta.svgDefs, color);\n\t\tpath.style.stroke = `url(#${gradient_id})`;\n\t}\n\n\tlet paths = {\n\t\tpath: path\n\t};\n\n\t// Region\n\tif(options.regionFill) {\n\t\tlet gradient_id_region = makeGradient(meta.svgDefs, color, true);\n\n\t\tlet pathStr = \"M\" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;\n\t\tpaths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`);\n\t}\n\n\treturn paths;\n}\n\nlet makeOverlay = {\n\t'bar': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\toverlay.style.fill = '#000000';\n\t\toverlay.style.opacity = '0.4';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'dot': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'heat_square': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t}\n};\n\nlet updateOverlay = {\n\t'bar': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['x', 'y', 'width', 'height'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'dot': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'heat_square': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n};\n\nconst UNIT_ANIM_DUR = 350;\nconst PATH_ANIM_DUR = 350;\nconst MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;\nconst REPLACE_ALL_NEW_DUR = 250;\n\nconst STD_EASING = 'easein';\n\nfunction translate(unit, oldCoord, newCoord, duration) {\n\tlet old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');\n\treturn [\n\t\tunit,\n\t\t{transform: newCoord.join(', ')},\n\t\tduration,\n\t\tSTD_EASING,\n\t\t\"translate\",\n\t\t{transform: old}\n\t];\n}\n\nfunction translateVertLine(xLine, newX, oldX) {\n\treturn translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR);\n}\n\nfunction translateHoriLine(yLine, newY, oldY) {\n\treturn translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR);\n}\n\nfunction animateRegion(rectGroup, newY1, newY2, oldY2) {\n\tlet newHeight = newY1 - newY2;\n\tlet rect = rectGroup.childNodes[0];\n\tlet width = rect.getAttribute(\"width\");\n\tlet rectAnim = [\n\t\trect,\n\t\t{ height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` },\n\t\tMARKER_LINE_ANIM_DUR,\n\t\tSTD_EASING\n\t];\n\n\tlet groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR);\n\treturn [rectAnim, groupAnim];\n}\n\nfunction animateBar(bar, x, yTop, width, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\tif(bar.nodeName !== 'rect') {\n\t\tlet rect = bar.childNodes[0];\n\t\tlet rectAnim = [\n\t\t\trect,\n\t\t\t{width: width, height: height},\n\t\t\tUNIT_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\n\t\tlet oldCoordStr = bar.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [rectAnim, groupAnim];\n\t} else {\n\t\treturn [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nfunction animateDot(dot, x, y) {\n\tif(dot.nodeName !== 'circle') {\n\t\tlet oldCoordStr = dot.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [groupAnim];\n\t} else {\n\t\treturn [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nfunction animatePath(paths, newXList, newYList, zeroLine) {\n\tlet pathComponents = [];\n\n\tlet pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y));\n\tlet pathStr = pointsStr.join(\"L\");\n\n\tconst animPath = [paths.path, {d:\"M\"+pathStr}, PATH_ANIM_DUR, STD_EASING];\n\tpathComponents.push(animPath);\n\n\tif(paths.region) {\n\t\tlet regStartPt = `${newXList[0]},${zeroLine}L`;\n\t\tlet regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;\n\n\t\tconst animRegion = [\n\t\t\tpaths.region,\n\t\t\t{d:\"M\" + regStartPt + pathStr + regEndPt},\n\t\t\tPATH_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\t\tpathComponents.push(animRegion);\n\t}\n\n\treturn pathComponents;\n}\n\nfunction animatePathStr(oldPath, pathStr) {\n\treturn [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];\n}\n\n// Leveraging SMIL Animations\n\nconst EASING = {\n\tease: \"0.25 0.1 0.25 1\",\n\tlinear: \"0 0 1 1\",\n\t// easein: \"0.42 0 1 1\",\n\teasein: \"0.1 0.8 0.2 1\",\n\teaseout: \"0 0 0.58 1\",\n\teaseinout: \"0.42 0 0.58 1\"\n};\n\nfunction animateSVGElement(element, props, dur, easingType=\"linear\", type=undefined, oldValues={}) {\n\n\tlet animElement = element.cloneNode(true);\n\tlet newElement = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animateElement;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet currentValue = oldValues[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet animAttr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: currentValue,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: currentValue + \";\" + value,\n\t\t\tkeySplines: EASING[easingType],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanimAttr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in animAttr) {\n\t\t\tanimateElement.setAttribute(i, animAttr[i]);\n\t\t}\n\n\t\tanimElement.appendChild(animateElement);\n\n\t\tif(type) {\n\t\t\tnewElement.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnewElement.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [animElement, newElement];\n}\n\nfunction transform(element, style) { // eslint-disable-line no-unused-vars\n\telement.style.transform = style;\n\telement.style.webkitTransform = style;\n\telement.style.msTransform = style;\n\telement.style.mozTransform = style;\n\telement.style.oTransform = style;\n}\n\nfunction animateSVG(svgContainer, elements) {\n\tlet newElements = [];\n\tlet animElements = [];\n\n\telements.map(element => {\n\t\tlet unit = element[0];\n\t\tlet parent = unit.parentNode;\n\n\t\tlet animElement, newElement;\n\n\t\telement[0] = unit;\n\t\t[animElement, newElement] = animateSVGElement(...element);\n\n\t\tnewElements.push(newElement);\n\t\tanimElements.push([animElement, parent]);\n\n\t\tparent.replaceChild(animElement, unit);\n\t});\n\n\tlet animSvg = svgContainer.cloneNode(true);\n\n\tanimElements.map((animElement, i) => {\n\t\tanimElement[1].replaceChild(newElements[i], animElement[0]);\n\t\telements[i][0] = newElements[i];\n\t});\n\n\treturn animSvg;\n}\n\nfunction runSMILAnimation(parent, svgElement, elementsToAnimate) {\n\tif(elementsToAnimate.length === 0) return;\n\n\tlet animSvgElement = animateSVG(svgElement, elementsToAnimate);\n\tif(svgElement.parentNode == parent) {\n\t\tparent.removeChild(svgElement);\n\t\tparent.appendChild(animSvgElement);\n\n\t}\n\n\t// Replace the new svgElement (data has already been replaced)\n\tsetTimeout(() => {\n\t\tif(animSvgElement.parentNode == parent) {\n\t\t\tparent.removeChild(animSvgElement);\n\t\t\tparent.appendChild(svgElement);\n\t\t}\n\t}, REPLACE_ALL_NEW_DUR);\n}\n\nconst CSSTEXT = \".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}\";\n\nfunction downloadFile(filename, data) {\n\tvar a = document.createElement('a');\n\ta.style = \"display: none\";\n\tvar blob = new Blob(data, {type: \"image/svg+xml; charset=utf-8\"});\n\tvar url = window.URL.createObjectURL(blob);\n\ta.href = url;\n\ta.download = filename;\n\tdocument.body.appendChild(a);\n\ta.click();\n\tsetTimeout(function(){\n\t\tdocument.body.removeChild(a);\n\t\twindow.URL.revokeObjectURL(url);\n\t}, 300);\n}\n\nfunction prepareForExport(svg) {\n\tlet clone = svg.cloneNode(true);\n\tclone.classList.add('chart-container');\n\tclone.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n\tclone.setAttribute('xmlns:xlink', \"http://www.w3.org/1999/xlink\");\n\tlet styleEl = $.create('style', {\n\t\t'innerHTML': CSSTEXT\n\t});\n\tclone.insertBefore(styleEl, clone.firstChild);\n\n\tlet container = $.create('div');\n\tcontainer.appendChild(clone);\n\n\treturn container.innerHTML;\n}\n\nlet BOUND_DRAW_FN;\n\nclass BaseChart {\n\tconstructor(parent, options) {\n\n\t\tthis.parent = typeof parent === 'string'\n\t\t\t? document.querySelector(parent)\n\t\t\t: parent;\n\n\t\tif (!(this.parent instanceof HTMLElement)) {\n\t\t\tthrow new Error('No `parent` element to render on was provided.');\n\t\t}\n\n\t\tthis.rawChartArgs = options;\n\n\t\tthis.title = options.title || '';\n\t\tthis.type = options.type || '';\n\n\t\tthis.realData = this.prepareData(options.data);\n\t\tthis.data = this.prepareFirstData(this.realData);\n\n\t\tthis.colors = this.validateColors(options.colors, this.type);\n\n\t\tthis.config = {\n\t\t\tshowTooltip: 1, // calculate\n\t\t\tshowLegend: 1, // calculate\n\t\t\tisNavigable: options.isNavigable || 0,\n\t\t\tanimate: 1\n\t\t};\n\n\t\tthis.measures = JSON.parse(JSON.stringify(BASE_MEASURES));\n\t\tlet m = this.measures;\n\t\tthis.setMeasures(options);\n\t\tif(!this.title.length) { m.titleHeight = 0; }\n\t\tif(!this.config.showLegend) m.legendHeight = 0;\n\t\tthis.argHeight = options.height || m.baseHeight;\n\n\t\tthis.state = {};\n\t\tthis.options = {};\n\n\t\tthis.initTimeout = INIT_CHART_UPDATE_TIMEOUT;\n\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.overlays = [];\n\t\t}\n\n\t\tthis.configure(options);\n\t}\n\n\tprepareData(data) {\n\t\treturn data;\n\t}\n\n\tprepareFirstData(data) {\n\t\treturn data;\n\t}\n\n\tvalidateColors(colors, type) {\n\t\tconst validColors = [];\n\t\tcolors = (colors || []).concat(DEFAULT_COLORS[type]);\n\t\tcolors.forEach((string) => {\n\t\t\tconst color = getColor(string);\n\t\t\tif(!isValidColor(color)) {\n\t\t\t\tconsole.warn('\"' + string + '\" is not a valid color.');\n\t\t\t} else {\n\t\t\t\tvalidColors.push(color);\n\t\t\t}\n\t\t});\n\t\treturn validColors;\n\t}\n\n\tsetMeasures() {\n\t\t// Override measures, including those for title and legend\n\t\t// set config for legend and title\n\t}\n\n\tconfigure() {\n\t\tlet height = this.argHeight;\n\t\tthis.baseHeight = height;\n\t\tthis.height = height - getExtraHeight(this.measures);\n\n\t\t// Bind window events\n\t\tBOUND_DRAW_FN = this.boundDrawFn.bind(this);\n\t\twindow.addEventListener('resize', BOUND_DRAW_FN);\n\t\twindow.addEventListener('orientationchange', this.boundDrawFn.bind(this));\n\t}\n\n\tboundDrawFn() {\n\t\tthis.draw(true);\n\t}\n\n\tunbindWindowEvents() {\n\t\twindow.removeEventListener('resize', BOUND_DRAW_FN);\n\t\twindow.removeEventListener('orientationchange', this.boundDrawFn.bind(this));\n\t}\n\n\t// Has to be called manually\n\tsetup() {\n\t\tthis.makeContainer();\n\t\tthis.updateWidth();\n\t\tthis.makeTooltip();\n\n\t\tthis.draw(false, true);\n\t}\n\n\tmakeContainer() {\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\n\t\tlet args = {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'chart-container'\n\t\t};\n\n\t\tif(this.independentWidth) {\n\t\t\targs.styles = { width: this.independentWidth + 'px' };\n\t\t}\n\n\t\tthis.container = $.create('div', args);\n\t}\n\n\tmakeTooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.container,\n\t\t\tcolors: this.colors\n\t\t});\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {}\n\n\tdraw(onlyWidthChange=false, init=false) {\n\t\tthis.updateWidth();\n\n\t\tthis.calc(onlyWidthChange);\n\t\tthis.makeChartArea();\n\t\tthis.setupComponents();\n\n\t\tthis.components.forEach(c => c.setup(this.drawArea));\n\t\t// this.components.forEach(c => c.make());\n\t\tthis.render(this.components, false);\n\n\t\tif(init) {\n\t\t\tthis.data = this.realData;\n\t\t\tsetTimeout(() => {this.update(this.data);}, this.initTimeout);\n\t\t}\n\n\t\tthis.renderLegend();\n\n\t\tthis.setupNavigation(init);\n\t}\n\n\tcalc() {} // builds state\n\n\tupdateWidth() {\n\t\tthis.baseWidth = getElementContentWidth(this.parent);\n\t\tthis.width = this.baseWidth - getExtraWidth(this.measures);\n\t}\n\n\tmakeChartArea() {\n\t\tif(this.svg) {\n\t\t\tthis.container.removeChild(this.svg);\n\t\t}\n\t\tlet m = this.measures;\n\n\t\tthis.svg = makeSVGContainer(\n\t\t\tthis.container,\n\t\t\t'frappe-chart chart',\n\t\t\tthis.baseWidth,\n\t\t\tthis.baseHeight\n\t\t);\n\t\tthis.svgDefs = makeSVGDefs(this.svg);\n\n\t\tif(this.title.length) {\n\t\t\tthis.titleEL = makeText(\n\t\t\t\t'title',\n\t\t\t\tm.margins.left,\n\t\t\t\tm.margins.top,\n\t\t\t\tthis.title,\n\t\t\t\t{\n\t\t\t\t\tfontSize: m.titleFontSize,\n\t\t\t\t\tfill: '#666666',\n\t\t\t\t\tdy: m.titleFontSize\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tlet top = getTopOffset(m);\n\t\tthis.drawArea = makeSVGGroup(\n\t\t\tthis.type + '-chart chart-draw-area',\n\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t);\n\n\t\tif(this.config.showLegend) {\n\t\t\ttop += this.height + m.paddings.bottom;\n\t\t\tthis.legendArea = makeSVGGroup(\n\t\t\t\t'chart-legend',\n\t\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t\t);\n\t\t}\n\n\t\tif(this.title.length) { this.svg.appendChild(this.titleEL); }\n\t\tthis.svg.appendChild(this.drawArea);\n\t\tif(this.config.showLegend) { this.svg.appendChild(this.legendArea); }\n\n\t\tthis.updateTipOffset(getLeftOffset(m), getTopOffset(m));\n\t}\n\n\tupdateTipOffset(x, y) {\n\t\tthis.tip.offset = {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t}\n\n\tsetupComponents() { this.components = new Map(); }\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\t\tthis.data = this.prepareData(data);\n\t\tthis.calc(); // builds state\n\t\tthis.render();\n\t}\n\n\trender(components=this.components, animate=true) {\n\t\tif(this.config.isNavigable) {\n\t\t\t// Remove all existing overlays\n\t\t\tthis.overlays.map(o => o.parentNode.removeChild(o));\n\t\t\t// ref.parentNode.insertBefore(element, ref);\n\t\t}\n\t\tlet elementsToAnimate = [];\n\t\t// Can decouple to this.refreshComponents() first to save animation timeout\n\t\tcomponents.forEach(c => {\n\t\t\telementsToAnimate = elementsToAnimate.concat(c.update(animate));\n\t\t});\n\t\tif(elementsToAnimate.length > 0) {\n\t\t\trunSMILAnimation(this.container, this.svg, elementsToAnimate);\n\t\t\tsetTimeout(() => {\n\t\t\t\tcomponents.forEach(c => c.make());\n\t\t\t\tthis.updateNav();\n\t\t\t}, CHART_POST_ANIMATE_TIMEOUT);\n\t\t} else {\n\t\t\tcomponents.forEach(c => c.make());\n\t\t\tthis.updateNav();\n\t\t}\n\t}\n\n\tupdateNav() {\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.makeOverlay();\n\t\t\tthis.bindUnits();\n\t\t}\n\t}\n\n\trenderLegend() {}\n\n\tsetupNavigation(init=false) {\n\t\tif(!this.config.isNavigable) return;\n\n\t\tif(init) {\n\t\t\tthis.bindOverlay();\n\n\t\t\tthis.keyActions = {\n\t\t\t\t'13': this.onEnterKey.bind(this),\n\t\t\t\t'37': this.onLeftArrow.bind(this),\n\t\t\t\t'38': this.onUpArrow.bind(this),\n\t\t\t\t'39': this.onRightArrow.bind(this),\n\t\t\t\t'40': this.onDownArrow.bind(this),\n\t\t\t};\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif(isElementInViewport(this.container)) {\n\t\t\t\t\te = e || window.event;\n\t\t\t\t\tif(this.keyActions[e.keyCode]) {\n\t\t\t\t\t\tthis.keyActions[e.keyCode]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmakeOverlay() {}\n\tupdateOverlay() {}\n\tbindOverlay() {}\n\tbindUnits() {}\n\n\tonLeftArrow() {}\n\tonRightArrow() {}\n\tonUpArrow() {}\n\tonDownArrow() {}\n\tonEnterKey() {}\n\n\taddDataPoint() {}\n\tremoveDataPoint() {}\n\n\tgetDataPoint() {}\n\tsetCurrentDataPoint() {}\n\n\tupdateDataset() {}\n\n\texport() {\n\t\tlet chartSvg = prepareForExport(this.svg);\n\t\tdownloadFile(this.title || 'Chart', [chartSvg]);\n\t}\n}\n\nclass AggregationChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\n\t\tthis.config.maxSlices = args.maxSlices || 20;\n\t\tthis.config.maxLegendPoints = args.maxLegendPoints || 20;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\t\tlet maxSlices = this.config.maxSlices;\n\t\ts.sliceTotals = [];\n\n\t\tlet allTotals = this.data.labels.map((label, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, label];\n\t\t}).filter(d => { return d[0] >= 0; }); // keep only positive results\n\n\t\tlet totals = allTotals;\n\t\tif(allTotals.length > maxSlices) {\n\t\t\t// Prune and keep a grey area for rest as per maxSlices\n\t\t\tallTotals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = allTotals.slice(0, maxSlices-1);\n\t\t\tlet remaining = allTotals.slice(maxSlices-1);\n\n\t\t\tlet sumOfRemaining = 0;\n\t\t\tremaining.map(d => {sumOfRemaining += d[0];});\n\t\t\ttotals.push([sumOfRemaining, 'Rest']);\n\t\t\tthis.colors[maxSlices-1] = 'grey';\n\t\t}\n\n\t\ts.labels = [];\n\t\ttotals.map(d => {\n\t\t\ts.sliceTotals.push(d[0]);\n\t\t\ts.labels.push(d[1]);\n\t\t});\n\n\t\ts.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);\n\n\t\tthis.center = {\n\t\t\tx: this.width / 2,\n\t\t\ty: this.height / 2\n\t\t};\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.state;\n\t\tthis.legendArea.textContent = '';\n\t\tthis.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);\n\n\t\tlet count = 0;\n\t\tlet y = 0;\n\t\tthis.legendTotals.map((d, i) => {\n\t\t\tlet barWidth = 110;\n\t\t\tlet divisor = Math.floor(\n\t\t\t\t(this.width - getExtraWidth(this.measures))/barWidth\n\t\t\t);\n\t\t\tif(count > divisor) {\n\t\t\t\tcount = 0;\n\t\t\t\ty += 20;\n\t\t\t}\n\t\t\tlet x = barWidth * count + 5;\n\t\t\tlet dot = legendDot(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\t5,\n\t\t\t\tthis.colors[i],\n\t\t\t\t`${s.labels[i]}: ${d}`\n\t\t\t);\n\t\t\tthis.legendArea.appendChild(dot);\n\t\t\tcount++;\n\t\t});\n\t}\n}\n\n// Playing around with dates\n\nconst NO_OF_YEAR_MONTHS = 12;\nconst NO_OF_DAYS_IN_WEEK = 7;\n\nconst NO_OF_MILLIS = 1000;\nconst SEC_IN_DAY = 86400;\n\nconst MONTH_NAMES = [\"January\", \"February\", \"March\", \"April\", \"May\",\n\t\"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\n\n\nconst DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\n\n\n// https://stackoverflow.com/a/11252167/6495043\nfunction treatAsUtc(date) {\n\tlet result = new Date(date);\n\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\treturn result;\n}\n\nfunction getYyyyMmDd(date) {\n\tlet dd = date.getDate();\n\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\treturn [\n\t\tdate.getFullYear(),\n\t\t(mm>9 ? '' : '0') + mm,\n\t\t(dd>9 ? '' : '0') + dd\n\t].join('-');\n}\n\nfunction clone(date) {\n\treturn new Date(date.getTime());\n}\n\n\n\n\n\n// export function getMonthsBetween(startDate, endDate) {}\n\nfunction getWeeksBetween(startDate, endDate) {\n\tlet weekStartDate = setDayToSunday(startDate);\n\treturn Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);\n}\n\nfunction getDaysBetween(startDate, endDate) {\n\tlet millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;\n\treturn (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;\n}\n\nfunction areInSameMonth(startDate, endDate) {\n\treturn startDate.getMonth() === endDate.getMonth()\n\t\t&& startDate.getFullYear() === endDate.getFullYear();\n}\n\nfunction getMonthName(i, short=false) {\n\tlet monthName = MONTH_NAMES[i];\n\treturn short ? monthName.slice(0, 3) : monthName;\n}\n\nfunction getLastDateInMonth (month, year) {\n\treturn new Date(year, month + 1, 0); // 0: last day in previous month\n}\n\n// mutates\nfunction setDayToSunday(date) {\n\tlet newDate = clone(date);\n\tconst day = newDate.getDay();\n\tif(day !== 0) {\n\t\taddDays(newDate, (-1) * day);\n\t}\n\treturn newDate;\n}\n\n// mutates\nfunction addDays(date, numberOfDays) {\n\tdate.setDate(date.getDate() + numberOfDays);\n}\n\nclass ChartComponent {\n\tconstructor({\n\t\tlayerClass = '',\n\t\tlayerTransform = '',\n\t\tconstants,\n\n\t\tgetData,\n\t\tmakeElements,\n\t\tanimateElements\n\t}) {\n\t\tthis.layerTransform = layerTransform;\n\t\tthis.constants = constants;\n\n\t\tthis.makeElements = makeElements;\n\t\tthis.getData = getData;\n\n\t\tthis.animateElements = animateElements;\n\n\t\tthis.store = [];\n\t\tthis.labels = [];\n\n\t\tthis.layerClass = layerClass;\n\t\tthis.layerClass = typeof(this.layerClass) === 'function'\n\t\t\t? this.layerClass() : this.layerClass;\n\n\t\tthis.refresh();\n\t}\n\n\trefresh(data) {\n\t\tthis.data = data || this.getData();\n\t}\n\n\tsetup(parent) {\n\t\tthis.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent);\n\t}\n\n\tmake() {\n\t\tthis.render(this.data);\n\t\tthis.oldData = this.data;\n\t}\n\n\trender(data) {\n\t\tthis.store = this.makeElements(data);\n\n\t\tthis.layer.textContent = '';\n\t\tthis.store.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t\tthis.labels.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t}\n\n\tupdate(animate = true) {\n\t\tthis.refresh();\n\t\tlet animateElements = [];\n\t\tif(animate) {\n\t\t\tanimateElements = this.animateElements(this.data) || [];\n\t\t}\n\t\treturn animateElements;\n\t}\n}\n\nlet componentConfigs = {\n\tpieSlices: {\n\t\tlayerClass: 'pie-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) =>{\n\t\t\t\tlet slice = makePath(s, 'pie-path', 'none', data.colors[i]);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) =>\n\t\t\t\tanimatePathStr(slice, newData.sliceStrings[i])\n\t\t\t);\n\t\t}\n\t},\n\tpercentageBars: {\n\t\tlayerClass: 'percentage-bars',\n\t\tmakeElements(data) {\n\t\t\treturn data.xPositions.map((x, i) =>{\n\t\t\t\tlet y = 0;\n\t\t\t\tlet bar = percentageBar(x, y, data.widths[i],\n\t\t\t\t\tthis.constants.barHeight, this.constants.barDepth, data.colors[i]);\n\t\t\t\treturn bar;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\tyAxis: {\n\t\tlayerClass: 'y axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\tyLine(position, data.labels[i], this.constants.width,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.labels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tlabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\txAxis: {\n\t\tlayerClass: 'x axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\txLine(position, data.calcLabels[i], this.constants.height,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.calcLabels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.calcLabels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tcalcLabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateVertLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyMarkers: {\n\t\tlayerClass: 'y-markers',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(m =>\n\t\t\t\tyMarker(m.position, m.label, this.constants.width,\n\t\t\t\t\t{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.position);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.position);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tposition: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyRegions: {\n\t\tlayerClass: 'y-regions',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(r =>\n\t\t\t\tyRegion(r.startPos, r.endPos, this.constants.width,\n\t\t\t\t\tr.label, {labelPos: r.options.labelPos})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.endPos);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newStarts = newData.map(d => d.startPos);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.endPos);\n\t\t\tlet oldStarts = this.oldData.map(d => d.startPos);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tstartPos: oldStarts[i],\n\t\t\t\t\tendPos: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((rectGroup, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateRegion(\n\t\t\t\t\trectGroup, newStarts[i], newPos[i], oldPos[i]\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\theatDomain: {\n\t\tlayerClass: function() { return 'heat-domain domain-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet {index, colWidth, rowHeight, squareSize, xTranslate} = this.constants;\n\t\t\tlet monthNameHeight = -12;\n\t\t\tlet x = xTranslate, y = 0;\n\n\t\t\tthis.serializedSubDomains = [];\n\n\t\t\tdata.cols.map((week, weekNo) => {\n\t\t\t\tif(weekNo === 1) {\n\t\t\t\t\tthis.labels.push(\n\t\t\t\t\t\tmakeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfontSize: 9\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tweek.map((day, i) => {\n\t\t\t\t\tif(day.fill) {\n\t\t\t\t\t\tlet data = {\n\t\t\t\t\t\t\t'data-date': day.yyyyMmDd,\n\t\t\t\t\t\t\t'data-value': day.dataValue,\n\t\t\t\t\t\t\t'data-day': i\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet square = heatSquare('day', x, y, squareSize, day.fill, data);\n\t\t\t\t\t\tthis.serializedSubDomains.push(square);\n\t\t\t\t\t}\n\t\t\t\t\ty += rowHeight;\n\t\t\t\t});\n\t\t\t\ty = 0;\n\t\t\t\tx += colWidth;\n\t\t\t});\n\n\t\t\treturn this.serializedSubDomains;\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\n\tbarGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'bar';\n\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\treturn datasetBar(\n\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\ty,\n\t\t\t\t\tdata.barWidth,\n\t\t\t\t\tc.color,\n\t\t\t\t\tdata.labels[j],\n\t\t\t\t\tj,\n\t\t\t\t\tdata.offsets[j],\n\t\t\t\t\t{\n\t\t\t\t\t\tzeroLine: data.zeroLine,\n\t\t\t\t\t\tbarsWidth: data.barsWidth,\n\t\t\t\t\t\tminHeight: c.minHeight\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn this.units;\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newOffsets = newData.offsets;\n\t\t\tlet newLabels = newData.labels;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldOffsets = this.oldData.offsets;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\toffsets: oldOffsets,\n\t\t\t\tlabels: newLabels,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tbarsWidth: this.oldData.barsWidth,\n\t\t\t\tbarWidth: this.oldData.barWidth,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((bar, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateBar(\n\t\t\t\t\tbar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],\n\t\t\t\t\t{zeroLine: newData.zeroLine}\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\tlineGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'dot';\n\t\t\tthis.paths = {};\n\t\t\tif(!c.hideLine) {\n\t\t\t\tthis.paths = getPaths(\n\t\t\t\t\tdata.xPositions,\n\t\t\t\t\tdata.yPositions,\n\t\t\t\t\tc.color,\n\t\t\t\t\t{\n\t\t\t\t\t\theatline: c.heatline,\n\t\t\t\t\t\tregionFill: c.regionFill\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsvgDefs: c.svgDefs,\n\t\t\t\t\t\tzeroLine: data.zeroLine\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.units = [];\n\t\t\tif(!c.hideDots) {\n\t\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\t\treturn datasetDot(\n\t\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\t\ty,\n\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\tc.color,\n\t\t\t\t\t\t(c.valuesOverPoints ? data.values[j] : ''),\n\t\t\t\t\t\tj\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Object.values(this.paths).concat(this.units);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newValues = newData.values;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldValues = this.oldData.values;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\tvalues: newValues,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tradius: this.oldData.radius,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tif(Object.keys(this.paths).length) {\n\t\t\t\tanimateElements = animateElements.concat(animatePath(\n\t\t\t\t\tthis.paths, newXPos, newYPos, newData.zeroLine));\n\t\t\t}\n\n\t\t\tif(this.units.length) {\n\t\t\t\tthis.units.map((dot, i) => {\n\t\t\t\t\tanimateElements = animateElements.concat(animateDot(\n\t\t\t\t\t\tdot, newXPos[i], newYPos[i]));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn animateElements;\n\t\t}\n\t}\n};\n\nfunction getComponent(name, constants, getData) {\n\tlet keys = Object.keys(componentConfigs).filter(k => name.includes(k));\n\tlet config = componentConfigs[keys[0]];\n\tObject.assign(config, {\n\t\tconstants: constants,\n\t\tgetData: getData\n\t});\n\treturn new ChartComponent(config);\n}\n\nclass PercentageChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'percentage';\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.barOptions = options.barOptions || {};\n\n\t\tlet b = this.barOptions;\n\t\tb.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;\n\t\tb.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;\n\n\t\tm.paddings.right = 30;\n\t\tm.legendHeight = 80;\n\t\tm.baseHeight = (b.height + b.depth * 0.5) * 8;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'percentageBars',\n\t\t\t\t{\n\t\t\t\t\tbarHeight: this.barOptions.height,\n\t\t\t\t\tbarDepth: this.barOptions.depth,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xPositions,\n\t\t\t\t\t\twidths: s.widths,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\n\t\ts.xPositions = [];\n\t\ts.widths = [];\n\n\t\tlet xPos = 0;\n\t\ts.sliceTotals.map((value) => {\n\t\t\tlet width = this.width * value / s.grandTotal;\n\t\t\ts.widths.push(width);\n\t\t\ts.xPositions.push(xPos);\n\t\t\txPos += width;\n\t\t});\n\t}\n\n\tmakeDataByIndex() { }\n\n\tbindTooltip() {\n\t\tlet s = this.state;\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet bars = this.components.get('percentageBars').store;\n\t\t\tlet bar = e.target;\n\t\t\tif(bars.includes(bar)) {\n\n\t\t\t\tlet i = bars.indexOf(bar);\n\t\t\t\tlet gOff = getOffset(this.container), pOff = getOffset(bar);\n\n\t\t\t\tlet x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;\n\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\tlet title = (this.formattedLabels && this.formattedLabels.length>0\n\t\t\t\t\t? this.formattedLabels[i] : this.state.labels[i]) + ': ';\n\t\t\t\tlet fraction = s.sliceTotals[i]/s.grandTotal;\n\n\t\t\t\tthis.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + \"%\"});\n\t\t\t\tthis.tip.showTip();\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass PieChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'pie';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius = (this.height > this.width ? this.center.x : this.center.y);\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath = makeArcPathStr(curStart, curEnd, this.center, this.radius, this.clockWise);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'pieSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{radius,hoverRadio} = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.fill = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.fill = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('pieSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n\nfunction normalize(x) {\n\t// Calculates mantissa and exponent of a number\n\t// Returns normalized number and exponent\n\t// https://stackoverflow.com/q/9383593/6495043\n\n\tif(x===0) {\n\t\treturn [0, 0];\n\t}\n\tif(isNaN(x)) {\n\t\treturn {mantissa: -6755399441055744, exponent: 972};\n\t}\n\tvar sig = x > 0 ? 1 : -1;\n\tif(!isFinite(x)) {\n\t\treturn {mantissa: sig * 4503599627370496, exponent: 972};\n\t}\n\n\tx = Math.abs(x);\n\tvar exp = Math.floor(Math.log10(x));\n\tvar man = x/Math.pow(10, exp);\n\n\treturn [sig * man, exp];\n}\n\nfunction getChartRangeIntervals(max, min=0) {\n\tlet upperBound = Math.ceil(max);\n\tlet lowerBound = Math.floor(min);\n\tlet range = upperBound - lowerBound;\n\n\tlet noOfParts = range;\n\tlet partSize = 1;\n\n\t// To avoid too many partitions\n\tif(range > 5) {\n\t\tif(range % 2 !== 0) {\n\t\t\tupperBound++;\n\t\t\t// Recalc range\n\t\t\trange = upperBound - lowerBound;\n\t\t}\n\t\tnoOfParts = range/2;\n\t\tpartSize = 2;\n\t}\n\n\t// Special case: 1 and 2\n\tif(range <= 2) {\n\t\tnoOfParts = 4;\n\t\tpartSize = range/noOfParts;\n\t}\n\n\t// Special case: 0\n\tif(range === 0) {\n\t\tnoOfParts = 5;\n\t\tpartSize = 1;\n\t}\n\n\tlet intervals = [];\n\tfor(var i = 0; i <= noOfParts; i++){\n\t\tintervals.push(lowerBound + partSize * i);\n\t}\n\treturn intervals;\n}\n\nfunction getChartIntervals(maxValue, minValue=0) {\n\tlet [normalMaxValue, exponent] = normalize(maxValue);\n\tlet normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;\n\n\t// Allow only 7 significant digits\n\tnormalMaxValue = normalMaxValue.toFixed(6);\n\n\tlet intervals = getChartRangeIntervals(normalMaxValue, normalMinValue);\n\tintervals = intervals.map(value => value * Math.pow(10, exponent));\n\treturn intervals;\n}\n\nfunction calcChartIntervals(values, withMinimum=false) {\n\t//*** Where the magic happens ***\n\n\t// Calculates best-fit y intervals from given values\n\t// and returns the interval array\n\n\tlet maxValue = Math.max(...values);\n\tlet minValue = Math.min(...values);\n\n\t// Exponent to be used for pretty print\n\tlet exponent = 0, intervals = []; // eslint-disable-line no-unused-vars\n\n\tfunction getPositiveFirstIntervals(maxValue, absMinValue) {\n\t\tlet intervals = getChartIntervals(maxValue);\n\n\t\tlet intervalSize = intervals[1] - intervals[0];\n\n\t\t// Then unshift the negative values\n\t\tlet value = 0;\n\t\tfor(var i = 1; value < absMinValue; i++) {\n\t\t\tvalue += intervalSize;\n\t\t\tintervals.unshift((-1) * value);\n\t\t}\n\t\treturn intervals;\n\t}\n\n\t// CASE I: Both non-negative\n\n\tif(maxValue >= 0 && minValue >= 0) {\n\t\texponent = normalize(maxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(maxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(maxValue, minValue);\n\t\t}\n\t}\n\n\t// CASE II: Only minValue negative\n\n\telse if(maxValue > 0 && minValue < 0) {\n\t\t// `withMinimum` irrelevant in this case,\n\t\t// We'll be handling both sides of zero separately\n\t\t// (both starting from zero)\n\t\t// Because ceil() and floor() behave differently\n\t\t// in those two regions\n\n\t\tlet absMinValue = Math.abs(minValue);\n\n\t\tif(maxValue >= absMinValue) {\n\t\t\texponent = normalize(maxValue)[1];\n\t\t\tintervals = getPositiveFirstIntervals(maxValue, absMinValue);\n\t\t} else {\n\t\t\t// Mirror: maxValue => absMinValue, then change sign\n\t\t\texponent = normalize(absMinValue)[1];\n\t\t\tlet posIntervals = getPositiveFirstIntervals(absMinValue, maxValue);\n\t\t\tintervals = posIntervals.map(d => d * (-1));\n\t\t}\n\n\t}\n\n\t// CASE III: Both non-positive\n\n\telse if(maxValue <= 0 && minValue <= 0) {\n\t\t// Mirrored Case I:\n\t\t// Work with positives, then reverse the sign and array\n\n\t\tlet pseudoMaxValue = Math.abs(minValue);\n\t\tlet pseudoMinValue = Math.abs(maxValue);\n\n\t\texponent = normalize(pseudoMaxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);\n\t\t}\n\n\t\tintervals = intervals.reverse().map(d => d * (-1));\n\t}\n\n\treturn intervals;\n}\n\nfunction getZeroIndex(yPts) {\n\tlet zeroIndex;\n\tlet interval = getIntervalSize(yPts);\n\tif(yPts.indexOf(0) >= 0) {\n\t\t// the range has a given zero\n\t\t// zero-line on the chart\n\t\tzeroIndex = yPts.indexOf(0);\n\t} else if(yPts[0] > 0) {\n\t\t// Minimum value is positive\n\t\t// zero-line is off the chart: below\n\t\tlet min = yPts[0];\n\t\tzeroIndex = (-1) * min / interval;\n\t} else {\n\t\t// Maximum value is negative\n\t\t// zero-line is off the chart: above\n\t\tlet max = yPts[yPts.length - 1];\n\t\tzeroIndex = (-1) * max / interval + (yPts.length - 1);\n\t}\n\treturn zeroIndex;\n}\n\n\n\nfunction getIntervalSize(orderedArray) {\n\treturn orderedArray[1] - orderedArray[0];\n}\n\nfunction getValueRange(orderedArray) {\n\treturn orderedArray[orderedArray.length-1] - orderedArray[0];\n}\n\nfunction scale(val, yAxis) {\n\treturn floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier);\n}\n\n\n\n\n\nfunction getClosestInArray(goal, arr, index = false) {\n\tlet closest = arr.reduce(function(prev, curr) {\n\t\treturn (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);\n\t});\n\n\treturn index ? arr.indexOf(closest) : closest;\n}\n\nfunction calcDistribution(values, distributionSize) {\n\t// Assume non-negative values,\n\t// implying distribution minimum at zero\n\n\tlet dataMaxValue = Math.max(...values);\n\n\tlet distributionStep = 1 / (distributionSize - 1);\n\tlet distribution = [];\n\n\tfor(var i = 0; i < distributionSize; i++) {\n\t\tlet checkpoint = dataMaxValue * (distributionStep * i);\n\t\tdistribution.push(checkpoint);\n\t}\n\n\treturn distribution;\n}\n\nfunction getMaxCheckpoint(value, distribution) {\n\treturn distribution.filter(d => d < value).length;\n}\n\nconst COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;\nconst ROW_HEIGHT = COL_WIDTH;\n// const DAY_INCR = 1;\n\nclass Heatmap extends BaseChart {\n\tconstructor(parent, options) {\n\t\tsuper(parent, options);\n\t\tthis.type = 'heatmap';\n\n\t\tthis.countLabel = options.countLabel || '';\n\n\t\tlet validStarts = ['Sunday', 'Monday'];\n\t\tlet startSubDomain = validStarts.includes(options.startSubDomain)\n\t\t\t? options.startSubDomain : 'Sunday';\n\t\tthis.startSubDomainIndex = validStarts.indexOf(startSubDomain);\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.discreteDomains = options.discreteDomains === 0 ? 0 : 1;\n\n\t\tm.paddings.top = ROW_HEIGHT * 3;\n\t\tm.paddings.bottom = 0;\n\t\tm.legendHeight = ROW_HEIGHT * 2;\n\t\tm.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK\n\t\t\t+ getExtraHeight(m);\n\n\t\tlet d = this.data;\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tthis.independentWidth = (getWeeksBetween(d.start, d.end)\n\t\t\t+ spacing) * COL_WIDTH + getExtraWidth(m);\n\t}\n\n\tupdateWidth() {\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tlet noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52;\n\t\tthis.baseWidth = (noOfWeeks + spacing) * COL_WIDTH\n\t\t\t+ getExtraWidth(this.measures);\n\t}\n\n\tprepareData(data=this.data) {\n\t\tif(data.start && data.end && data.start > data.end) {\n\t\t\tthrow new Error('Start date cannot be greater than end date.');\n\t\t}\n\n\t\tif(!data.start) {\n\t\t\tdata.start = new Date();\n\t\t\tdata.start.setFullYear( data.start.getFullYear() - 1 );\n\t\t}\n\t\tif(!data.end) { data.end = new Date(); }\n\t\tdata.dataPoints = data.dataPoints || {};\n\n\t\tif(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {\n\t\t\tlet points = {};\n\t\t\tObject.keys(data.dataPoints).forEach(timestampSec$$1 => {\n\t\t\t\tlet date = new Date(timestampSec$$1 * NO_OF_MILLIS);\n\t\t\t\tpoints[getYyyyMmDd(date)] = data.dataPoints[timestampSec$$1];\n\t\t\t});\n\t\t\tdata.dataPoints = points;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\n\t\ts.start = clone(this.data.start);\n\t\ts.end = clone(this.data.end);\n\n\t\ts.firstWeekStart = clone(s.start);\n\t\ts.noOfWeeks = getWeeksBetween(s.start, s.end);\n\t\ts.distribution = calcDistribution(\n\t\t\tObject.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE);\n\n\t\ts.domainConfigs = this.getDomains();\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\t\tlet lessCol = this.discreteDomains ? 0 : 1;\n\n\t\tlet componentConfigs = s.domainConfigs.map((config, i) => [\n\t\t\t'heatDomain',\n\t\t\t{\n\t\t\t\tindex: config.index,\n\t\t\t\tcolWidth: COL_WIDTH,\n\t\t\t\trowHeight: ROW_HEIGHT,\n\t\t\t\tsquareSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\txTranslate: s.domainConfigs\n\t\t\t\t\t.filter((config, j) => j < i)\n\t\t\t\t\t.map(config => config.cols.length - lessCol)\n\t\t\t\t\t.reduce((a, b) => a + b, 0)\n\t\t\t\t\t* COL_WIDTH\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\treturn s.domainConfigs[i];\n\t\t\t}.bind(this)\n\n\t\t]);\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map((args, i) => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0] + '-' + i, component];\n\t\t\t})\n\t\t);\n\n\t\tlet y = 0;\n\t\tDAY_NAMES_SHORT.forEach((dayName, i) => {\n\t\t\tif([1, 3, 5].includes(i)) {\n\t\t\t\tlet dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,\n\t\t\t\t\t{\n\t\t\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\t\t\tdy: 8,\n\t\t\t\t\t\ttextAnchor: 'end'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.drawArea.appendChild(dayText);\n\t\t\t}\n\t\t\ty += ROW_HEIGHT;\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\n\t\tthis.data = this.prepareData(data);\n\t\tthis.draw();\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tthis.components.forEach(comp => {\n\t\t\t\tlet daySquares = comp.store;\n\t\t\t\tlet daySquare = e.target;\n\t\t\t\tif(daySquares.includes(daySquare)) {\n\n\t\t\t\t\tlet count = daySquare.getAttribute('data-value');\n\t\t\t\t\tlet dateParts = daySquare.getAttribute('data-date').split('-');\n\n\t\t\t\t\tlet month = getMonthName(parseInt(dateParts[1])-1, true);\n\n\t\t\t\t\tlet gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();\n\n\t\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\t\tlet x = pOff.left - gOff.left + width/2;\n\t\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\t\tlet value = count + ' ' + this.countLabel;\n\t\t\t\t\tlet name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];\n\n\t\t\t\t\tthis.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);\n\t\t\t\t\tthis.tip.showTip();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\trenderLegend() {\n\t\tthis.legendArea.textContent = '';\n\t\tlet x = 0;\n\t\tlet y = ROW_HEIGHT;\n\n\t\tlet lessText = makeText('subdomain-name', x, y, 'Less',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tx = (COL_WIDTH * 2) + COL_WIDTH/2;\n\t\tthis.legendArea.appendChild(lessText);\n\n\t\tthis.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {\n\t\t\tconst square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i,\n\t\t\t\ty, HEATMAP_SQUARE_SIZE, color);\n\t\t\tthis.legendArea.appendChild(square);\n\t\t});\n\n\t\tlet moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;\n\t\tlet moreText = makeText('subdomain-name', moreTextX, y, 'More',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tthis.legendArea.appendChild(moreText);\n\t}\n\n\tgetDomains() {\n\t\tlet s = this.state;\n\t\tconst [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()];\n\t\tconst [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()];\n\n\t\tconst noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12;\n\n\t\tlet domainConfigs = [];\n\n\t\tlet startOfMonth = clone(s.start);\n\t\tfor(var i = 0; i < noOfMonths; i++) {\n\t\t\tlet endDate = s.end;\n\t\t\tif(!areInSameMonth(startOfMonth, s.end)) {\n\t\t\t\tlet [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];\n\t\t\t\tendDate = getLastDateInMonth(month, year);\n\t\t\t}\n\t\t\tdomainConfigs.push(this.getDomainConfig(startOfMonth, endDate));\n\n\t\t\taddDays(endDate, 1);\n\t\t\tstartOfMonth = endDate;\n\t\t}\n\n\t\treturn domainConfigs;\n\t}\n\n\tgetDomainConfig(startDate, endDate='') {\n\t\tlet [month, year] = [startDate.getMonth(), startDate.getFullYear()];\n\t\tlet startOfWeek = setDayToSunday(startDate); // TODO: Monday as well\n\t\tendDate = clone(endDate) || getLastDateInMonth(month, year);\n\n\t\tlet domainConfig = {\n\t\t\tindex: month,\n\t\t\tcols: []\n\t\t};\n\n\t\taddDays(endDate, 1);\n\t\tlet noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);\n\n\t\tlet cols = [], col;\n\t\tfor(var i = 0; i < noOfMonthWeeks; i++) {\n\t\t\tcol = this.getCol(startOfWeek, month);\n\t\t\tcols.push(col);\n\n\t\t\tstartOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);\n\t\t\taddDays(startOfWeek, 1);\n\t\t}\n\n\t\tif(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {\n\t\t\taddDays(startOfWeek, 1);\n\t\t\tcols.push(this.getCol(startOfWeek, month, true));\n\t\t}\n\n\t\tdomainConfig.cols = cols;\n\n\t\treturn domainConfig;\n\t}\n\n\tgetCol(startDate, month, empty = false) {\n\t\tlet s = this.state;\n\n\t\t// startDate is the start of week\n\t\tlet currentDate = clone(startDate);\n\t\tlet col = [];\n\n\t\tfor(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {\n\t\t\tlet config = {};\n\n\t\t\t// Non-generic adjustment for entire heatmap, needs state\n\t\t\tlet currentDateWithinData = currentDate >= s.start && currentDate <= s.end;\n\n\t\t\tif(empty || currentDate.getMonth() !== month || !currentDateWithinData) {\n\t\t\t\tconfig.yyyyMmDd = getYyyyMmDd(currentDate);\n\t\t\t} else {\n\t\t\t\tconfig = this.getSubDomainConfig(currentDate);\n\t\t\t}\n\t\t\tcol.push(config);\n\t\t}\n\n\t\treturn col;\n\t}\n\n\tgetSubDomainConfig(date) {\n\t\tlet yyyyMmDd = getYyyyMmDd(date);\n\t\tlet dataValue = this.data.dataPoints[yyyyMmDd];\n\t\tlet config = {\n\t\t\tyyyyMmDd: yyyyMmDd,\n\t\t\tdataValue: dataValue || 0,\n\t\t\tfill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]\n\t\t};\n\t\treturn config;\n\t}\n}\n\nfunction dataPrep(data, type) {\n\tdata.labels = data.labels || [];\n\n\tlet datasetLength = data.labels.length;\n\n\t// Datasets\n\tlet datasets = data.datasets;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\tif(!datasets) {\n\t\t// default\n\t\tdatasets = [{\n\t\t\tvalues: zeroArray\n\t\t}];\n\t}\n\n\tdatasets.map(d=> {\n\t\t// Set values\n\t\tif(!d.values) {\n\t\t\td.values = zeroArray;\n\t\t} else {\n\t\t\t// Check for non values\n\t\t\tlet vals = d.values;\n\t\t\tvals = vals.map(val => (!isNaN(val) ? val : 0));\n\n\t\t\t// Trim or extend\n\t\t\tif(vals.length > datasetLength) {\n\t\t\t\tvals = vals.slice(0, datasetLength);\n\t\t\t} else {\n\t\t\t\tvals = fillArray(vals, datasetLength - vals.length, 0);\n\t\t\t}\n\t\t}\n\n\t\t// Set labels\n\t\t//\n\n\t\t// Set type\n\t\tif(!d.chartType ) {\n\t\t\tif(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;\n\t\t\td.chartType = type;\n\t\t}\n\n\t});\n\n\t// Markers\n\n\t// Regions\n\t// data.yRegions = data.yRegions || [];\n\tif(data.yRegions) {\n\t\tdata.yRegions.map(d => {\n\t\t\tif(d.end < d.start) {\n\t\t\t\t[d.start, d.end] = [d.end, d.start];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn data;\n}\n\nfunction zeroDataPrep(realData) {\n\tlet datasetLength = realData.labels.length;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\n\tlet zeroData = {\n\t\tlabels: realData.labels.slice(0, -1),\n\t\tdatasets: realData.datasets.map(d => {\n\t\t\treturn {\n\t\t\t\tname: '',\n\t\t\t\tvalues: zeroArray.slice(0, -1),\n\t\t\t\tchartType: d.chartType\n\t\t\t};\n\t\t}),\n\t};\n\n\tif(realData.yMarkers) {\n\t\tzeroData.yMarkers = [\n\t\t\t{\n\t\t\t\tvalue: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\tif(realData.yRegions) {\n\t\tzeroData.yRegions = [\n\t\t\t{\n\t\t\t\tstart: 0,\n\t\t\t\tend: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\treturn zeroData;\n}\n\nfunction getShortenedLabels(chartWidth, labels=[], isSeries=true) {\n\tlet allowedSpace = chartWidth / labels.length;\n\tif(allowedSpace <= 0) allowedSpace = 1;\n\tlet allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;\n\n\tlet calcLabels = labels.map((label, i) => {\n\t\tlabel += \"\";\n\t\tif(label.length > allowedLetters) {\n\n\t\t\tif(!isSeries) {\n\t\t\t\tif(allowedLetters-3 > 0) {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters-3) + \" ...\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters) + '..';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlet multiple = Math.ceil(label.length/allowedLetters);\n\t\t\t\tif(i % multiple !== 0) {\n\t\t\t\t\tlabel = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn label;\n\t});\n\n\treturn calcLabels;\n}\n\nclass AxisChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\n\t\tthis.barOptions = args.barOptions || {};\n\t\tthis.lineOptions = args.lineOptions || {};\n\n\t\tthis.type = args.type || 'line';\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures() {\n\t\tif(this.data.datasets.length <= 1) {\n\t\t\tthis.config.showLegend = 0;\n\t\t\tthis.measures.paddings.bottom = 30;\n\t\t}\n\t}\n\n\tconfigure(options) {\n\t\tsuper.configure(options);\n\n\t\toptions.axisOptions = options.axisOptions || {};\n\t\toptions.tooltipOptions = options.tooltipOptions || {};\n\n\t\tthis.config.xAxisMode = options.axisOptions.xAxisMode || 'span';\n\t\tthis.config.yAxisMode = options.axisOptions.yAxisMode || 'span';\n\t\tthis.config.xIsSeries = options.axisOptions.xIsSeries || 0;\n\n\t\tthis.config.formatTooltipX = options.tooltipOptions.formatTooltipX;\n\t\tthis.config.formatTooltipY = options.tooltipOptions.formatTooltipY;\n\n\t\tthis.config.valuesOverPoints = options.valuesOverPoints;\n\t}\n\n\tprepareData(data=this.data) {\n\t\treturn dataPrep(data, this.type);\n\t}\n\n\tprepareFirstData(data=this.data) {\n\t\treturn zeroDataPrep(data);\n\t}\n\n\tcalc(onlyWidthChange = false) {\n\t\tthis.calcXPositions();\n\t\tif(!onlyWidthChange) {\n\t\t\tthis.calcYAxisParameters(this.getAllYValues(), this.type === 'line');\n\t\t}\n\t\tthis.makeDataByIndex();\n\t}\n\n\tcalcXPositions() {\n\t\tlet s = this.state;\n\t\tlet labels = this.data.labels;\n\t\ts.datasetLength = labels.length;\n\n\t\ts.unitWidth = this.width/(s.datasetLength);\n\t\t// Default, as per bar, and mixed. Only line will be a special case\n\t\ts.xOffset = s.unitWidth/2;\n\n\t\t// // For a pure Line Chart\n\t\t// s.unitWidth = this.width/(s.datasetLength - 1);\n\t\t// s.xOffset = 0;\n\n\t\ts.xAxis = {\n\t\t\tlabels: labels,\n\t\t\tpositions: labels.map((d, i) =>\n\t\t\t\tfloatTwo(s.xOffset + i * s.unitWidth)\n\t\t\t)\n\t\t};\n\t}\n\n\tcalcYAxisParameters(dataValues, withMinimum = 'false') {\n\t\tconst yPts = calcChartIntervals(dataValues, withMinimum);\n\t\tconst scaleMultiplier = this.height / getValueRange(yPts);\n\t\tconst intervalHeight = getIntervalSize(yPts) * scaleMultiplier;\n\t\tconst zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);\n\n\t\tthis.state.yAxis = {\n\t\t\tlabels: yPts,\n\t\t\tpositions: yPts.map(d => zeroLine - d * scaleMultiplier),\n\t\t\tscaleMultiplier: scaleMultiplier,\n\t\t\tzeroLine: zeroLine,\n\t\t};\n\n\t\t// Dependent if above changes\n\t\tthis.calcDatasetPoints();\n\t\tthis.calcYExtremes();\n\t\tthis.calcYRegions();\n\t}\n\n\tcalcDatasetPoints() {\n\t\tlet s = this.state;\n\t\tlet scaleAll = values => values.map(val => scale(val, s.yAxis));\n\n\t\ts.datasets = this.data.datasets.map((d, i) => {\n\t\t\tlet values = d.values;\n\t\t\tlet cumulativeYs = d.cumulativeYs || [];\n\t\t\treturn {\n\t\t\t\tname: d.name,\n\t\t\t\tindex: i,\n\t\t\t\tchartType: d.chartType,\n\n\t\t\t\tvalues: values,\n\t\t\t\tyPositions: scaleAll(values),\n\n\t\t\t\tcumulativeYs: cumulativeYs,\n\t\t\t\tcumulativeYPos: scaleAll(cumulativeYs),\n\t\t\t};\n\t\t});\n\t}\n\n\tcalcYExtremes() {\n\t\tlet s = this.state;\n\t\tif(this.barOptions.stacked) {\n\t\t\ts.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;\n\t\t\treturn;\n\t\t}\n\t\ts.yExtremes = new Array(s.datasetLength).fill(9999);\n\t\ts.datasets.map(d => {\n\t\t\td.yPositions.map((pos, j) => {\n\t\t\t\tif(pos < s.yExtremes[j]) {\n\t\t\t\t\ts.yExtremes[j] = pos;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tcalcYRegions() {\n\t\tlet s = this.state;\n\t\tif(this.data.yMarkers) {\n\t\t\tthis.state.yMarkers = this.data.yMarkers.map(d => {\n\t\t\t\td.position = scale(d.value, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\t// if(!d.label.includes(':')) {\n\t\t\t\t// \td.label += ': ' + d.value;\n\t\t\t\t// }\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.state.yRegions = this.data.yRegions.map(d => {\n\t\t\t\td.startPos = scale(d.start, s.yAxis);\n\t\t\t\td.endPos = scale(d.end, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t}\n\n\tgetAllYValues() {\n\t\tlet key = 'values';\n\n\t\tif(this.barOptions.stacked) {\n\t\t\tkey = 'cumulativeYs';\n\t\t\tlet cumulative = new Array(this.state.datasetLength).fill(0);\n\t\t\tthis.data.datasets.map((d, i) => {\n\t\t\t\tlet values = this.data.datasets[i].values;\n\t\t\t\td[key] = cumulative = cumulative.map((c, i) => c + values[i]);\n\t\t\t});\n\t\t}\n\n\t\tlet allValueLists = this.data.datasets.map(d => d[key]);\n\t\tif(this.data.yMarkers) {\n\t\t\tallValueLists.push(this.data.yMarkers.map(d => d.value));\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.data.yRegions.map(d => {\n\t\t\t\tallValueLists.push([d.end, d.start]);\n\t\t\t});\n\t\t}\n\n\t\treturn [].concat(...allValueLists);\n\t}\n\n\tsetupComponents() {\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'yAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.yAxisMode,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'xAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.xAxisMode,\n\t\t\t\t\theight: this.height,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\ts.xAxis.calcLabels = getShortenedLabels(this.width,\n\t\t\t\t\t\ts.xAxis.labels, this.config.xIsSeries);\n\n\t\t\t\t\treturn s.xAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'yRegions',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yRegions;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\t\t];\n\n\t\tlet barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');\n\t\tlet lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');\n\n\t\tlet barsConfigs = barDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'barGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tstacked: this.barOptions.stacked,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t\tminHeight: this.height * MIN_BAR_PERCENT_HEIGHT,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet stacked = this.barOptions.stacked;\n\n\t\t\t\t\tlet spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;\n\t\t\t\t\tlet barsWidth = s.unitWidth * (1 - spaceRatio);\n\t\t\t\t\tlet barWidth = barsWidth/(stacked ? 1 : barDatasets.length);\n\n\t\t\t\t\tlet xPositions = s.xAxis.positions.map(x => x - barsWidth/2);\n\t\t\t\t\tif(!stacked) {\n\t\t\t\t\t\txPositions = xPositions.map(p => p + barWidth * index);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet labels = new Array(s.datasetLength).fill('');\n\t\t\t\t\tif(this.config.valuesOverPoints) {\n\t\t\t\t\t\tif(stacked && d.index === s.datasets.length - 1) {\n\t\t\t\t\t\t\tlabels = d.cumulativeYs;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabels = d.values;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet offsets = new Array(s.datasetLength).fill(0);\n\t\t\t\t\tif(stacked) {\n\t\t\t\t\t\toffsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: xPositions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\t\t\t\t\t\toffsets: offsets,\n\t\t\t\t\t\t// values: d.values,\n\t\t\t\t\t\tlabels: labels,\n\n\t\t\t\t\t\tzeroLine: s.yAxis.zeroLine,\n\t\t\t\t\t\tbarsWidth: barsWidth,\n\t\t\t\t\t\tbarWidth: barWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet lineConfigs = lineDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'lineGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tsvgDefs: this.svgDefs,\n\t\t\t\t\theatline: this.lineOptions.heatline,\n\t\t\t\t\tregionFill: this.lineOptions.regionFill,\n\t\t\t\t\thideDots: this.lineOptions.hideDots,\n\t\t\t\t\thideLine: this.lineOptions.hideLine,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet minLine = s.yAxis.positions[0] < s.yAxis.zeroLine\n\t\t\t\t\t\t? s.yAxis.positions[0] : s.yAxis.zeroLine;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xAxis.positions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\n\t\t\t\t\t\tvalues: d.values,\n\n\t\t\t\t\t\tzeroLine: minLine,\n\t\t\t\t\t\tradius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet markerConfigs = [\n\t\t\t[\n\t\t\t\t'yMarkers',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yMarkers;\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tcomponentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);\n\n\t\tlet optionals = ['yMarkers', 'yRegions'];\n\t\tthis.dataUnitComponents = [];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.filter(args => !optionals.includes(args[0]) || this.state[args[0]])\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\tif(args[0].includes('lineGraph') || args[0].includes('barGraph')) {\n\t\t\t\t\tthis.dataUnitComponents.push(component);\n\t\t\t\t}\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tmakeDataByIndex() {\n\t\tthis.dataByIndex = {};\n\n\t\tlet s = this.state;\n\t\tlet formatX = this.config.formatTooltipX;\n\t\tlet formatY = this.config.formatTooltipY;\n\t\tlet titles = s.xAxis.labels;\n\n\t\ttitles.map((label, index) => {\n\t\t\tlet values = this.state.datasets.map((set, i) => {\n\t\t\t\tlet value = set.values[index];\n\t\t\t\treturn {\n\t\t\t\t\ttitle: set.name,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tyPos: set.yPositions[index],\n\t\t\t\t\tcolor: this.colors[i],\n\t\t\t\t\tformatted: formatY ? formatY(value) : value,\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tthis.dataByIndex[index] = {\n\t\t\t\tlabel: label,\n\t\t\t\tformattedLabel: formatX ? formatX(label) : label,\n\t\t\t\txPos: s.xAxis.positions[index],\n\t\t\t\tvalues: values,\n\t\t\t\tyExtreme: s.yExtremes[index],\n\t\t\t};\n\t\t});\n\t}\n\n\tbindTooltip() {\n\t\t// NOTE: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet m = this.measures;\n\t\t\tlet o = getOffset(this.container);\n\t\t\tlet relX = e.pageX - o.left - getLeftOffset(m);\n\t\t\tlet relY = e.pageY - o.top;\n\n\t\t\tif(relY < this.height + getTopOffset(m)\n\t\t\t\t&& relY > getTopOffset(m)) {\n\t\t\t\tthis.mapTooltipXPosition(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hideTip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmapTooltipXPosition(relX) {\n\t\tlet s = this.state;\n\t\tif(!s.yExtremes) return;\n\n\t\tlet index = getClosestInArray(relX, s.xAxis.positions, true);\n\t\tlet dbi = this.dataByIndex[index];\n\n\t\tthis.tip.setValues(\n\t\t\tdbi.xPos + this.tip.offset.x,\n\t\t\tdbi.yExtreme + this.tip.offset.y,\n\t\t\t{name: dbi.formattedLabel, value: ''},\n\t\t\tdbi.values,\n\t\t\tindex\n\t\t);\n\n\t\tthis.tip.showTip();\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.data;\n\t\tif(s.datasets.length > 1) {\n\t\t\tthis.legendArea.textContent = '';\n\t\t\ts.datasets.map((d, i) => {\n\t\t\t\tlet barWidth = AXIS_LEGEND_BAR_SIZE;\n\t\t\t\t// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;\n\t\t\t\t// let multiplier = s.datasets.length - i;\n\t\t\t\tlet rect = legendBar(\n\t\t\t\t\t// rightEndPoint - multiplier * barWidth,\t// To right align\n\t\t\t\t\tbarWidth * i,\n\t\t\t\t\t'0',\n\t\t\t\t\tbarWidth,\n\t\t\t\t\tthis.colors[i],\n\t\t\t\t\td.name);\n\t\t\t\tthis.legendArea.appendChild(rect);\n\t\t\t});\n\t\t}\n\t}\n\n\n\n\t// Overlay\n\tmakeOverlay() {\n\t\tif(this.init) {\n\t\t\tthis.init = 0;\n\t\t\treturn;\n\t\t}\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\n\t\tthis.overlayGuides = this.dataUnitComponents.map(c => {\n\t\t\treturn {\n\t\t\t\ttype: c.unitType,\n\t\t\t\toverlay: undefined,\n\t\t\t\tunits: c.units,\n\t\t\t};\n\t\t});\n\n\t\tif(this.state.currentIndex === undefined) {\n\t\t\tthis.state.currentIndex = this.state.datasetLength - 1;\n\t\t}\n\n\t\t// Render overlays\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\n\t\t\td.overlay = makeOverlay[d.type](currentUnit);\n\t\t\tthis.drawArea.appendChild(d.overlay);\n\t\t});\n\t}\n\n\tupdateOverlayGuides() {\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\t}\n\n\tbindOverlay() {\n\t\tthis.parent.addEventListener('data-select', () => {\n\t\t\tthis.updateOverlay();\n\t\t});\n\t}\n\n\tbindUnits() {\n\t\tthis.dataUnitComponents.map(c => {\n\t\t\tc.units.map(unit => {\n\t\t\t\tunit.addEventListener('click', () => {\n\t\t\t\t\tlet index = unit.getAttribute('data-point-index');\n\t\t\t\t\tthis.setCurrentDataPoint(index);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\t// Note: Doesn't work as tooltip is absolutely positioned\n\t\tthis.tip.container.addEventListener('click', () => {\n\t\t\tlet index = this.tip.container.getAttribute('data-point-index');\n\t\t\tthis.setCurrentDataPoint(index);\n\t\t});\n\t}\n\n\tupdateOverlay() {\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\t\t\tupdateOverlay[d.type](currentUnit, d.overlay);\n\t\t});\n\t}\n\n\tonLeftArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex - 1);\n\t}\n\n\tonRightArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex + 1);\n\t}\n\n\tgetDataPoint(index=this.state.currentIndex) {\n\t\tlet s = this.state;\n\t\tlet data_point = {\n\t\t\tindex: index,\n\t\t\tlabel: s.xAxis.labels[index],\n\t\t\tvalues: s.datasets.map(d => d.values[index])\n\t\t};\n\t\treturn data_point;\n\t}\n\n\tsetCurrentDataPoint(index) {\n\t\tlet s = this.state;\n\t\tindex = parseInt(index);\n\t\tif(index < 0) index = 0;\n\t\tif(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;\n\t\tif(index === s.currentIndex) return;\n\t\ts.currentIndex = index;\n\t\tfire(this.parent, \"data-select\", this.getDataPoint());\n\t}\n\n\n\n\t// API\n\taddDataPoint(label, datasetValues, index=this.state.datasetLength) {\n\t\tsuper.addDataPoint(label, datasetValues, index);\n\t\tthis.data.labels.splice(index, 0, label);\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\td.values.splice(index, 0, datasetValues[i]);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tremoveDataPoint(index = this.state.datasetLength-1) {\n\t\tif (this.data.labels.length <= 1) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.removeDataPoint(index);\n\t\tthis.data.labels.splice(index, 1);\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values.splice(index, 1);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tupdateDataset(datasetValues, index=0) {\n\t\tthis.data.datasets[index].values = datasetValues;\n\t\tthis.update(this.data);\n\t}\n\t// addDataset(dataset, index) {}\n\t// removeDataset(index = 0) {}\n\n\tupdateDatasets(datasets) {\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\tif(datasets[i]) {\n\t\t\t\td.values = datasets[i];\n\t\t\t}\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\t// updateDataPoint(dataPoint, index = 0) {}\n\t// addDataPoint(dataPoint, index = 0) {}\n\t// removeDataPoint(index = 0) {}\n}\n\nconst chartTypes = {\n\tbar: AxisChart,\n\tline: AxisChart,\n\t// multiaxis: MultiAxisChart,\n\tpercentage: PercentageChart,\n\theatmap: Heatmap,\n\tpie: PieChart\n};\n\nfunction getChartByType(chartType = 'line', parent, options) {\n\tif (chartType === 'axis-mixed') {\n\t\toptions.type = 'line';\n\t\treturn new AxisChart(parent, options);\n\t}\n\n\tif (!chartTypes[chartType]) {\n\t\tconsole.error(\"Undefined chart type: \" + chartType);\n\t\treturn;\n\t}\n\n\treturn new chartTypes[chartType](parent, options);\n}\n\nclass Chart {\n\tconstructor(parent, options) {\n\t\treturn getChartByType(options.type, parent, options);\n\t}\n}\n\nexport { Chart, PercentageChart, PieChart, Heatmap, AxisChart };\n","/*\n * This file is part of Flarum.\n *\n * (c) Toby Zerner \n *\n * For the full copyright and license information, please view the LICENSE\n * file that was distributed with this source code.\n */\n\nimport DashboardWidget from 'flarum/components/DashboardWidget';\nimport SelectDropdown from 'flarum/components/SelectDropdown';\nimport Button from 'flarum/components/Button';\nimport icon from 'flarum/helpers/icon';\nimport abbreviateNumber from 'flarum/utils/abbreviateNumber';\n\nimport { Chart } from 'frappe-charts/dist/frappe-charts.esm.js';\n\nexport default class StatisticsWidget extends DashboardWidget {\n oninit(vnode) {\n super.oninit(vnode);\n\n // Create a Date object which represents the start of the day in the\n // configured timezone. To do this we convert a UTC time into that timezone,\n // reset to the first hour of the day, and then convert back into UTC time.\n // We'll be working with seconds rather than milliseconds throughout too.\n let today = new Date();\n today.setTime(today.getTime() + app.data.statistics.timezoneOffset * 1000);\n today.setUTCHours(0, 0, 0, 0);\n today.setTime(today.getTime() - app.data.statistics.timezoneOffset * 1000);\n today = today / 1000;\n\n this.entities = ['users', 'discussions', 'posts'];\n this.periods = {\n today: {start: today, end: today + 86400, step: 3600},\n last_7_days: {start: today - 86400 * 7, end: today, step: 86400},\n last_28_days: {start: today - 86400 * 28, end: today, step: 86400},\n last_12_months: {start: today - 86400 * 364, end: today, step: 86400 * 7}\n };\n\n this.selectedEntity = 'users';\n this.selectedPeriod = 'last_7_days';\n }\n\n className() {\n return 'StatisticsWidget';\n }\n\n content() {\n const thisPeriod = this.periods[this.selectedPeriod];\n\n return (\n
        \n
        \n
        {app.translator.trans('flarum-statistics.admin.statistics.total_label')}
        \n
        \n \n {Object.keys(this.periods).map(period => (\n \n {app.translator.trans(`flarum-statistics.admin.statistics.${period}_label`)}\n \n ))}\n \n
        \n
        \n\n {this.entities.map(entity => {\n const totalCount = this.getTotalCount(entity);\n const thisPeriodCount = this.getPeriodCount(entity, thisPeriod);\n const lastPeriodCount = this.getPeriodCount(entity, this.getLastPeriod(thisPeriod));\n const periodChange = lastPeriodCount > 0 && (thisPeriodCount - lastPeriodCount) / lastPeriodCount * 100;\n\n return (\n \n

        {app.translator.trans('flarum-statistics.admin.statistics.'+entity+'_heading')}

        \n
        {abbreviateNumber(totalCount)}
        \n
        \n {abbreviateNumber(thisPeriodCount)}{' '}\n {periodChange ? (\n 0 ? 'up' : 'down')}>\n {icon('fas fa-arrow-'+(periodChange > 0 ? 'up' : 'down'))}\n {Math.abs(periodChange.toFixed(1))}%\n \n ) : ''}\n
        \n
        \n );\n })}\n\n
        \n
        \n );\n }\n\n drawChart(vnode) {\n if (this.chart && this.entity === this.selectedEntity && this.period === this.selectedPeriod) {\n return;\n }\n\n const offset = app.data.statistics.timezoneOffset;\n const period = this.periods[this.selectedPeriod];\n const periodLength = period.end - period.start;\n const labels = [];\n const thisPeriod = [];\n const lastPeriod = [];\n\n for (let i = period.start; i < period.end; i += period.step) {\n let label;\n\n if (period.step < 86400) {\n label = dayjs.unix(i + offset).format('h A');\n } else {\n label = dayjs.unix(i + offset).format('D MMM');\n\n if (period.step > 86400) {\n label += ' - ' + dayjs.unix(i + offset + period.step - 1).format('D MMM');\n }\n }\n\n labels.push(label);\n\n thisPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i, end: i + period.step}));\n\n lastPeriod.push(this.getPeriodCount(this.selectedEntity, {start: i - periodLength, end: i - periodLength + period.step}));\n }\n\n const datasets = [\n {values: lastPeriod},\n {values: thisPeriod}\n ];\n const data = {\n labels,\n datasets\n };\n\n if (!this.chart) {\n this.chart = new Chart(vnode.dom, {\n data,\n type: 'line',\n height: 280,\n axisOptions: {\n xAxisMode: 'tick',\n yAxisMode: 'span',\n xIsSeries: true\n },\n lineOptions: {\n hideDots: 1\n },\n colors: ['black', app.forum.attribute('themePrimaryColor')]\n });\n } else {\n this.chart.update(data);\n }\n\n this.entity = this.selectedEntity;\n this.period = this.selectedPeriod;\n }\n\n changeEntity(entity) {\n this.selectedEntity = entity;\n }\n\n changePeriod(period) {\n this.selectedPeriod = period;\n }\n\n getTotalCount(entity) {\n return app.data.statistics[entity].total;\n }\n\n getPeriodCount(entity, period) {\n const timed = app.data.statistics[entity].timed;\n let count = 0;\n\n for (const time in timed) {\n if (time >= period.start && time < period.end) {\n count += timed[time];\n }\n }\n\n return count;\n }\n\n getLastPeriod(thisPeriod) {\n return {\n start: thisPeriod.start - (thisPeriod.end - thisPeriod.start),\n end: thisPeriod.start\n };\n }\n}\n","export default function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n subClass.__proto__ = superClass;\n}","import app from 'flarum/app';\nimport { extend } from 'flarum/extend';\n\nimport DashboardPage from 'flarum/components/DashboardPage';\n\nimport StatisticsWidget from './components/StatisticsWidget';\n\napp.initializers.add('flarum-statistics', () => {\n extend(DashboardPage.prototype, 'availableWidgets', widgets => {\n widgets.push();\n });\n});\n"],"sourceRoot":""} \ No newline at end of file