Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

chartogram

Package Overview
Dependencies
Maintainers
1
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

chartogram - npm Package Compare versions

Comparing version 0.1.4 to 0.1.5

commonjs/Chartogram.js

2

bundle/chartogram.js

@@ -1,2 +0,2 @@

!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).chartogram=e()}(this,function(){"use strict";function t(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=[],r=!0,a=!1,i=void 0;try{for(var o,c=t[Symbol.iterator]();!(r=(o=c.next()).done)&&(n.push(o.value),!e||n.length!==e);r=!0);}catch(t){a=!0,i=t}finally{try{r||null==c.return||c.return()}finally{if(a)throw i}}return n}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function e(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{},a=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(a=a.concat(Object.getOwnPropertySymbols(r).filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable}))),a.forEach(function(e){n(t,e,r[e])})}return t}function n(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e<t.length;e++)n[e]=t[e];return n}}(t)||function(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}return function(n,a){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Title",o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};n.innerHTML='\n\t\t<header class="chartogram__header">\n\t\t\t<h1 class="chartogram__title">'.concat(i,'</h1>\n\t\t</header>\n\t\t<div class="chartogram__plan-with-axes">\n\t\t\t<div class="chartogram__plan">\n\t\t\t\t<div class="chartogram__top-border"></div>\n\t\t\t\t<div class="chartogram__canvas-wrapper">\n\t\t\t\t\t<svg class="chartogram__canvas" preserveAspectRatio="none"></svg>\n\t\t\t\t\t<div class="chartogram__x"></div>\n\t\t\t\t\t<div class="chartogram__y-wrapper">\n\t\t\t\t\t\t<div class="chartogram__y"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class="chartogram__timeline">\n\t\t\t<div class="chartogram__timeline-canvas-padding">\n\t\t\t\t<svg class="chartogram__timeline-canvas" preserveAspectRatio="none"></svg>\n\t\t\t</div>\n\t\t\t<div class="chartogram__timeline-overlay-left"></div>\n\t\t\t<div class="chartogram__timeline-overlay-right"></div>\n\t\t\t<div class="chartogram__timeline-window">\n\t\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__drag"></button>\n\t\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__left-handle"></button>\n\t\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__right-handle"></button>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class="chartogram__chart-togglers"></div>\n\t'),n.classList.add("chartogram");var c,l,d,s,u,h,m,v,f,g,p,y,_,b,w,x=o.gaugeMarkTicksCount||6,A=o.timelineWindowSize||40,E=(o.timelineChartMaxPoints,o.months||["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]),L=o.weekdays||["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],S=document.querySelector(".chartogram__plan"),C=document.querySelector(".chartogram__canvas"),M=document.querySelector(".chartogram__canvas-wrapper"),k=document.querySelector(".chartogram__x"),z=document.querySelector(".chartogram__y"),N=document.querySelector(".chartogram__timeline"),T=document.querySelector(".chartogram__timeline-overlay-left"),q=document.querySelector(".chartogram__timeline-window__left-handle"),O=document.querySelector(".chartogram__timeline-window"),j=document.querySelector(".chartogram__timeline-window__drag"),B=document.querySelector(".chartogram__timeline-window__right-handle"),R=document.querySelector(".chartogram__timeline-overlay-right"),X=document.querySelector(".chartogram__timeline-canvas"),D=1;function I(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function Y(t,e){return n=t.map(F),r=e.map(F),n.map(function(t,e){return"".concat(t,",").concat(r[e])});var n,r}function F(t){return Math.round(t*Number.MAX_SAFE_INTEGER)/Number.MAX_SAFE_INTEGER}function P(t,e,n,r){for(var a=0;a<x;){var i=document.createElement("div"),o=e+a*(n-e)/(x-1);r&&(o=r(o)),i.appendChild(document.createTextNode(o)),t.appendChild(i),a++}}function H(t){var e=t[0]===a.x,n=1/0,i=-1/0,o=t,c=Array.isArray(o),l=0;for(o=c?o:o[Symbol.iterator]();;){var d;if(c){if(l>=o.length)break;d=o[l++]}else{if((l=o.next()).done)break;d=l.value}var s=d;e?(s.min=s.points[0],s.max=s.points[s.points.length-1]):(s.min=0,s.max=Math.max.apply(Math,r(s.points))),n=Math.min(n,s.min),i=Math.max(i,s.max)}e||(n=0);var u=n,h=i-n,m=t,v=Array.isArray(m),f=0;for(m=v?m:m[Symbol.iterator]();;){var g;if(v){if(f>=m.length)break;g=m[f++]}else{if((f=m.next()).done)break;g=f.value}var p=g;p.normalized={points:p.points.map(function(t){return(t-u)/h}),shift:u,scale:h}}}function J(n){I(C);var i=a.x.points,o=i[0],g=i[i.length-1],p=g-o,y=o+c*p,_=g-(1-l)*p,b=i.findIndex(function(t){return t>y})-1;b<0&&(b=0);var w=i.findIndex(function(t){return t>_});w<0&&(w=i.length-1),f=a.x.normalized.points.slice(b,w+1);var A=-1/0;s=[];var L=a.y,S=Array.isArray(L),M=0;for(L=S?L:L[Symbol.iterator]();;){var N;if(S){if(M>=L.length)break;N=L[M++]}else{if((M=L.next()).done)break;N=M.value}var T=N;if(d[T.id]){var q=T.points.slice(b,w+1),O=Math.max.apply(Math,r(q));s.push(e({},T,{points:q,min:0,max:O,normalized:e({},T.normalized,{points:T.normalized.points.slice(b,w+1)})})),A=Math.max.apply(Math,[A].concat(r(q)))}}var j=(y-a.x.normalized.shift)/a.x.normalized.scale,B=(_-a.x.normalized.shift)/a.x.normalized.scale,R=(0-a.y[0].normalized.shift)/a.y[0].normalized.scale,F=(A-a.y[0].normalized.shift)/a.y[0].normalized.scale;C.setAttribute("viewBox","".concat(j," ").concat(R," ").concat(B-j," ").concat(F-R));var H=function(t,e){for(;;){if(t<e)return e;if(t%e==0)return t;t--}}(A,10),J=(A-0)/(H-0),K=function(t,e){for(var n=new Array(x),r=0;r<x;)n[r]=t+r*(e-t)/(x-1),r++;return n}(0,H),Q=Array.isArray(K),U=0;for(K=Q?K:K[Symbol.iterator]();;){var V;if(Q){if(U>=K.length)break;V=K[U++]}else{if((U=K.next()).done)break;V=U.value}var Z=V;C.appendChild(W((Z-a.y[0].normalized.shift)/a.y[0].normalized.scale,j,B,R,F))}var $=f.slice(),tt=$[0],et=$[$.length-1],nt=(j-tt)/($[1]-tt),rt=(et-B)/(et-$[$.length-2]);$[0]=j,$[$.length-1]=B;var at=s,it=Array.isArray(at),ot=0;for(at=it?at:at[Symbol.iterator]();;){var ct;if(it){if(ot>=at.length)break;ct=at[ot++]}else{if((ot=at.next()).done)break;ct=ot.value}var lt=ct,dt=(lt.id,lt.color),st=lt.normalized.points.slice(),ut=st[0],ht=st[st.length-1];st[0]=ut+(st[1]-ut)*nt,st[st.length-1]=ht-(ht-st[st.length-2])*rt;var mt=document.createElement("polyline");mt.setAttribute("stroke",dt),mt.setAttribute("points",Y($,st.map(function(t){return F-D*t})).join(" ")),mt.classList.add("chartogram__graph"),C.appendChild(mt)}C.innerHTML+="",function(t,e,n,r,a){I(k),I(z),P(k,t,e,function(t){var e=new Date(t);return"".concat(E[e.getMonth()]," ").concat(e.getDate())}),P(z,n,r),z.style.height="".concat(100/a,"%")}(y,_,0,H,J),m=R,v=F,u=j,h=B,n&&function(){var e=a.x.normalized.points,n=a.y.filter(function(t){return d[t.id]}),i=(Math.min.apply(Math,r(n.map(function(t){return t.min})))-n[0].normalized.shift)/n[0].normalized.scale,o=(Math.max.apply(Math,r(n.map(function(t){return t.max})))-n[0].normalized.shift)/n[0].normalized.scale;I(X),X.setAttribute("viewBox","".concat(0," ").concat(i," ").concat(1," ").concat(o-i));for(var c=n,l=Array.isArray(c),s=0,c=l?c:c[Symbol.iterator]();;){var u;if(l){if(s>=c.length)break;u=c[s++]}else{if((s=c.next()).done)break;u=s.value}var h=u,m=(h.id,h.color),v=h.normalized.points,f=G(e,v,80),g=t(f,2),p=g[0],y=g[1],_=document.createElement("polyline");_.setAttribute("stroke",m),_.setAttribute("points",Y(p,y.map(function(t){return o-i-t})).join(" ")),_.classList.add("chartogram__graph"),X.appendChild(_)}X.innerHTML+=""}()}function W(t,e,n,r,a){var i=document.createElement("line");return i.classList.add("chartogram__grid-line"),i.setAttribute("x1",F(e)),i.setAttribute("x2",F(n)),i.setAttribute("y1",F(a-r-t)),i.setAttribute("y2",F(a-r-t)),i}function G(t,e,n){var a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Math.max.apply(Math,r(e)),i=arguments.length>4&&void 0!==arguments[4]?arguments[4]:.025,o=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,c=arguments.length>6&&void 0!==arguments[6]?arguments[6]:new Array(t.length),l=arguments.length>7&&void 0!==arguments[7]?arguments[7]:new Array(t.length),d=arguments.length>8&&void 0!==arguments[8]?arguments[8]:0;if(o+2>t.length-1){for(;o<e.length;)c[d]=t[o],l[d]=e[o],d++,o++;return c=c.slice(0,d),l=l.slice(0,d),c.length<=n?[c,l]:(t.length/c.length<1.1&&(i=Math.min(i+.025,1)),G(c,l,n,a,i))}var s=(e[o+2]+e[o])/2;return Math.abs(s-e[o+1])/a<i?(c[d]=t[o],c[d+1]=t[o+2],l[d]=e[o],l[d+1]=e[o+2],G(t,e,n,a,i,o+2,c,l,d+1)):(c[d]=t[o],c[d+1]=t[o+1],c[d+2]=t[o+2],l[d]=e[o],l[d+1]=e[o+1],l[d+2]=e[o+2],G(t,e,n,a,i,o+2,c,l,d+2))}function K(t){var e=t.id,n=t.name,r=t.color,a=document.createElement("button");a.setAttribute("type","button"),a.classList.add("chartogram__chart-toggler"),a.classList.add("chartogram__chart-toggler--on"),a.classList.add("chartogram__reset-button");var i="http://www.w3.org/2000/svg",o=document.createElementNS(i,"svg");o.setAttributeNS(null,"viewBox","0 0 19 19"),o.classList.add("chartogram__chart-toggler-check");var c=document.createElementNS(i,"circle");c.setAttribute("cx","9.5"),c.setAttribute("cy","9.5"),c.setAttribute("r","9.5"),c.setAttribute("fill",r),o.appendChild(c);var l=document.createElementNS(i,"circle");l.setAttribute("cx","9.5"),l.setAttribute("cy","9.5"),l.setAttribute("r","8"),l.classList.add("chartogram__chart-toggler-check-circle"),o.appendChild(l);var s=document.createElementNS(i,"path");return s.setAttribute("d","M13.64 4.94l-6.2 6.34-1.69-1.9c-.73-.63-1.89.1-1.36 1.06l2 3.38c.3.43 1.04.85 1.78 0 .32-.42 6.31-7.93 6.31-7.93.74-.84-.2-1.58-.84-.95z"),s.setAttribute("fill","white"),s.classList.add("chartogram__chart-toggler-check-mark"),o.appendChild(s),a.appendChild(o),a.appendChild(document.createTextNode(n)),a.addEventListener("click",function(){var t=!d[e];(t||1!==Object.keys(d).filter(function(t){return!1!==d[t]}).length)&&(d[e]=t,J(!0),a.classList.toggle("chartogram__chart-toggler--on"))}),a}function Q(t){var e,n,r,a,i="left"===t?q:B,o=parseFloat(getComputedStyle(O).borderLeftWidth);return U(i,function(i){e=N.getBoundingClientRect();var c=O.getBoundingClientRect();"left"===t?(n=e.x,r=c.x+c.width-2*o,a=i-c.x):(n=c.x+2*o,r=e.x+e.width,a=i-(c.x+c.width))},function(i){i-=a,i=((i=Math.max(Math.min(i,r),n))-e.x)/e.width,"left"===t?c=i:l=i,V()})}function U(t,e,n){function r(t){n(t.changedTouches[0].clientX,t.changedTouches[0].clientY)}function a(t){n(t.clientX,t.clientY)}function i(){window.removeEventListener("pointermove",a),window.removeEventListener("touchmove",r),window.removeEventListener("pointerup",i),window.removeEventListener("pointercancel",i),window.removeEventListener("touchend",i),window.removeEventListener("touchcancel",i)}function o(t){if(t.touches.length>1)return i();e(t.changedTouches[0].clientX,t.changedTouches[0].clientY),window.addEventListener("touchmove",r),window.addEventListener("touchend",i),window.addEventListener("touchcancel",i)}function c(t){e(t.clientX,t.clientY),window.addEventListener("pointermove",a),window.addEventListener("pointerup",i),window.addEventListener("pointercancel",i)}return t.addEventListener("touchstart",o),t.addEventListener("pointerdown",c),function(){i(),t.removeEventListener(c),t.removeEventListener(o)}}function V(){var t;t=c,T.style.right="".concat(100*(1-t),"%"),O.style.left="".concat(100*t,"%"),function(t){R.style.left="".concat(100*t,"%"),O.style.right="".concat(100*(1-t),"%")}(l),J(!1)}function Z(){g&&(_=void 0,S.removeChild(g),g=void 0,function(){for(var t=b,e=Array.isArray(t),n=0,t=e?t:t[Symbol.iterator]();;){var r;if(e){if(n>=t.length)break;r=t[n++]}else{if((n=t.next()).done)break;r=n.value}var a=r;M.removeChild(a)}b=void 0}(),C.removeChild(w),w=void 0)}Q("left"),Q("right"),U(j,function(t){$=N.getBoundingClientRect(),tt=O.getBoundingClientRect(),rt=t-tt.x,et=$.x,nt=$.x+($.width-tt.width)},function(t){t-=rt,t=((t=Math.max(Math.min(t,nt),et))-$.x)/$.width,c=t,l=t+tt.width/$.width,V()}),H([a.x]),H(a.y),function(){d={};for(var t=a.y,e=Array.isArray(t),n=0,t=e?t:t[Symbol.iterator]();;){var r;if(e){if(n>=t.length)break;r=t[n++]}else{if((n=t.next()).done)break;r=n.value}var i=r;d[i.id]=!0}if(a.x.points.length>A){var o=a.x.points[0],s=a.x.points[a.x.points.length-1],u=a.x.points[a.x.points.length-A];c=(u-o)/(s-o)}else c=0;l=1,V(),J(!0),w=void 0;var h=document.querySelector(".chartogram__chart-togglers");I(h);for(var m=a.y,v=Array.isArray(m),f=0,m=v?m:m[Symbol.iterator]();;){var g;if(v){if(f>=m.length)break;g=m[f++]}else{if((f=m.next()).done)break;g=f.value}var p=g;h.appendChild(K(p))}}(),function(){var t,e;function n(n){var r=(n-t.x)/t.width,i=u+r*(h-u),o=f.findIndex(function(t){return t>=i}),c=o-1;if(e(o)||(o=-1),e(c)||(c=-1),o<0){if(c<0)return Z();i=f[c]}else if(c<0)i=f[o];else{var l=f[c],x=f[o],A=i-l,k=x-i;i=A>k?x:l}if(i!==_){_=i,g||function(){(g=document.createElement("div")).classList.add("chartogram__tooltip"),S.appendChild(g),(p=document.createElement("h1")).classList.add("chartogram__tooltip-header"),g.appendChild(p),(y=document.createElement("dl")).classList.add("chartogram__tooltip-values"),g.appendChild(y);for(var t=a.y,e=Array.isArray(t),n=0,t=e?t:t[Symbol.iterator]();;){var r;if(e){if(n>=t.length)break;r=t[n++]}else{if((n=t.next()).done)break;r=n.value}var i=r;if(d[i.id]){var o=document.createElement("dt");o.style.color=i.color,y.appendChild(o);var c=document.createElement("dd");c.style.color=i.color,y.appendChild(c)}}}();var z=new Date(i*a.x.normalized.scale+a.x.normalized.shift);p.textContent="".concat(L[z.getDay()],", ").concat(E[z.getMonth()]," ").concat(z.getDate());for(var N=f.indexOf(i),T=0;2*T<y.childNodes.length;)y.childNodes[2*T].textContent=s[T].points[N],y.childNodes[2*T+1].textContent=a.y[T].name,T++;var q=(i-u)/(h-u);g.style.left="".concat(100*q,"%"),function(t,e){b||function(){b=[];for(var t=0;t<s.length;){var e=document.createElement("div");e.classList.add("chartogram__tooltip-point"),e.style.color=s[t].color,b.push(e),M.appendChild(e),t++}}();for(var n=0;n<b.length;){var r=b[n];r.style.left="".concat(100*e,"%");var a=s[n].normalized.points[t],i=a/v;r.style.bottom="".concat(100*i,"%"),n++}}(N,q),function(t){w||((w=document.createElementNS("http://www.w3.org/2000/svg","line")).setAttributeNS(null,"class","chartogram__tooltip-line"),C.insertBefore(w,C.querySelector("polyline"))),w.setAttributeNS(null,"x1",F(t)),w.setAttributeNS(null,"x2",F(t)),w.setAttributeNS(null,"y1",F(m)),w.setAttributeNS(null,"y2",F(v))}(i)}}function r(){t=C.getBoundingClientRect(),e=function(t){return!(t<0)&&f[t]>=u&&f[t]<=h}}function i(t){if(t.touches.length>1)return l();r(),C.addEventListener("touchend",l),C.addEventListener("touchmove",o),C.addEventListener("touchend",l),C.addEventListener("touchcancel",l),o(t)}function o(e){var r=e.changedTouches[0].clientX,a=e.changedTouches[0].clientY;r<t.x||r>t.x+t.width||a<t.y||a>t.y+t.height?l():n(r)}function c(t){n(t.clientX,t.clientY)}function l(){C.removeEventListener("pointermove",c),C.removeEventListener("pointerleave",l),C.removeEventListener("pointercancel",l),C.removeEventListener("touchmove",o),C.removeEventListener("touchend",l),C.removeEventListener("touchcancel",l),Z()}function x(){r(),C.addEventListener("pointermove",c),C.addEventListener("pointerleave",l),C.addEventListener("pointercancel",l)}C.addEventListener("touchstart",i),C.addEventListener("pointerenter",x)}();var $,tt,et,nt,rt}});
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t=t||self).chartogram=e()}(this,function(){"use strict";function t(t){return function(t){if(Array.isArray(t)){for(var e=0,i=new Array(t.length);e<t.length;e++)i[e]=t[e];return i}}(t)||function(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function e(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function i(t,e,i,n,a){for(var o=0;o<n;){var r=document.createElement("div"),s=e+o*(i-e)/(n-1);a&&(s=a(s)),r.appendChild(document.createTextNode(s)),t.appendChild(r),o++}}function n(t,e,i){function n(t){i(t.changedTouches[0].clientX,t.changedTouches[0].clientY)}function a(t){i(t.clientX,t.clientY)}function o(){window.removeEventListener("pointermove",a),window.removeEventListener("touchmove",n),window.removeEventListener("pointerup",o),window.removeEventListener("pointercancel",o),window.removeEventListener("touchend",o),window.removeEventListener("touchcancel",o)}function r(t){if(t.touches.length>1)return o();e(t.changedTouches[0].clientX,t.changedTouches[0].clientY),window.addEventListener("touchmove",n),window.addEventListener("touchend",o),window.addEventListener("touchcancel",o)}function s(t){e(t.clientX,t.clientY),window.addEventListener("pointermove",a),window.addEventListener("pointerup",o),window.addEventListener("pointercancel",o)}return t.addEventListener("touchstart",r),t.addEventListener("pointerdown",s),function(){o(),t.removeEventListener(s),t.removeEventListener(r)}}function a(t){return function(t){if(Array.isArray(t)){for(var e=0,i=new Array(t.length);e<t.length;e++)i[e]=t[e];return i}}(t)||function(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function o(t){for(var e=1;e<arguments.length;e++){var i=null!=arguments[e]?arguments[e]:{},n=Object.keys(i);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(i).filter(function(t){return Object.getOwnPropertyDescriptor(i,t).enumerable}))),n.forEach(function(e){l(t,e,i[e])})}return t}function r(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var i=[],n=!0,a=!1,o=void 0;try{for(var r,s=t[Symbol.iterator]();!(n=(r=s.next()).done)&&(i.push(r.value),!e||i.length!==e);n=!0);}catch(t){a=!0,o=t}finally{try{n||null==s.return||s.return()}finally{if(a)throw o}}return i}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function s(t,e){for(var i=0;i<e.length;i++){var n=e[i];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(t,n.key,n)}}function l(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}var c=function(){function c(s,d){var h,u,v,m,p,f=this,g=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Title",y=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,c),l(this,"onResize",function(t){f.setState({aspectRatio:f.getCanvasAspectRatio(),timelineAspectRatio:f.getTimelineCanvasAspectRatio()})}),l(this,"onResizeThrottled",(h=this.onResize,u=33,m=0,p=function(){v=void 0,m=Date.now(),h()},function(){var t=Date.now(),e=u-(t-m);e<=0?(v&&(clearTimeout(v),v=void 0),m=t,h()):v||(v=setTimeout(p,e))})),l(this,"fixSvgCoordinate",function(t){var e=f.props.precisionFactor;return Math.round(t*e)/e}),l(this,"mapX",function(t){var e=f.props.canvasWidth,i=f.state,n=i.minX;return(t-n)/(i.maxX-n)*e}),l(this,"mapY",function(t){var e=f.props.canvasWidth,i=f.state,n=i.minY;return(t-n)/(i.maxY-n)*e/i.aspectRatio}),l(this,"mapXForTimeline",function(t){var e=f.props.canvasWidth,i=f.data,n=i.minX;return(t-n)/(i.maxX-n)*e}),l(this,"mapYForTimeline",function(t){var e=f.props.canvasWidth,i=f.state,n=i.minYGlobal;return(t-n)/(i.maxYGlobal-n)*e/i.timelineAspectRatio}),l(this,"createGridLine",function(t){var e=f.state,i=e.minX,n=e.maxX,a=(e.minY,e.maxY),o=e.yScale,r=document.createElement("line");return r.classList.add("chartogram__grid-line"),r.setAttribute("x1",f.fixSvgCoordinate(f.mapX(i))),r.setAttribute("x2",f.fixSvgCoordinate(f.mapX(n))),r.setAttribute("y1",f.fixSvgCoordinate(f.mapY(a-o*t))),r.setAttribute("y2",f.fixSvgCoordinate(f.mapY(a-o*t))),r}),l(this,"drawGauges",function(t,n,a,o,r){var s=f.props,l=s.gaugeTickMarksCount,c=s.months;e(f.xAxis),e(f.yAxis),i(f.xAxis,t,n,l,function(t){var e=new Date(t);return"".concat(c[e.getMonth()]," ").concat(e.getDate())}),i(f.yAxis,a,o,l),f.yAxis.style.height="".concat(100/r,"%")}),l(this,"renderTimeline",function(){var i=f.props.canvasWidth,n=f.data,a=n.x,o=n.y,s=f.state,l=s.timelineAspectRatio,c=s.maxYGlobal,d=s.yScale;e(f.timelineCanvas),f.timelineCanvas.setAttribute("viewBox","0 0 ".concat(i," ").concat(f.fixSvgCoordinate(i/l)));var h=function(){if(v){if(m>=u.length)return"break";p=u[m++]}else{if((m=u.next()).done)return"break";p=m.value}var e=p,i=e.id,n=e.color,o=e.points;if(f.state.y.find(function(t){return t.id===i}).isShown){var s=r(function e(i,n,a){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Math.max.apply(Math,t(n)),r=arguments.length>4&&void 0!==arguments[4]?arguments[4]:.025,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,l=arguments.length>6&&void 0!==arguments[6]?arguments[6]:new Array(i.length),c=arguments.length>7&&void 0!==arguments[7]?arguments[7]:new Array(i.length),d=arguments.length>8&&void 0!==arguments[8]?arguments[8]:0;if(s+2>i.length-1){for(;s<n.length;)l[d]=i[s],c[d]=n[s],d++,s++;return l=l.slice(0,d),c=c.slice(0,d),l.length<=a?[l,c]:(i.length/l.length<1.1&&(r=Math.min(r+.025,1)),e(l,c,a,o,r))}var h=(n[s+2]+n[s])/2;return Math.abs(h-n[s+1])/o<r?(l[d]=i[s],l[d+1]=i[s+2],c[d]=n[s],c[d+1]=n[s+2],e(i,n,a,o,r,s+2,l,c,d+1)):(l[d]=i[s],l[d+1]=i[s+1],l[d+2]=i[s+2],c[d]=n[s],c[d+1]=n[s+1],c[d+2]=n[s+2],e(i,n,a,o,r,s+2,l,c,d+2))}(a.points,o,80),2),l=s[0],h=s[1],g=document.createElement("polyline");g.setAttribute("stroke",n),g.setAttribute("points",f.createPolylinePoints(l.map(f.mapXForTimeline),h.map(function(t){return f.mapYForTimeline(c-t*d)})).join(" ")),g.classList.add("chartogram__graph"),f.timelineCanvas.appendChild(g)}},u=o,v=Array.isArray(u),m=0;for(u=v?u:u[Symbol.iterator]();;){var p;if("break"===h())break}f.timelineCanvas.innerHTML+=""}),l(this,"createGraphToggler",function(t){var e=t.id,i=t.name,n=t.color,a=document.createElement("button");a.setAttribute("type","button"),a.classList.add("chartogram__chart-toggler"),a.classList.add("chartogram__chart-toggler--on"),a.classList.add("chartogram__reset-button");var r="http://www.w3.org/2000/svg",s=document.createElementNS(r,"svg");s.setAttribute("viewBox","0 0 19 19"),s.setAttribute("class","chartogram__chart-toggler-check");var l=document.createElementNS(r,"circle");l.setAttribute("cx","9.5"),l.setAttribute("cy","9.5"),l.setAttribute("r","9.5"),l.setAttribute("fill",n),s.appendChild(l);var c=document.createElementNS(r,"circle");c.setAttribute("cx","9.5"),c.setAttribute("cy","9.5"),c.setAttribute("r","8"),c.setAttribute("class","chartogram__chart-toggler-check-circle"),s.appendChild(c);var d=document.createElementNS(r,"path");return d.setAttribute("d","M13.64 4.94l-6.2 6.34-1.69-1.9c-.73-.63-1.89.1-1.36 1.06l2 3.38c.3.43 1.04.85 1.78 0 .32-.42 6.31-7.93 6.31-7.93.74-.84-.2-1.58-.84-.95z"),d.setAttribute("fill","white"),d.setAttribute("class","chartogram__chart-toggler-check-mark"),s.appendChild(d),a.appendChild(s),a.appendChild(document.createTextNode(i)),a.addEventListener("click",function(){var t=f.state.y.find(function(t){return t.id===e});if(t.isShown&&1===f.state.y.filter(function(t){return t.isShown}).length)return;t.isShown=!t.isShown,f.setState(o({},f.state,f.calculateMinMaxY(f.state.y))),a.classList.toggle("chartogram__chart-toggler--on")}),a}),l(this,"setUpTimelineWindowHandle",function(t){var e,i,a,o,r="left"===t?f.timelineWindowLeftHandle:f.timelineWindowRightHandle,s=parseFloat(getComputedStyle(f.timelineWindow).borderLeftWidth);return n(r,function(n){e=f.timeline.getBoundingClientRect();var r=f.timelineWindow.getBoundingClientRect();"left"===t?(i=e.left,a=r.left+r.width-2*s,o=n-r.left):(i=r.left+2*s,a=e.left+e.width,o=n-(r.left+r.width))},function(n){n-=o;var r=((n=Math.max(Math.min(n,a),i))-e.left)/e.width;"left"===t?f.updateBounds(r,f.state.toRatio):f.updateBounds(f.state.fromRatio,r)})}),l(this,"setUpTimelineWindow",function(){var t,e,i,a,o;return n(f.timelineWindowDrag,function(n){t=f.timeline.getBoundingClientRect(),e=f.timelineWindow.getBoundingClientRect(),o=n-e.left,i=t.left,a=t.left+(t.width-e.width)},function(n){n-=o;var r=((n=Math.max(Math.min(n,a),i))-t.left)/t.width;f.updateBounds(r,r+e.width/t.width)})}),l(this,"setTimelineWindowLeft",function(t){f.timelineOverlayLeft.style.right="".concat(100*(1-t),"%"),f.timelineWindow.style.left="".concat(100*t,"%")}),l(this,"setTimelineWindowRight",function(t){f.timelineOverlayRight.style.left="".concat(100*t,"%"),f.timelineWindow.style.right="".concat(100*(1-t),"%")}),l(this,"setUpCanvasTooltipListener",function(){var t,e,i=f.props,n=i.weekdays,a=i.months,o=function(i){var o,r=f.state,s=r.minX,l=r.maxX,c=r.xPoints,d=r.y,h=s+(i-t.left)/t.width*(l-s),u=c.findIndex(function(t){return t>=h}),v=u-1;if(e(u)||(u=-1),e(v)||(v=-1),u<0){if(v<0)return f.removeTooltip();o=v}else if(v<0)o=u;else{var m=c[v],p=c[u];o=h-m>p-h?u:v}var g=c[o];if(g!==f.tooltipForX){f.tooltipForX=g,f.tooltip||f.addTooltip();var y=new Date(g);f.tooltipDate.textContent="".concat(n[y.getDay()],", ").concat(a[y.getMonth()]," ").concat(y.getDate());var w=0,b=d,_=Array.isArray(b),x=0;for(b=_?b:b[Symbol.iterator]();;){var S;if(_){if(x>=b.length)break;S=b[x++]}else{if((x=b.next()).done)break;S=x.value}var A=S,L=A.isShown,T=A.points,C=A.name;L&&(f.tooltipValues.childNodes[2*w].textContent=T[o],f.tooltipValues.childNodes[2*w+1].textContent=C,w++)}var E=(g-s)/(l-s);f.tooltip.style.left="".concat(100*E,"%"),f.updateTooltipPoints(o,E),f.updateTooltipLine(g)}},r=function(){t=f.canvas.getBoundingClientRect(),e=function(t){var e=f.state.xPoints;return t>=0&&t<e.length}},s=function(t){if(t.touches.length>1)return d();r(),f.canvas.addEventListener("touchend",d),f.canvas.addEventListener("touchmove",l),f.canvas.addEventListener("touchend",d),f.canvas.addEventListener("touchcancel",d),l(t)};function l(e){var i=e.changedTouches[0].clientX,n=e.changedTouches[0].clientY;i<t.left||i>t.left+t.width||n<t.top||n>t.top+t.height?d():o(i,n)}function c(t){o(t.clientX,t.clientY)}f.canvas.addEventListener("touchstart",s);var d=function t(){f.canvas.removeEventListener("pointermove",c),f.canvas.removeEventListener("pointerleave",t),f.canvas.removeEventListener("pointercancel",t),f.canvas.removeEventListener("touchmove",l),f.canvas.removeEventListener("touchend",t),f.canvas.removeEventListener("touchcancel",t),f.removeTooltip()},h=function(){r(),f.canvas.addEventListener("pointermove",c),f.canvas.addEventListener("pointerleave",d),f.canvas.addEventListener("pointercancel",d)};return f.canvas.addEventListener("pointerenter",h),function(){d(),f.canvas.removeEventListener(h),f.canvas.removeEventListener(s)}}),l(this,"addTooltip",function(){var t=f.state.y;f.tooltip=document.createElement("div"),f.tooltip.classList.add("chartogram__tooltip"),f.tooltipContainer.appendChild(f.tooltip),f.tooltipDate=document.createElement("h1"),f.tooltipDate.classList.add("chartogram__tooltip-header"),f.tooltip.appendChild(f.tooltipDate),f.tooltipValues=document.createElement("dl"),f.tooltipValues.classList.add("chartogram__tooltip-values"),f.tooltip.appendChild(f.tooltipValues);var e=t,i=Array.isArray(e),n=0;for(e=i?e:e[Symbol.iterator]();;){var a;if(i){if(n>=e.length)break;a=e[n++]}else{if((n=e.next()).done)break;a=n.value}var o=a,r=o.isShown,s=o.color;if(r){var l=document.createElement("dt");l.style.color=s,f.tooltipValues.appendChild(l);var c=document.createElement("dd");c.style.color=s,f.tooltipValues.appendChild(c)}}}),l(this,"addTooltipLine",function(){f.tooltipLine=document.createElementNS("http://www.w3.org/2000/svg","line"),f.tooltipLine.setAttributeNS(null,"class","chartogram__tooltip-line"),f.canvas.insertBefore(f.tooltipLine,f.canvas.querySelector("polyline"))}),l(this,"removeTooltip",function(){f.tooltip&&(f.tooltipForX=void 0,f.tooltipContainer.removeChild(f.tooltip),f.tooltip=void 0,f.removeTooltipPoints(),f.removeTooltipLine())}),l(this,"removeTooltipLine",function(){f.canvas.removeChild(f.tooltipLine),f.tooltipLine=void 0}),l(this,"addTooltipPoints",function(){f.tooltipPoints=[];var t=f.state.y,e=Array.isArray(t),i=0;for(t=e?t:t[Symbol.iterator]();;){var n;if(e){if(i>=t.length)break;n=t[i++]}else{if((i=t.next()).done)break;n=i.value}var a=n;if(a.isShown){var o=document.createElement("div");o.classList.add("chartogram__tooltip-point"),o.style.color=a.color,f.tooltipPoints.push(o),f.canvasWrapper.appendChild(o)}}}),l(this,"removeTooltipPoints",function(){var t=f.tooltipPoints,e=Array.isArray(t),i=0;for(t=e?t:t[Symbol.iterator]();;){var n;if(e){if(i>=t.length)break;n=t[i++]}else{if((i=t.next()).done)break;n=i.value}var a=n;f.canvasWrapper.removeChild(a)}f.tooltipPoints=void 0}),l(this,"updateTooltipLine",function(t){var e=f.props.canvasWidth,i=f.state.aspectRatio;f.tooltipLine||f.addTooltipLine(),f.tooltipLine.setAttributeNS(null,"x1",f.fixSvgCoordinate(f.mapX(t))),f.tooltipLine.setAttributeNS(null,"x2",f.fixSvgCoordinate(f.mapX(t))),f.tooltipLine.setAttributeNS(null,"y1",0),f.tooltipLine.setAttributeNS(null,"y2",f.fixSvgCoordinate(e/i))}),l(this,"updateTooltipPoints",function(t,e){var i=f.state,n=i.maxY,a=i.y;f.tooltipPoints||f.addTooltipPoints();for(var o=0;o<f.tooltipPoints.length;){var r=f.tooltipPoints[o],s=a[o].points[t]/n;r.style.left="".concat(100*e,"%"),r.style.bottom="".concat(100*s,"%"),o++}}),this.props=o({title:g,gaugeTickMarksCount:6,timelineWindowSize:40,canvasWidth:512,precisionFactor:Math.pow(10,y.precision||3),months:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},y),this.rootNode=s,this.data=o({},d,{minX:Math.min.apply(Math,a(d.x.points)),maxX:Math.max.apply(Math,a(d.x.points)),y:d.y.map(function(t){return o({},t,{min:Math.min.apply(Math,a(t.points)),max:Math.max.apply(Math,a(t.points))})})})}var d,h,u;return d=c,(h=[{key:"componentDidMount",value:function(){this.rootNode.classList.add("chartogram"),this.rootNode.innerHTML='\n\t\t\t<header class="chartogram__header">\n\t\t\t\t<h1 class="chartogram__title">'.concat(this.props.title,'</h1>\n\t\t\t</header>\n\t\t\t<div class="chartogram__plan-with-axes">\n\t\t\t\t<div class="chartogram__plan">\n\t\t\t\t\t<div class="chartogram__top-border"></div>\n\t\t\t\t\t<div class="chartogram__canvas-wrapper">\n\t\t\t\t\t\t<svg class="chartogram__canvas"></svg>\n\t\t\t\t\t\t<div class="chartogram__x"></div>\n\t\t\t\t\t\t<div class="chartogram__y-wrapper">\n\t\t\t\t\t\t\t<div class="chartogram__y"></div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class="chartogram__timeline">\n\t\t\t\t<div class="chartogram__timeline-canvas-padding">\n\t\t\t\t\t<svg class="chartogram__timeline-canvas" preserveAspectRatio="none"></svg>\n\t\t\t\t</div>\n\t\t\t\t<div class="chartogram__timeline-overlay-left"></div>\n\t\t\t\t<div class="chartogram__timeline-overlay-right"></div>\n\t\t\t\t<div class="chartogram__timeline-window">\n\t\t\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__drag"></button>\n\t\t\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__left-handle"></button>\n\t\t\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__right-handle"></button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class="chartogram__chart-togglers"></div>\n\t\t'),this.tooltipContainer=this.rootNode.querySelector(".chartogram__plan"),this.canvas=this.rootNode.querySelector(".chartogram__canvas"),this.canvasWrapper=this.rootNode.querySelector(".chartogram__canvas-wrapper"),this.xAxis=this.rootNode.querySelector(".chartogram__x"),this.yAxis=this.rootNode.querySelector(".chartogram__y"),this.timeline=this.rootNode.querySelector(".chartogram__timeline"),this.timelineOverlayLeft=this.rootNode.querySelector(".chartogram__timeline-overlay-left"),this.timelineWindowLeftHandle=this.rootNode.querySelector(".chartogram__timeline-window__left-handle"),this.timelineWindow=this.rootNode.querySelector(".chartogram__timeline-window"),this.timelineWindowDrag=this.rootNode.querySelector(".chartogram__timeline-window__drag"),this.timelineWindowRightHandle=this.rootNode.querySelector(".chartogram__timeline-window__right-handle"),this.timelineOverlayRight=this.rootNode.querySelector(".chartogram__timeline-overlay-right"),this.timelineCanvas=this.rootNode.querySelector(".chartogram__timeline-canvas"),this.setUpTimelineWindowHandle("left"),this.setUpTimelineWindowHandle("right"),this.setUpTimelineWindow(),this.setUpCanvasTooltipListener();var t=this.rootNode.querySelector(".chartogram__chart-togglers");e(t);var i=this.data.y,n=Array.isArray(i),a=0;for(i=n?i:i[Symbol.iterator]();;){var o;if(n){if(a>=i.length)break;o=i[a++]}else{if((a=i.next()).done)break;o=a.value}var r=o;t.appendChild(this.createGraphToggler(r))}this.state=this.getInitialState(),this.updateTimelineBounds(this.state.fromRatio,this.state.toRatio),window.addEventListener("resize",this.onResizeThrottled)}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onResizeThrottled)}},{key:"getCanvasAspectRatio",value:function(){var t=this.canvas.getBoundingClientRect();return t.width/t.height}},{key:"getTimelineCanvasAspectRatio",value:function(){var t=this.timelineCanvas.getBoundingClientRect();return t.width/t.height}},{key:"setState",value:function(t,e){this.state=o({},this.state,t),this.render(e)}},{key:"getInitialState",value:function(){var t,e=this.props.timelineWindowSize,i=this.data,n=i.minX,a=i.maxX;t=this.data.x.points.length>e?this.data.x.points.length-e:0;var r=(this.data.x.points[t]-n)/(a-n);return o({},this.createState(r,1),{aspectRatio:this.getCanvasAspectRatio(),timelineAspectRatio:this.getTimelineCanvasAspectRatio(),yScale:1})}},{key:"createState",value:function(t,e){var i,n,r=this,s=this.data.x,l=this.data.minX+t*(this.data.maxX-this.data.minX),c=this.data.minX+e*(this.data.maxX-this.data.minX);i=l===this.data.minX?0:s.points.findIndex(function(t){return t>l})-1,n=c===this.data.maxX?s.points.length-1:s.points.findIndex(function(t){return t>c});var d=s.points.slice(i,n+1),h=d.slice();d.length>=2&&(s.points[i]!==l&&(h[0]=l),s.points[n]!==c&&(h[h.length-1]=c));var u=this.data.y.map(function(t,e){var h=r.data.y[e].points.slice(i,n+1),u=h.slice();if(d.length>=2){if(s.points[i]!==l){var v=r.data.y[e].points[i],m=v+(r.data.y[e].points[i+1]-v)*((l-r.data.x.points[i])/(r.data.x.points[i+1]-r.data.x.points[i]));u[0]=m}if(s.points[n]!==c){var p=r.data.y[e].points[n],f=r.data.y[e].points[n-1],g=f+(p-f)*((c-r.data.x.points[n-1])/(r.data.x.points[n]-r.data.x.points[n-1]));u[u.length-1]=g}}return o({},r.data.y[e],r.state?r.state.y[e]:{isShown:!0},{points:h,graphPoints:u,min:0,max:Math.max.apply(Math,a(u))})});return o({minX:l,maxX:c,fromIndex:i,toIndex:n,fromRatio:t,toRatio:e,xPoints:d,xGraphPoints:h},this.calculateMinMaxY(u),{y:u})}},{key:"calculateMinMaxY",value:function(t){var e=1/0,i=-1/0,n=t,a=Array.isArray(n),o=0;for(n=a?n:n[Symbol.iterator]();;){var r;if(a){if(o>=n.length)break;r=n[o++]}else{if((o=n.next()).done)break;r=o.value}var s=r;s.isShown&&(e=Math.min(e,s.min),i=Math.max(i,s.max))}e=0;var l=1/0,c=-1/0,d=function(){if(u){if(v>=h.length)return"break";m=h[v++]}else{if((v=h.next()).done)return"break";m=v.value}var e=m;t.find(function(t){return t.id===e.id}).isShown&&(l=Math.min(l,e.min),c=Math.max(c,e.max))},h=this.data.y,u=Array.isArray(h),v=0;for(h=u?h:h[Symbol.iterator]();;){var m;if("break"===d())break}return{minY:e,maxY:i,minYGlobal:l=0,maxYGlobal:c}}},{key:"updateTimelineBounds",value:function(t,e){this.setTimelineWindowLeft(t),this.setTimelineWindowRight(e)}},{key:"updateBounds",value:function(t,e){this.updateTimelineBounds(t,e),this.setState(this.createState(t,e),!1)}},{key:"createPolylinePoints",value:function(t,e){return i=t.map(this.fixSvgCoordinate),n=e.map(this.fixSvgCoordinate),i.map(function(t,e){return"".concat(t,",").concat(n[e])});var i,n}},{key:"render",value:function(){var t=this,i=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],n=this.props,a=n.canvasWidth,o=n.gaugeTickMarksCount,r=this.state,s=r.minX,l=r.maxX,c=r.minY,d=r.maxY,h=r.yScale,u=r.xGraphPoints,v=r.aspectRatio;e(this.canvas),this.canvas.setAttribute("viewBox","0 0 ".concat(a," ").concat(this.fixSvgCoordinate(a/v)));var m=c,p=function(t,e){for(t=Math.floor(t);;){if(t<e)return e;if(t%e==0)return t;t--}}(d,10),f=(d-c)/(p-m),g=function(t,e,i){for(var n=new Array(i),a=0;a<i;)n[a]=t+a*(e-t)/(i-1),a++;return n}(m,p,o),y=Array.isArray(g),w=0;for(g=y?g:g[Symbol.iterator]();;){var b;if(y){if(w>=g.length)break;b=g[w++]}else{if((w=g.next()).done)break;b=w.value}var _=b;this.canvas.appendChild(this.createGridLine(_))}var x=this.state.y,S=Array.isArray(x),A=0;for(x=S?x:x[Symbol.iterator]();;){var L;if(S){if(A>=x.length)break;L=x[A++]}else{if((A=x.next()).done)break;L=A.value}var T=L,C=T.color,E=T.graphPoints;if(T.isShown){var k=document.createElement("polyline");k.setAttribute("stroke",C),k.setAttribute("points",this.createPolylinePoints(u.map(this.mapX),E.map(function(e){return t.mapY(d-e*h)})).join(" ")),k.classList.add("chartogram__graph"),this.canvas.appendChild(k)}}this.canvas.innerHTML+="",this.drawGauges(s,l,m,p,f),i&&this.renderTimeline()}}])&&s(d.prototype,h),u&&s(d,u),c}();return function(t,e,i,n){var a=new c(t,e,i,n);return a.componentDidMount(),a.render(),function(){a.componentWillUnmount()}}});
//# sourceMappingURL=chartogram.js.map

@@ -8,1033 +8,14 @@ "use strict";

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
var _Chartogram = _interopRequireDefault(require("./Chartogram"));
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
function chartogram(rootNode, data) {
var title = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'Title';
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// clearElement(rootNode)
rootNode.innerHTML = "\n\t\t<header class=\"chartogram__header\">\n\t\t\t<h1 class=\"chartogram__title\">".concat(title, "</h1>\n\t\t</header>\n\t\t<div class=\"chartogram__plan-with-axes\">\n\t\t\t<div class=\"chartogram__plan\">\n\t\t\t\t<div class=\"chartogram__top-border\"></div>\n\t\t\t\t<div class=\"chartogram__canvas-wrapper\">\n\t\t\t\t\t<svg class=\"chartogram__canvas\" preserveAspectRatio=\"none\"></svg>\n\t\t\t\t\t<div class=\"chartogram__x\"></div>\n\t\t\t\t\t<div class=\"chartogram__y-wrapper\">\n\t\t\t\t\t\t<div class=\"chartogram__y\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"chartogram__timeline\">\n\t\t\t<div class=\"chartogram__timeline-canvas-padding\">\n\t\t\t\t<svg class=\"chartogram__timeline-canvas\" preserveAspectRatio=\"none\"></svg>\n\t\t\t</div>\n\t\t\t<div class=\"chartogram__timeline-overlay-left\"></div>\n\t\t\t<div class=\"chartogram__timeline-overlay-right\"></div>\n\t\t\t<div class=\"chartogram__timeline-window\">\n\t\t\t\t<button type=\"button\" class=\"chartogram__reset-button chartogram__timeline-window__drag\"></button>\n\t\t\t\t<button type=\"button\" class=\"chartogram__reset-button chartogram__timeline-window__left-handle\"></button>\n\t\t\t\t<button type=\"button\" class=\"chartogram__reset-button chartogram__timeline-window__right-handle\"></button>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"chartogram__chart-togglers\"></div>\n\t");
rootNode.classList.add('chartogram');
var GAUGE_TICK_MARKS_COUNT = options.gaugeMarkTicksCount || 6;
var TIMELINE_WINDOW_SIZE = options.timelineWindowSize || 40;
var TIMELINE_CHART_MAX_POINTS = options.timelineChartMaxPoints || 80;
var MONTHS = options.months || ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var WEEKDAYS = options.weekdays || ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var tooltipContainer = document.querySelector('.chartogram__plan');
var canvas = document.querySelector('.chartogram__canvas');
var canvasWrapper = document.querySelector('.chartogram__canvas-wrapper');
var xAxis = document.querySelector('.chartogram__x');
var yAxis = document.querySelector('.chartogram__y');
var timeline = document.querySelector('.chartogram__timeline');
var timelineOverlayLeft = document.querySelector('.chartogram__timeline-overlay-left');
var timelineWindowLeftHandle = document.querySelector('.chartogram__timeline-window__left-handle');
var timelineWindow = document.querySelector('.chartogram__timeline-window');
var timelineWindowDrag = document.querySelector('.chartogram__timeline-window__drag');
var timelineWindowRightHandle = document.querySelector('.chartogram__timeline-window__right-handle');
var timelineOverlayRight = document.querySelector('.chartogram__timeline-overlay-right');
var timelineCanvas = document.querySelector('.chartogram__timeline-canvas');
var timelineWindowFrom;
var timelineWindowTo;
var showGraphs;
var showGraphsNext;
var timelineWindowGraphs;
var timelineWindowMinX;
var timelineWindowMaxX;
var timelineWindowMinY;
var timelineWindowMaxY;
var timelineWindowX;
var tooltip;
var tooltipDate;
var tooltipValues;
var tooltipForX;
var tooltipPoints;
var tooltipLine; // A stub for possible animations.
var yScale = 1;
setUpTimelineWindowHandle('left');
setUpTimelineWindowHandle('right');
setUpTimelineWindow();
normalizeDataPoints();
displayGraphs();
setUpCanvas();
function clearElement(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
function commaJoin(a, b) {
return a.map(function (ai, i) {
return "".concat(ai, ",").concat(b[i]);
});
}
function createPolylinePoints(x, y) {
// return commaJoin(x, y)
return commaJoin(x.map(fixSvgCoordinate), y.map(fixSvgCoordinate));
} // Firefox is buggy with too high and too fractional SVG coordinates.
function fixSvgCoordinate(x) {
return Math.round(x * Number.MAX_SAFE_INTEGER) / Number.MAX_SAFE_INTEGER;
}
function getLowerSiblingDivisibleBy(n, divider) {
while (true) {
if (n < divider) {
return divider;
}
if (n % divider === 0) {
return n;
}
n--;
}
}
function divideInterval(min, max) {
var points = new Array(GAUGE_TICK_MARKS_COUNT);
var i = 0;
while (i < GAUGE_TICK_MARKS_COUNT) {
points[i] = min + i * (max - min) / (GAUGE_TICK_MARKS_COUNT - 1);
i++;
}
return points;
}
function drawGauge(element, min, max, transform) {
var i = 0;
while (i < GAUGE_TICK_MARKS_COUNT) {
var tickMark = document.createElement('div');
var value = min + i * (max - min) / (GAUGE_TICK_MARKS_COUNT - 1);
if (transform) {
value = transform(value);
}
tickMark.appendChild(document.createTextNode(value));
element.appendChild(tickMark);
i++;
}
} // Chrome and Firefox can't handle timestamps in milliseconds for point coordinates (draws nothing).
// Reducing timestamps to lower numbers to work around that bug.
function normalizeDataPoints() {
normalizePoints([data.x]);
normalizePoints(data.y);
}
function normalizePoints(all) {
var isX = all[0] === data.x;
var min = Infinity;
var max = -Infinity;
for (var _iterator = all, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i2 >= _iterator.length) break;
_ref = _iterator[_i2++];
} else {
_i2 = _iterator.next();
if (_i2.done) break;
_ref = _i2.value;
}
var one = _ref;
if (isX) {
one.min = one.points[0];
one.max = one.points[one.points.length - 1];
} else {
// For Y min is always 0 by design.
one.min = 0; // one.min = Math.min(...one.points)
one.max = Math.max.apply(Math, _toConsumableArray(one.points));
}
min = Math.min(min, one.min);
max = Math.max(max, one.max);
} // For Y min is always 0 by design.
if (!isX) {
min = 0;
}
var shift = min;
var scale = max - min;
for (var _iterator2 = all, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i3 >= _iterator2.length) break;
_ref2 = _iterator2[_i3++];
} else {
_i3 = _iterator2.next();
if (_i3.done) break;
_ref2 = _i3.value;
}
var _one = _ref2;
_one.normalized = {
points: _one.points.map(function (_) {
return (_ - shift) / scale;
}),
shift: shift,
scale: scale
};
}
}
function displayGraphs() {
showGraphs = {};
for (var _iterator3 = data.y, _isArray3 = Array.isArray(_iterator3), _i4 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i4 >= _iterator3.length) break;
_ref3 = _iterator3[_i4++];
} else {
_i4 = _iterator3.next();
if (_i4.done) break;
_ref3 = _i4.value;
}
var y = _ref3;
showGraphs[y.id] = true;
}
showGraphsNext = undefined;
if (data.x.points.length > TIMELINE_WINDOW_SIZE) {
var xMin = data.x.points[0];
var xMax = data.x.points[data.x.points.length - 1];
var xFrom = data.x.points[data.x.points.length - TIMELINE_WINDOW_SIZE];
timelineWindowFrom = (xFrom - xMin) / (xMax - xMin);
} else {
timelineWindowFrom = 0;
}
timelineWindowTo = 1;
updateTimelineWindow();
drawGraphs(true);
tooltipLine = undefined; // Add graph togglers.
var graphTogglers = document.querySelector('.chartogram__chart-togglers');
clearElement(graphTogglers);
for (var _iterator4 = data.y, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref4;
if (_isArray4) {
if (_i5 >= _iterator4.length) break;
_ref4 = _iterator4[_i5++];
} else {
_i5 = _iterator4.next();
if (_i5.done) break;
_ref4 = _i5.value;
}
var _y2 = _ref4;
graphTogglers.appendChild(createGraphToggler(_y2));
}
}
function drawGraphs(redrawTimeline) {
// Clear canvas.
clearElement(canvas); // Calculate bounds.
var xPoints = data.x.points;
var minXOverall = xPoints[0];
var maxXOverall = xPoints[xPoints.length - 1];
var deltaX = maxXOverall - minXOverall;
var minX = minXOverall + timelineWindowFrom * deltaX;
var maxX = maxXOverall - (1 - timelineWindowTo) * deltaX;
var minXIndex = xPoints.findIndex(function (x) {
return x > minX;
}) - 1;
if (minXIndex < 0) {
minXIndex = 0;
}
var maxXIndex = xPoints.findIndex(function (x) {
return x > maxX;
});
if (maxXIndex < 0) {
maxXIndex = xPoints.length - 1;
}
timelineWindowX = data.x.normalized.points.slice(minXIndex, maxXIndex + 1); // let minY = Infinity
// Min Y is always 0 by design.
var minY = 0;
var maxY = -Infinity;
timelineWindowGraphs = [];
for (var _iterator5 = data.y, _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
var _ref5;
if (_isArray5) {
if (_i6 >= _iterator5.length) break;
_ref5 = _iterator5[_i6++];
} else {
_i6 = _iterator5.next();
if (_i6.done) break;
_ref5 = _i6.value;
}
var y = _ref5;
if (!showGraphs[y.id]) {
continue;
}
var points = y.points.slice(minXIndex, maxXIndex + 1); // Min Y is always 0 by design.
var min = 0; // const min = Math.min(...points)
var max = Math.max.apply(Math, _toConsumableArray(points));
timelineWindowGraphs.push(_objectSpread({}, y, {
points: points,
min: min,
max: max,
normalized: _objectSpread({}, y.normalized, {
points: y.normalized.points.slice(minXIndex, maxXIndex + 1)
})
})); // minY = Math.min(minY, ...points)
maxY = Math.max.apply(Math, [maxY].concat(_toConsumableArray(points)));
} // Set canvas `viewBox`.
var minXNormalized = (minX - data.x.normalized.shift) / data.x.normalized.scale;
var maxXNormalized = (maxX - data.x.normalized.shift) / data.x.normalized.scale;
var minYNormalized = (minY - data.y[0].normalized.shift) / data.y[0].normalized.scale;
var maxYNormalized = (maxY - data.y[0].normalized.shift) / data.y[0].normalized.scale;
canvas.setAttribute('viewBox', "".concat(minXNormalized, " ").concat(minYNormalized, " ").concat(maxXNormalized - minXNormalized, " ").concat(maxYNormalized - minYNormalized)); // Calculate grid lines' coordinates.
var minY_ = 0;
var maxY_ = getLowerSiblingDivisibleBy(maxY, 10);
var yAxisScale = (maxY - minY) / (maxY_ - minY);
var yAxisTickMarks = divideInterval(minY_, maxY_); // Draw grid lines.
for (var _iterator6 = yAxisTickMarks, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
var _ref6;
if (_isArray6) {
if (_i7 >= _iterator6.length) break;
_ref6 = _iterator6[_i7++];
} else {
_i7 = _iterator6.next();
if (_i7.done) break;
_ref6 = _i7.value;
}
var _y3 = _ref6;
canvas.appendChild(createGridLine((_y3 - data.y[0].normalized.shift) / data.y[0].normalized.scale, minXNormalized, maxXNormalized, minYNormalized, maxYNormalized));
} // Trim X axis.
var _x = timelineWindowX.slice();
var _minX = _x[0];
var _maxX = _x[_x.length - 1];
var trimLeftRatio = (minXNormalized - _minX) / (_x[1] - _minX);
var trimRightRatio = (_maxX - maxXNormalized) / (_maxX - _x[_x.length - 2]);
_x[0] = minXNormalized;
_x[_x.length - 1] = maxXNormalized; // Draw charts.
for (var _iterator7 = timelineWindowGraphs, _isArray7 = Array.isArray(_iterator7), _i8 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) {
var _ref7;
if (_isArray7) {
if (_i8 >= _iterator7.length) break;
_ref7 = _iterator7[_i8++];
} else {
_i8 = _iterator7.next();
if (_i8.done) break;
_ref7 = _i8.value;
}
var _ref8 = _ref7,
id = _ref8.id,
color = _ref8.color,
_points = _ref8.normalized.points;
// Trim chart.
var _y = _points.slice();
var _minY = _y[0];
var _maxY = _y[_y.length - 1];
_y[0] = _minY + (_y[1] - _minY) * trimLeftRatio;
_y[_y.length - 1] = _maxY - (_maxY - _y[_y.length - 2]) * trimRightRatio; // Draw chart.
var graph = document.createElement('polyline');
graph.setAttribute('stroke', color);
graph.setAttribute('points', createPolylinePoints(_x, _y.map(function (y) {
return maxYNormalized - yScale * y;
})).join(' '));
graph.classList.add('chartogram__graph');
canvas.appendChild(graph);
} // A workaround to fix WebKit bug when it's not re-rendering the <svg/>.
// https://stackoverflow.com/questions/30905493/how-to-force-webkit-to-update-svg-use-elements-after-changes-to-original
canvas.innerHTML += ''; // Draw gauges.
drawGauges(minX, maxX, minY_, maxY_, yAxisScale); // Draw timeline graph.
timelineWindowMinY = minYNormalized;
timelineWindowMaxY = maxYNormalized;
timelineWindowMinX = minXNormalized;
timelineWindowMaxX = maxXNormalized;
if (redrawTimeline) {
drawTimeline();
}
} // function animateScale(scale) {
// console.log(scale)
// animateScaleTo = scale
// animateScaleStartedAt = Date.now()
// previousYScale = yScale
// requestAnimationFrame(animateScaleTick)
// }
// function animateScaleTick() {
// const elapsed = Date.now() - animateScaleStartedAt
// yScale = previousYScale + (animateScaleTo - previousYScale) * elapsed / 300
// drawGraphs(true)
// if (elapsed < 300) {
// requestAnimationFrame(animateScaleTick)
// }
// }
function createGridLine(y, minX, maxX, minY, maxY) {
var line = document.createElement('line');
line.classList.add('chartogram__grid-line');
line.setAttribute('x1', fixSvgCoordinate(minX));
line.setAttribute('x2', fixSvgCoordinate(maxX));
line.setAttribute('y1', fixSvgCoordinate(maxY - minY - y));
line.setAttribute('y2', fixSvgCoordinate(maxY - minY - y));
return line;
}
function drawGauges(minX, maxX, minY, maxY, yAxisScale) {
clearElement(xAxis);
clearElement(yAxis);
drawGauge(xAxis, minX, maxX, function (timestamp) {
var date = new Date(timestamp);
return "".concat(MONTHS[date.getMonth()], " ").concat(date.getDate());
});
drawGauge(yAxis, minY, maxY);
yAxis.style.height = "".concat(100 / yAxisScale, "%");
}
function simplifyGraph(x, y, maxPoints) {
var yMax = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Math.max.apply(Math, _toConsumableArray(y));
var threshold = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0.025;
var i = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
var _x = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : new Array(x.length);
var _y = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : new Array(x.length);
var _i = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;
if (i + 2 > x.length - 1) {
while (i < y.length) {
_x[_i] = x[i];
_y[_i] = y[i];
_i++;
i++;
}
_x = _x.slice(0, _i);
_y = _y.slice(0, _i);
if (_x.length <= maxPoints) {
return [_x, _y];
} else {
if (x.length / _x.length < 1.1) {
threshold = Math.min(threshold + 0.025, 1);
}
return simplifyGraph(_x, _y, maxPoints, yMax, threshold);
}
}
var y0 = (y[i + 2] + y[i]) / 2;
if (Math.abs(y0 - y[i + 1]) / yMax < threshold) {
_x[_i] = x[i];
_x[_i + 1] = x[i + 2];
_y[_i] = y[i];
_y[_i + 1] = y[i + 2];
return simplifyGraph(x, y, maxPoints, yMax, threshold, i + 2, _x, _y, _i + 1);
} else {
_x[_i] = x[i];
_x[_i + 1] = x[i + 1];
_x[_i + 2] = x[i + 2];
_y[_i] = y[i];
_y[_i + 1] = y[i + 1];
_y[_i + 2] = y[i + 2];
return simplifyGraph(x, y, maxPoints, yMax, threshold, i + 2, _x, _y, _i + 2);
}
}
function drawTimeline() {
var x = data.x.normalized.points;
var graphs = data.y.filter(function (_) {
return showGraphs[_.id];
});
var minX = 0;
var maxX = 1;
var minY = (Math.min.apply(Math, _toConsumableArray(graphs.map(function (_) {
return _.min;
}))) - graphs[0].normalized.shift) / graphs[0].normalized.scale;
var maxY = (Math.max.apply(Math, _toConsumableArray(graphs.map(function (_) {
return _.max;
}))) - graphs[0].normalized.shift) / graphs[0].normalized.scale;
clearElement(timelineCanvas); // Set canvas `viewBox`.
timelineCanvas.setAttribute('viewBox', "".concat(minX, " ").concat(minY, " ").concat(maxX - minX, " ").concat(maxY - minY));
for (var _iterator8 = graphs, _isArray8 = Array.isArray(_iterator8), _i9 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) {
var _ref9;
if (_isArray8) {
if (_i9 >= _iterator8.length) break;
_ref9 = _iterator8[_i9++];
} else {
_i9 = _iterator8.next();
if (_i9.done) break;
_ref9 = _i9.value;
}
var _ref10 = _ref9,
id = _ref10.id,
color = _ref10.color,
points = _ref10.normalized.points;
var _simplifyGraph = simplifyGraph(x, points, 80),
_simplifyGraph2 = _slicedToArray(_simplifyGraph, 2),
_x = _simplifyGraph2[0],
_y = _simplifyGraph2[1];
var graph = document.createElement('polyline');
graph.setAttribute('stroke', color);
graph.setAttribute('points', createPolylinePoints(_x, _y.map(function (y) {
return maxY - minY - y;
})).join(' '));
graph.classList.add('chartogram__graph');
timelineCanvas.appendChild(graph);
} // A workaround to fix WebKit bug when it's not re-rendering the <svg/>.
// https://stackoverflow.com/questions/30905493/how-to-force-webkit-to-update-svg-use-elements-after-changes-to-original
timelineCanvas.innerHTML += '';
}
function createGraphToggler(_ref11) {
var id = _ref11.id,
name = _ref11.name,
color = _ref11.color;
var toggler = document.createElement('button');
toggler.setAttribute('type', 'button');
toggler.classList.add('chartogram__chart-toggler');
toggler.classList.add('chartogram__chart-toggler--on');
toggler.classList.add('chartogram__reset-button'); // Add check.
var xmlns = 'http://www.w3.org/2000/svg';
var check = document.createElementNS(xmlns, 'svg');
check.setAttributeNS(null, 'viewBox', '0 0 19 19');
check.classList.add('chartogram__chart-toggler-check'); // Add background circle.
var backgroundCircle = document.createElementNS(xmlns, 'circle');
backgroundCircle.setAttribute('cx', '9.5');
backgroundCircle.setAttribute('cy', '9.5');
backgroundCircle.setAttribute('r', '9.5');
backgroundCircle.setAttribute('fill', color);
check.appendChild(backgroundCircle); // Add check circle.
var checkCircle = document.createElementNS(xmlns, 'circle');
checkCircle.setAttribute('cx', '9.5');
checkCircle.setAttribute('cy', '9.5');
checkCircle.setAttribute('r', '8');
checkCircle.classList.add('chartogram__chart-toggler-check-circle');
check.appendChild(checkCircle); // Add check mark.
var checkMark = document.createElementNS(xmlns, 'path');
checkMark.setAttribute('d', 'M13.64 4.94l-6.2 6.34-1.69-1.9c-.73-.63-1.89.1-1.36 1.06l2 3.38c.3.43 1.04.85 1.78 0 .32-.42 6.31-7.93 6.31-7.93.74-.84-.2-1.58-.84-.95z');
checkMark.setAttribute('fill', 'white');
checkMark.classList.add('chartogram__chart-toggler-check-mark');
check.appendChild(checkMark); // Add checkmark.
toggler.appendChild(check); // Add graph name.
toggler.appendChild(document.createTextNode(name)); // On click.
toggler.addEventListener('click', function () {
var show = !showGraphs[id]; // Won't allow hiding all graphs.
if (!show) {
var graphsShown = Object.keys(showGraphs).filter(function (id) {
return showGraphs[id] !== false;
}).length;
if (graphsShown === 1) {
return;
}
}
showGraphs[id] = show;
drawGraphs(true);
toggler.classList.toggle('chartogram__chart-toggler--on');
});
return toggler;
}
function getMaxY(graphs) {
var maxY = 0;
for (var _iterator9 = graphs, _isArray9 = Array.isArray(_iterator9), _i10 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) {
var _ref12;
if (_isArray9) {
if (_i10 >= _iterator9.length) break;
_ref12 = _iterator9[_i10++];
} else {
_i10 = _iterator9.next();
if (_i10.done) break;
_ref12 = _i10.value;
}
var graph = _ref12;
maxY = Math.max.apply(Math, [maxY].concat(_toConsumableArray(graph.points)));
}
return maxY;
}
function setUpTimelineWindowHandle(side) {
var handle = side === 'left' ? timelineWindowLeftHandle : timelineWindowRightHandle;
var handleWidth = parseFloat(getComputedStyle(timelineWindow).borderLeftWidth);
var timelineCoordinates;
var minX;
var maxX;
var deltaX;
var startedX;
function onDrag(x) {
x = x - deltaX;
x = Math.max(Math.min(x, maxX), minX);
x = (x - timelineCoordinates.x) / timelineCoordinates.width;
if (side === 'left') {
timelineWindowFrom = x;
} else {
timelineWindowTo = x;
}
updateTimelineWindow();
}
function onDragStart(x) {
timelineCoordinates = timeline.getBoundingClientRect();
var timelineWindowCoordinates = timelineWindow.getBoundingClientRect();
if (side === 'left') {
minX = timelineCoordinates.x;
maxX = timelineWindowCoordinates.x + timelineWindowCoordinates.width - 2 * handleWidth;
deltaX = x - timelineWindowCoordinates.x;
} else {
minX = timelineWindowCoordinates.x + 2 * handleWidth;
maxX = timelineCoordinates.x + timelineCoordinates.width;
deltaX = x - (timelineWindowCoordinates.x + timelineWindowCoordinates.width);
}
}
return setUpDrag(handle, onDragStart, onDrag);
}
function setUpTimelineWindow() {
var timelineCoordinates;
var timelineWindowCoordinates;
var minX;
var maxX;
var innerX;
function onDrag(x) {
x = x - innerX;
x = Math.max(Math.min(x, maxX), minX);
x = (x - timelineCoordinates.x) / timelineCoordinates.width;
timelineWindowFrom = x;
timelineWindowTo = x + timelineWindowCoordinates.width / timelineCoordinates.width;
updateTimelineWindow();
}
function onDragStart(x) {
timelineCoordinates = timeline.getBoundingClientRect();
timelineWindowCoordinates = timelineWindow.getBoundingClientRect();
innerX = x - timelineWindowCoordinates.x;
minX = timelineCoordinates.x;
maxX = timelineCoordinates.x + (timelineCoordinates.width - timelineWindowCoordinates.width);
}
return setUpDrag(timelineWindowDrag, onDragStart, onDrag);
}
function setUpDrag(element, onDragStart, onDrag) {
function onTouchMove(event) {
onDrag(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
}
function onPointerMove(event) {
onDrag(event.clientX, event.clientY);
}
function onDragStop() {
window.removeEventListener('pointermove', onPointerMove);
window.removeEventListener('touchmove', onTouchMove);
window.removeEventListener('pointerup', onDragStop);
window.removeEventListener('pointercancel', onDragStop);
window.removeEventListener('touchend', onDragStop);
window.removeEventListener('touchcancel', onDragStop);
}
function onTouchStart(event) {
// Ignore multitouch.
if (event.touches.length > 1) {
// Reset.
return onDragStop();
}
onDragStart(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
window.addEventListener('touchmove', onTouchMove);
window.addEventListener('touchend', onDragStop);
window.addEventListener('touchcancel', onDragStop);
} // Safari doesn't support pointer events.
// https://caniuse.com/#feat=pointer
element.addEventListener('touchstart', onTouchStart);
function onPointerDown(event) {
onDragStart(event.clientX, event.clientY);
window.addEventListener('pointermove', onPointerMove);
window.addEventListener('pointerup', onDragStop);
window.addEventListener('pointercancel', onDragStop);
}
element.addEventListener('pointerdown', onPointerDown);
return function () {
onDragStop();
element.removeEventListener(onPointerDown);
element.removeEventListener(onTouchStart);
};
}
function setTimelineWindowLeft(x) {
timelineOverlayLeft.style.right = "".concat(100 * (1 - x), "%");
timelineWindow.style.left = "".concat(100 * x, "%");
}
function setTimelineWindowRight(x) {
timelineOverlayRight.style.left = "".concat(100 * x, "%");
timelineWindow.style.right = "".concat(100 * (1 - x), "%");
}
function updateTimelineWindow() {
setTimelineWindowLeft(timelineWindowFrom);
setTimelineWindowRight(timelineWindowTo);
drawGraphs(false);
}
function setUpCanvas() {
var canvasDimensions;
var isIndexInBounds;
function onTrack(screenX) {
var xScreenRatio = (screenX - canvasDimensions.x) / canvasDimensions.width;
var x = timelineWindowMinX + xScreenRatio * (timelineWindowMaxX - timelineWindowMinX);
var xHigherIndex = timelineWindowX.findIndex(function (_) {
return _ >= x;
});
var xLowerIndex = xHigherIndex - 1;
if (!isIndexInBounds(xHigherIndex)) {
xHigherIndex = -1;
}
if (!isIndexInBounds(xLowerIndex)) {
xLowerIndex = -1;
}
if (xHigherIndex < 0) {
if (xLowerIndex < 0) {
return removeTooltip();
} else {
x = timelineWindowX[xLowerIndex];
}
} else {
if (xLowerIndex < 0) {
x = timelineWindowX[xHigherIndex];
} else {
var xLower = timelineWindowX[xLowerIndex];
var xHigher = timelineWindowX[xHigherIndex];
var deltaLower = x - xLower;
var deltaHigher = xHigher - x;
x = deltaLower > deltaHigher ? xHigher : xLower;
}
}
if (x !== tooltipForX) {
tooltipForX = x;
if (!tooltip) {
addTooltip();
}
var date = new Date(x * data.x.normalized.scale + data.x.normalized.shift);
tooltipDate.textContent = "".concat(WEEKDAYS[date.getDay()], ", ").concat(MONTHS[date.getMonth()], " ").concat(date.getDate());
var xIndex = timelineWindowX.indexOf(x);
var i = 0;
while (2 * i < tooltipValues.childNodes.length) {
tooltipValues.childNodes[2 * i].textContent = timelineWindowGraphs[i].points[xIndex];
tooltipValues.childNodes[2 * i + 1].textContent = data.y[i].name;
i++;
}
var xRatio = (x - timelineWindowMinX) / (timelineWindowMaxX - timelineWindowMinX);
tooltip.style.left = "".concat(xRatio * 100, "%");
updateTooltipPoints(xIndex, xRatio);
updateTooltipLine(x);
}
}
function onTrackStart() {
canvasDimensions = canvas.getBoundingClientRect();
isIndexInBounds = function isIndexInBounds(index) {
if (index < 0) {
return false;
}
return timelineWindowX[index] >= timelineWindowMinX && timelineWindowX[index] <= timelineWindowMaxX;
};
}
function onTouchStart(event) {
// Ignore multitouch.
if (event.touches.length > 1) {
// Reset.
return onTrackStop();
}
onTrackStart();
canvas.addEventListener('touchend', onTrackStop);
canvas.addEventListener('touchmove', onTouchMove);
canvas.addEventListener('touchend', onTrackStop);
canvas.addEventListener('touchcancel', onTrackStop);
onTouchMove(event);
} // Safari doesn't support pointer events.
// https://caniuse.com/#feat=pointer
canvas.addEventListener('touchstart', onTouchStart);
function onTouchMove(event) {
var x = event.changedTouches[0].clientX;
var y = event.changedTouches[0].clientY; // Emulate 'pointerleave' behavior.
if (x < canvasDimensions.x || x > canvasDimensions.x + canvasDimensions.width || y < canvasDimensions.y || y > canvasDimensions.y + canvasDimensions.height) {
onTrackStop();
} else {
onTrack(x, y);
}
}
function onPointerMove(event) {
onTrack(event.clientX, event.clientY);
}
function onTrackStop() {
canvas.removeEventListener('pointermove', onPointerMove);
canvas.removeEventListener('pointerleave', onTrackStop);
canvas.removeEventListener('pointercancel', onTrackStop);
canvas.removeEventListener('touchmove', onTouchMove);
canvas.removeEventListener('touchend', onTrackStop);
canvas.removeEventListener('touchcancel', onTrackStop);
removeTooltip();
}
function onPointerEnter() {
onTrackStart();
canvas.addEventListener('pointermove', onPointerMove);
canvas.addEventListener('pointerleave', onTrackStop);
canvas.addEventListener('pointercancel', onTrackStop);
}
canvas.addEventListener('pointerenter', onPointerEnter);
return function () {
onTrackStop();
canvas.removeEventListener(onPointerEnter);
canvas.removeEventListener(onTouchStart);
};
}
function addTooltip() {
// Create tooltip.
tooltip = document.createElement('div');
tooltip.classList.add('chartogram__tooltip');
tooltipContainer.appendChild(tooltip); // Add tooltip title.
tooltipDate = document.createElement('h1');
tooltipDate.classList.add('chartogram__tooltip-header');
tooltip.appendChild(tooltipDate); // Add graph values.
tooltipValues = document.createElement('dl');
tooltipValues.classList.add('chartogram__tooltip-values');
tooltip.appendChild(tooltipValues); // Add graph values.
for (var _iterator10 = data.y, _isArray10 = Array.isArray(_iterator10), _i11 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) {
var _ref13;
if (_isArray10) {
if (_i11 >= _iterator10.length) break;
_ref13 = _iterator10[_i11++];
} else {
_i11 = _iterator10.next();
if (_i11.done) break;
_ref13 = _i11.value;
}
var y = _ref13;
if (showGraphs[y.id]) {
// Add graph value.
var tooltipValue = document.createElement('dt');
tooltipValue.style.color = y.color;
tooltipValues.appendChild(tooltipValue); // Add graph name.
var tooltipName = document.createElement('dd');
tooltipName.style.color = y.color;
tooltipValues.appendChild(tooltipName);
}
}
}
function removeTooltip() {
if (tooltip) {
tooltipForX = undefined;
tooltipContainer.removeChild(tooltip);
tooltip = undefined;
removeTooltipPoints();
removeTooltipLine();
}
}
function addTooltipLine() {
var xmlns = 'http://www.w3.org/2000/svg';
tooltipLine = document.createElementNS(xmlns, 'line');
tooltipLine.setAttributeNS(null, 'class', 'chartogram__tooltip-line');
canvas.insertBefore(tooltipLine, canvas.querySelector('polyline'));
}
function removeTooltipLine() {
canvas.removeChild(tooltipLine);
tooltipLine = undefined;
}
function addTooltipPoints() {
tooltipPoints = [];
var i = 0;
while (i < timelineWindowGraphs.length) {
var point = document.createElement('div');
point.classList.add('chartogram__tooltip-point');
point.style.color = timelineWindowGraphs[i].color;
tooltipPoints.push(point);
canvasWrapper.appendChild(point);
i++;
}
}
function removeTooltipPoints() {
for (var _iterator11 = tooltipPoints, _isArray11 = Array.isArray(_iterator11), _i12 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) {
var _ref14;
if (_isArray11) {
if (_i12 >= _iterator11.length) break;
_ref14 = _iterator11[_i12++];
} else {
_i12 = _iterator11.next();
if (_i12.done) break;
_ref14 = _i12.value;
}
var point = _ref14;
canvasWrapper.removeChild(point);
}
tooltipPoints = undefined;
}
function updateTooltipLine(x) {
if (!tooltipLine) {
addTooltipLine();
}
tooltipLine.setAttributeNS(null, 'x1', fixSvgCoordinate(x));
tooltipLine.setAttributeNS(null, 'x2', fixSvgCoordinate(x));
tooltipLine.setAttributeNS(null, 'y1', fixSvgCoordinate(timelineWindowMinY));
tooltipLine.setAttributeNS(null, 'y2', fixSvgCoordinate(timelineWindowMaxY));
}
function updateTooltipPoints(xIndex, xRatio) {
if (!tooltipPoints) {
addTooltipPoints();
}
var i = 0;
while (i < tooltipPoints.length) {
var point = tooltipPoints[i];
point.style.left = "".concat(xRatio * 100, "%");
var y = timelineWindowGraphs[i].normalized.points[xIndex];
var yRatio = y / timelineWindowMaxY;
point.style.bottom = "".concat(yRatio * 100, "%");
i++;
}
}
function chartogram(rootNode, data, title, options) {
var chartogram = new _Chartogram.default(rootNode, data, title, options);
chartogram.componentDidMount();
chartogram.render();
return function () {
chartogram.componentWillUnmount();
};
}
//# sourceMappingURL=index.js.map

@@ -1,1032 +0,10 @@

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
export default function chartogram(rootNode, data) {
var title = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'Title';
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// clearElement(rootNode)
rootNode.innerHTML = "\n\t\t<header class=\"chartogram__header\">\n\t\t\t<h1 class=\"chartogram__title\">".concat(title, "</h1>\n\t\t</header>\n\t\t<div class=\"chartogram__plan-with-axes\">\n\t\t\t<div class=\"chartogram__plan\">\n\t\t\t\t<div class=\"chartogram__top-border\"></div>\n\t\t\t\t<div class=\"chartogram__canvas-wrapper\">\n\t\t\t\t\t<svg class=\"chartogram__canvas\" preserveAspectRatio=\"none\"></svg>\n\t\t\t\t\t<div class=\"chartogram__x\"></div>\n\t\t\t\t\t<div class=\"chartogram__y-wrapper\">\n\t\t\t\t\t\t<div class=\"chartogram__y\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"chartogram__timeline\">\n\t\t\t<div class=\"chartogram__timeline-canvas-padding\">\n\t\t\t\t<svg class=\"chartogram__timeline-canvas\" preserveAspectRatio=\"none\"></svg>\n\t\t\t</div>\n\t\t\t<div class=\"chartogram__timeline-overlay-left\"></div>\n\t\t\t<div class=\"chartogram__timeline-overlay-right\"></div>\n\t\t\t<div class=\"chartogram__timeline-window\">\n\t\t\t\t<button type=\"button\" class=\"chartogram__reset-button chartogram__timeline-window__drag\"></button>\n\t\t\t\t<button type=\"button\" class=\"chartogram__reset-button chartogram__timeline-window__left-handle\"></button>\n\t\t\t\t<button type=\"button\" class=\"chartogram__reset-button chartogram__timeline-window__right-handle\"></button>\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"chartogram__chart-togglers\"></div>\n\t");
rootNode.classList.add('chartogram');
var GAUGE_TICK_MARKS_COUNT = options.gaugeMarkTicksCount || 6;
var TIMELINE_WINDOW_SIZE = options.timelineWindowSize || 40;
var TIMELINE_CHART_MAX_POINTS = options.timelineChartMaxPoints || 80;
var MONTHS = options.months || ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
var WEEKDAYS = options.weekdays || ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
var tooltipContainer = document.querySelector('.chartogram__plan');
var canvas = document.querySelector('.chartogram__canvas');
var canvasWrapper = document.querySelector('.chartogram__canvas-wrapper');
var xAxis = document.querySelector('.chartogram__x');
var yAxis = document.querySelector('.chartogram__y');
var timeline = document.querySelector('.chartogram__timeline');
var timelineOverlayLeft = document.querySelector('.chartogram__timeline-overlay-left');
var timelineWindowLeftHandle = document.querySelector('.chartogram__timeline-window__left-handle');
var timelineWindow = document.querySelector('.chartogram__timeline-window');
var timelineWindowDrag = document.querySelector('.chartogram__timeline-window__drag');
var timelineWindowRightHandle = document.querySelector('.chartogram__timeline-window__right-handle');
var timelineOverlayRight = document.querySelector('.chartogram__timeline-overlay-right');
var timelineCanvas = document.querySelector('.chartogram__timeline-canvas');
var timelineWindowFrom;
var timelineWindowTo;
var showGraphs;
var showGraphsNext;
var timelineWindowGraphs;
var timelineWindowMinX;
var timelineWindowMaxX;
var timelineWindowMinY;
var timelineWindowMaxY;
var timelineWindowX;
var tooltip;
var tooltipDate;
var tooltipValues;
var tooltipForX;
var tooltipPoints;
var tooltipLine; // A stub for possible animations.
var yScale = 1;
setUpTimelineWindowHandle('left');
setUpTimelineWindowHandle('right');
setUpTimelineWindow();
normalizeDataPoints();
displayGraphs();
setUpCanvas();
function clearElement(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
function commaJoin(a, b) {
return a.map(function (ai, i) {
return "".concat(ai, ",").concat(b[i]);
});
}
function createPolylinePoints(x, y) {
// return commaJoin(x, y)
return commaJoin(x.map(fixSvgCoordinate), y.map(fixSvgCoordinate));
} // Firefox is buggy with too high and too fractional SVG coordinates.
function fixSvgCoordinate(x) {
return Math.round(x * Number.MAX_SAFE_INTEGER) / Number.MAX_SAFE_INTEGER;
}
function getLowerSiblingDivisibleBy(n, divider) {
while (true) {
if (n < divider) {
return divider;
}
if (n % divider === 0) {
return n;
}
n--;
}
}
function divideInterval(min, max) {
var points = new Array(GAUGE_TICK_MARKS_COUNT);
var i = 0;
while (i < GAUGE_TICK_MARKS_COUNT) {
points[i] = min + i * (max - min) / (GAUGE_TICK_MARKS_COUNT - 1);
i++;
}
return points;
}
function drawGauge(element, min, max, transform) {
var i = 0;
while (i < GAUGE_TICK_MARKS_COUNT) {
var tickMark = document.createElement('div');
var value = min + i * (max - min) / (GAUGE_TICK_MARKS_COUNT - 1);
if (transform) {
value = transform(value);
}
tickMark.appendChild(document.createTextNode(value));
element.appendChild(tickMark);
i++;
}
} // Chrome and Firefox can't handle timestamps in milliseconds for point coordinates (draws nothing).
// Reducing timestamps to lower numbers to work around that bug.
function normalizeDataPoints() {
normalizePoints([data.x]);
normalizePoints(data.y);
}
function normalizePoints(all) {
var isX = all[0] === data.x;
var min = Infinity;
var max = -Infinity;
for (var _iterator = all, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i2 >= _iterator.length) break;
_ref = _iterator[_i2++];
} else {
_i2 = _iterator.next();
if (_i2.done) break;
_ref = _i2.value;
}
var one = _ref;
if (isX) {
one.min = one.points[0];
one.max = one.points[one.points.length - 1];
} else {
// For Y min is always 0 by design.
one.min = 0; // one.min = Math.min(...one.points)
one.max = Math.max.apply(Math, _toConsumableArray(one.points));
}
min = Math.min(min, one.min);
max = Math.max(max, one.max);
} // For Y min is always 0 by design.
if (!isX) {
min = 0;
}
var shift = min;
var scale = max - min;
for (var _iterator2 = all, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i3 >= _iterator2.length) break;
_ref2 = _iterator2[_i3++];
} else {
_i3 = _iterator2.next();
if (_i3.done) break;
_ref2 = _i3.value;
}
var _one = _ref2;
_one.normalized = {
points: _one.points.map(function (_) {
return (_ - shift) / scale;
}),
shift: shift,
scale: scale
};
}
}
function displayGraphs() {
showGraphs = {};
for (var _iterator3 = data.y, _isArray3 = Array.isArray(_iterator3), _i4 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i4 >= _iterator3.length) break;
_ref3 = _iterator3[_i4++];
} else {
_i4 = _iterator3.next();
if (_i4.done) break;
_ref3 = _i4.value;
}
var y = _ref3;
showGraphs[y.id] = true;
}
showGraphsNext = undefined;
if (data.x.points.length > TIMELINE_WINDOW_SIZE) {
var xMin = data.x.points[0];
var xMax = data.x.points[data.x.points.length - 1];
var xFrom = data.x.points[data.x.points.length - TIMELINE_WINDOW_SIZE];
timelineWindowFrom = (xFrom - xMin) / (xMax - xMin);
} else {
timelineWindowFrom = 0;
}
timelineWindowTo = 1;
updateTimelineWindow();
drawGraphs(true);
tooltipLine = undefined; // Add graph togglers.
var graphTogglers = document.querySelector('.chartogram__chart-togglers');
clearElement(graphTogglers);
for (var _iterator4 = data.y, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref4;
if (_isArray4) {
if (_i5 >= _iterator4.length) break;
_ref4 = _iterator4[_i5++];
} else {
_i5 = _iterator4.next();
if (_i5.done) break;
_ref4 = _i5.value;
}
var _y2 = _ref4;
graphTogglers.appendChild(createGraphToggler(_y2));
}
}
function drawGraphs(redrawTimeline) {
// Clear canvas.
clearElement(canvas); // Calculate bounds.
var xPoints = data.x.points;
var minXOverall = xPoints[0];
var maxXOverall = xPoints[xPoints.length - 1];
var deltaX = maxXOverall - minXOverall;
var minX = minXOverall + timelineWindowFrom * deltaX;
var maxX = maxXOverall - (1 - timelineWindowTo) * deltaX;
var minXIndex = xPoints.findIndex(function (x) {
return x > minX;
}) - 1;
if (minXIndex < 0) {
minXIndex = 0;
}
var maxXIndex = xPoints.findIndex(function (x) {
return x > maxX;
});
if (maxXIndex < 0) {
maxXIndex = xPoints.length - 1;
}
timelineWindowX = data.x.normalized.points.slice(minXIndex, maxXIndex + 1); // let minY = Infinity
// Min Y is always 0 by design.
var minY = 0;
var maxY = -Infinity;
timelineWindowGraphs = [];
for (var _iterator5 = data.y, _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
var _ref5;
if (_isArray5) {
if (_i6 >= _iterator5.length) break;
_ref5 = _iterator5[_i6++];
} else {
_i6 = _iterator5.next();
if (_i6.done) break;
_ref5 = _i6.value;
}
var y = _ref5;
if (!showGraphs[y.id]) {
continue;
}
var points = y.points.slice(minXIndex, maxXIndex + 1); // Min Y is always 0 by design.
var min = 0; // const min = Math.min(...points)
var max = Math.max.apply(Math, _toConsumableArray(points));
timelineWindowGraphs.push(_objectSpread({}, y, {
points: points,
min: min,
max: max,
normalized: _objectSpread({}, y.normalized, {
points: y.normalized.points.slice(minXIndex, maxXIndex + 1)
})
})); // minY = Math.min(minY, ...points)
maxY = Math.max.apply(Math, [maxY].concat(_toConsumableArray(points)));
} // Set canvas `viewBox`.
var minXNormalized = (minX - data.x.normalized.shift) / data.x.normalized.scale;
var maxXNormalized = (maxX - data.x.normalized.shift) / data.x.normalized.scale;
var minYNormalized = (minY - data.y[0].normalized.shift) / data.y[0].normalized.scale;
var maxYNormalized = (maxY - data.y[0].normalized.shift) / data.y[0].normalized.scale;
canvas.setAttribute('viewBox', "".concat(minXNormalized, " ").concat(minYNormalized, " ").concat(maxXNormalized - minXNormalized, " ").concat(maxYNormalized - minYNormalized)); // Calculate grid lines' coordinates.
var minY_ = 0;
var maxY_ = getLowerSiblingDivisibleBy(maxY, 10);
var yAxisScale = (maxY - minY) / (maxY_ - minY);
var yAxisTickMarks = divideInterval(minY_, maxY_); // Draw grid lines.
for (var _iterator6 = yAxisTickMarks, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
var _ref6;
if (_isArray6) {
if (_i7 >= _iterator6.length) break;
_ref6 = _iterator6[_i7++];
} else {
_i7 = _iterator6.next();
if (_i7.done) break;
_ref6 = _i7.value;
}
var _y3 = _ref6;
canvas.appendChild(createGridLine((_y3 - data.y[0].normalized.shift) / data.y[0].normalized.scale, minXNormalized, maxXNormalized, minYNormalized, maxYNormalized));
} // Trim X axis.
var _x = timelineWindowX.slice();
var _minX = _x[0];
var _maxX = _x[_x.length - 1];
var trimLeftRatio = (minXNormalized - _minX) / (_x[1] - _minX);
var trimRightRatio = (_maxX - maxXNormalized) / (_maxX - _x[_x.length - 2]);
_x[0] = minXNormalized;
_x[_x.length - 1] = maxXNormalized; // Draw charts.
for (var _iterator7 = timelineWindowGraphs, _isArray7 = Array.isArray(_iterator7), _i8 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) {
var _ref7;
if (_isArray7) {
if (_i8 >= _iterator7.length) break;
_ref7 = _iterator7[_i8++];
} else {
_i8 = _iterator7.next();
if (_i8.done) break;
_ref7 = _i8.value;
}
var _ref8 = _ref7,
id = _ref8.id,
color = _ref8.color,
_points = _ref8.normalized.points;
// Trim chart.
var _y = _points.slice();
var _minY = _y[0];
var _maxY = _y[_y.length - 1];
_y[0] = _minY + (_y[1] - _minY) * trimLeftRatio;
_y[_y.length - 1] = _maxY - (_maxY - _y[_y.length - 2]) * trimRightRatio; // Draw chart.
var graph = document.createElement('polyline');
graph.setAttribute('stroke', color);
graph.setAttribute('points', createPolylinePoints(_x, _y.map(function (y) {
return maxYNormalized - yScale * y;
})).join(' '));
graph.classList.add('chartogram__graph');
canvas.appendChild(graph);
} // A workaround to fix WebKit bug when it's not re-rendering the <svg/>.
// https://stackoverflow.com/questions/30905493/how-to-force-webkit-to-update-svg-use-elements-after-changes-to-original
canvas.innerHTML += ''; // Draw gauges.
drawGauges(minX, maxX, minY_, maxY_, yAxisScale); // Draw timeline graph.
timelineWindowMinY = minYNormalized;
timelineWindowMaxY = maxYNormalized;
timelineWindowMinX = minXNormalized;
timelineWindowMaxX = maxXNormalized;
if (redrawTimeline) {
drawTimeline();
}
} // function animateScale(scale) {
// console.log(scale)
// animateScaleTo = scale
// animateScaleStartedAt = Date.now()
// previousYScale = yScale
// requestAnimationFrame(animateScaleTick)
// }
// function animateScaleTick() {
// const elapsed = Date.now() - animateScaleStartedAt
// yScale = previousYScale + (animateScaleTo - previousYScale) * elapsed / 300
// drawGraphs(true)
// if (elapsed < 300) {
// requestAnimationFrame(animateScaleTick)
// }
// }
function createGridLine(y, minX, maxX, minY, maxY) {
var line = document.createElement('line');
line.classList.add('chartogram__grid-line');
line.setAttribute('x1', fixSvgCoordinate(minX));
line.setAttribute('x2', fixSvgCoordinate(maxX));
line.setAttribute('y1', fixSvgCoordinate(maxY - minY - y));
line.setAttribute('y2', fixSvgCoordinate(maxY - minY - y));
return line;
}
function drawGauges(minX, maxX, minY, maxY, yAxisScale) {
clearElement(xAxis);
clearElement(yAxis);
drawGauge(xAxis, minX, maxX, function (timestamp) {
var date = new Date(timestamp);
return "".concat(MONTHS[date.getMonth()], " ").concat(date.getDate());
});
drawGauge(yAxis, minY, maxY);
yAxis.style.height = "".concat(100 / yAxisScale, "%");
}
function simplifyGraph(x, y, maxPoints) {
var yMax = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : Math.max.apply(Math, _toConsumableArray(y));
var threshold = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0.025;
var i = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 0;
var _x = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : new Array(x.length);
var _y = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : new Array(x.length);
var _i = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : 0;
if (i + 2 > x.length - 1) {
while (i < y.length) {
_x[_i] = x[i];
_y[_i] = y[i];
_i++;
i++;
}
_x = _x.slice(0, _i);
_y = _y.slice(0, _i);
if (_x.length <= maxPoints) {
return [_x, _y];
} else {
if (x.length / _x.length < 1.1) {
threshold = Math.min(threshold + 0.025, 1);
}
return simplifyGraph(_x, _y, maxPoints, yMax, threshold);
}
}
var y0 = (y[i + 2] + y[i]) / 2;
if (Math.abs(y0 - y[i + 1]) / yMax < threshold) {
_x[_i] = x[i];
_x[_i + 1] = x[i + 2];
_y[_i] = y[i];
_y[_i + 1] = y[i + 2];
return simplifyGraph(x, y, maxPoints, yMax, threshold, i + 2, _x, _y, _i + 1);
} else {
_x[_i] = x[i];
_x[_i + 1] = x[i + 1];
_x[_i + 2] = x[i + 2];
_y[_i] = y[i];
_y[_i + 1] = y[i + 1];
_y[_i + 2] = y[i + 2];
return simplifyGraph(x, y, maxPoints, yMax, threshold, i + 2, _x, _y, _i + 2);
}
}
function drawTimeline() {
var x = data.x.normalized.points;
var graphs = data.y.filter(function (_) {
return showGraphs[_.id];
});
var minX = 0;
var maxX = 1;
var minY = (Math.min.apply(Math, _toConsumableArray(graphs.map(function (_) {
return _.min;
}))) - graphs[0].normalized.shift) / graphs[0].normalized.scale;
var maxY = (Math.max.apply(Math, _toConsumableArray(graphs.map(function (_) {
return _.max;
}))) - graphs[0].normalized.shift) / graphs[0].normalized.scale;
clearElement(timelineCanvas); // Set canvas `viewBox`.
timelineCanvas.setAttribute('viewBox', "".concat(minX, " ").concat(minY, " ").concat(maxX - minX, " ").concat(maxY - minY));
for (var _iterator8 = graphs, _isArray8 = Array.isArray(_iterator8), _i9 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) {
var _ref9;
if (_isArray8) {
if (_i9 >= _iterator8.length) break;
_ref9 = _iterator8[_i9++];
} else {
_i9 = _iterator8.next();
if (_i9.done) break;
_ref9 = _i9.value;
}
var _ref10 = _ref9,
id = _ref10.id,
color = _ref10.color,
points = _ref10.normalized.points;
var _simplifyGraph = simplifyGraph(x, points, 80),
_simplifyGraph2 = _slicedToArray(_simplifyGraph, 2),
_x = _simplifyGraph2[0],
_y = _simplifyGraph2[1];
var graph = document.createElement('polyline');
graph.setAttribute('stroke', color);
graph.setAttribute('points', createPolylinePoints(_x, _y.map(function (y) {
return maxY - minY - y;
})).join(' '));
graph.classList.add('chartogram__graph');
timelineCanvas.appendChild(graph);
} // A workaround to fix WebKit bug when it's not re-rendering the <svg/>.
// https://stackoverflow.com/questions/30905493/how-to-force-webkit-to-update-svg-use-elements-after-changes-to-original
timelineCanvas.innerHTML += '';
}
function createGraphToggler(_ref11) {
var id = _ref11.id,
name = _ref11.name,
color = _ref11.color;
var toggler = document.createElement('button');
toggler.setAttribute('type', 'button');
toggler.classList.add('chartogram__chart-toggler');
toggler.classList.add('chartogram__chart-toggler--on');
toggler.classList.add('chartogram__reset-button'); // Add check.
var xmlns = 'http://www.w3.org/2000/svg';
var check = document.createElementNS(xmlns, 'svg');
check.setAttributeNS(null, 'viewBox', '0 0 19 19');
check.classList.add('chartogram__chart-toggler-check'); // Add background circle.
var backgroundCircle = document.createElementNS(xmlns, 'circle');
backgroundCircle.setAttribute('cx', '9.5');
backgroundCircle.setAttribute('cy', '9.5');
backgroundCircle.setAttribute('r', '9.5');
backgroundCircle.setAttribute('fill', color);
check.appendChild(backgroundCircle); // Add check circle.
var checkCircle = document.createElementNS(xmlns, 'circle');
checkCircle.setAttribute('cx', '9.5');
checkCircle.setAttribute('cy', '9.5');
checkCircle.setAttribute('r', '8');
checkCircle.classList.add('chartogram__chart-toggler-check-circle');
check.appendChild(checkCircle); // Add check mark.
var checkMark = document.createElementNS(xmlns, 'path');
checkMark.setAttribute('d', 'M13.64 4.94l-6.2 6.34-1.69-1.9c-.73-.63-1.89.1-1.36 1.06l2 3.38c.3.43 1.04.85 1.78 0 .32-.42 6.31-7.93 6.31-7.93.74-.84-.2-1.58-.84-.95z');
checkMark.setAttribute('fill', 'white');
checkMark.classList.add('chartogram__chart-toggler-check-mark');
check.appendChild(checkMark); // Add checkmark.
toggler.appendChild(check); // Add graph name.
toggler.appendChild(document.createTextNode(name)); // On click.
toggler.addEventListener('click', function () {
var show = !showGraphs[id]; // Won't allow hiding all graphs.
if (!show) {
var graphsShown = Object.keys(showGraphs).filter(function (id) {
return showGraphs[id] !== false;
}).length;
if (graphsShown === 1) {
return;
}
}
showGraphs[id] = show;
drawGraphs(true);
toggler.classList.toggle('chartogram__chart-toggler--on');
});
return toggler;
}
function getMaxY(graphs) {
var maxY = 0;
for (var _iterator9 = graphs, _isArray9 = Array.isArray(_iterator9), _i10 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) {
var _ref12;
if (_isArray9) {
if (_i10 >= _iterator9.length) break;
_ref12 = _iterator9[_i10++];
} else {
_i10 = _iterator9.next();
if (_i10.done) break;
_ref12 = _i10.value;
}
var graph = _ref12;
maxY = Math.max.apply(Math, [maxY].concat(_toConsumableArray(graph.points)));
}
return maxY;
}
function setUpTimelineWindowHandle(side) {
var handle = side === 'left' ? timelineWindowLeftHandle : timelineWindowRightHandle;
var handleWidth = parseFloat(getComputedStyle(timelineWindow).borderLeftWidth);
var timelineCoordinates;
var minX;
var maxX;
var deltaX;
var startedX;
function onDrag(x) {
x = x - deltaX;
x = Math.max(Math.min(x, maxX), minX);
x = (x - timelineCoordinates.x) / timelineCoordinates.width;
if (side === 'left') {
timelineWindowFrom = x;
} else {
timelineWindowTo = x;
}
updateTimelineWindow();
}
function onDragStart(x) {
timelineCoordinates = timeline.getBoundingClientRect();
var timelineWindowCoordinates = timelineWindow.getBoundingClientRect();
if (side === 'left') {
minX = timelineCoordinates.x;
maxX = timelineWindowCoordinates.x + timelineWindowCoordinates.width - 2 * handleWidth;
deltaX = x - timelineWindowCoordinates.x;
} else {
minX = timelineWindowCoordinates.x + 2 * handleWidth;
maxX = timelineCoordinates.x + timelineCoordinates.width;
deltaX = x - (timelineWindowCoordinates.x + timelineWindowCoordinates.width);
}
}
return setUpDrag(handle, onDragStart, onDrag);
}
function setUpTimelineWindow() {
var timelineCoordinates;
var timelineWindowCoordinates;
var minX;
var maxX;
var innerX;
function onDrag(x) {
x = x - innerX;
x = Math.max(Math.min(x, maxX), minX);
x = (x - timelineCoordinates.x) / timelineCoordinates.width;
timelineWindowFrom = x;
timelineWindowTo = x + timelineWindowCoordinates.width / timelineCoordinates.width;
updateTimelineWindow();
}
function onDragStart(x) {
timelineCoordinates = timeline.getBoundingClientRect();
timelineWindowCoordinates = timelineWindow.getBoundingClientRect();
innerX = x - timelineWindowCoordinates.x;
minX = timelineCoordinates.x;
maxX = timelineCoordinates.x + (timelineCoordinates.width - timelineWindowCoordinates.width);
}
return setUpDrag(timelineWindowDrag, onDragStart, onDrag);
}
function setUpDrag(element, onDragStart, onDrag) {
function onTouchMove(event) {
onDrag(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
}
function onPointerMove(event) {
onDrag(event.clientX, event.clientY);
}
function onDragStop() {
window.removeEventListener('pointermove', onPointerMove);
window.removeEventListener('touchmove', onTouchMove);
window.removeEventListener('pointerup', onDragStop);
window.removeEventListener('pointercancel', onDragStop);
window.removeEventListener('touchend', onDragStop);
window.removeEventListener('touchcancel', onDragStop);
}
function onTouchStart(event) {
// Ignore multitouch.
if (event.touches.length > 1) {
// Reset.
return onDragStop();
}
onDragStart(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
window.addEventListener('touchmove', onTouchMove);
window.addEventListener('touchend', onDragStop);
window.addEventListener('touchcancel', onDragStop);
} // Safari doesn't support pointer events.
// https://caniuse.com/#feat=pointer
element.addEventListener('touchstart', onTouchStart);
function onPointerDown(event) {
onDragStart(event.clientX, event.clientY);
window.addEventListener('pointermove', onPointerMove);
window.addEventListener('pointerup', onDragStop);
window.addEventListener('pointercancel', onDragStop);
}
element.addEventListener('pointerdown', onPointerDown);
return function () {
onDragStop();
element.removeEventListener(onPointerDown);
element.removeEventListener(onTouchStart);
};
}
function setTimelineWindowLeft(x) {
timelineOverlayLeft.style.right = "".concat(100 * (1 - x), "%");
timelineWindow.style.left = "".concat(100 * x, "%");
}
function setTimelineWindowRight(x) {
timelineOverlayRight.style.left = "".concat(100 * x, "%");
timelineWindow.style.right = "".concat(100 * (1 - x), "%");
}
function updateTimelineWindow() {
setTimelineWindowLeft(timelineWindowFrom);
setTimelineWindowRight(timelineWindowTo);
drawGraphs(false);
}
function setUpCanvas() {
var canvasDimensions;
var isIndexInBounds;
function onTrack(screenX) {
var xScreenRatio = (screenX - canvasDimensions.x) / canvasDimensions.width;
var x = timelineWindowMinX + xScreenRatio * (timelineWindowMaxX - timelineWindowMinX);
var xHigherIndex = timelineWindowX.findIndex(function (_) {
return _ >= x;
});
var xLowerIndex = xHigherIndex - 1;
if (!isIndexInBounds(xHigherIndex)) {
xHigherIndex = -1;
}
if (!isIndexInBounds(xLowerIndex)) {
xLowerIndex = -1;
}
if (xHigherIndex < 0) {
if (xLowerIndex < 0) {
return removeTooltip();
} else {
x = timelineWindowX[xLowerIndex];
}
} else {
if (xLowerIndex < 0) {
x = timelineWindowX[xHigherIndex];
} else {
var xLower = timelineWindowX[xLowerIndex];
var xHigher = timelineWindowX[xHigherIndex];
var deltaLower = x - xLower;
var deltaHigher = xHigher - x;
x = deltaLower > deltaHigher ? xHigher : xLower;
}
}
if (x !== tooltipForX) {
tooltipForX = x;
if (!tooltip) {
addTooltip();
}
var date = new Date(x * data.x.normalized.scale + data.x.normalized.shift);
tooltipDate.textContent = "".concat(WEEKDAYS[date.getDay()], ", ").concat(MONTHS[date.getMonth()], " ").concat(date.getDate());
var xIndex = timelineWindowX.indexOf(x);
var i = 0;
while (2 * i < tooltipValues.childNodes.length) {
tooltipValues.childNodes[2 * i].textContent = timelineWindowGraphs[i].points[xIndex];
tooltipValues.childNodes[2 * i + 1].textContent = data.y[i].name;
i++;
}
var xRatio = (x - timelineWindowMinX) / (timelineWindowMaxX - timelineWindowMinX);
tooltip.style.left = "".concat(xRatio * 100, "%");
updateTooltipPoints(xIndex, xRatio);
updateTooltipLine(x);
}
}
function onTrackStart() {
canvasDimensions = canvas.getBoundingClientRect();
isIndexInBounds = function isIndexInBounds(index) {
if (index < 0) {
return false;
}
return timelineWindowX[index] >= timelineWindowMinX && timelineWindowX[index] <= timelineWindowMaxX;
};
}
function onTouchStart(event) {
// Ignore multitouch.
if (event.touches.length > 1) {
// Reset.
return onTrackStop();
}
onTrackStart();
canvas.addEventListener('touchend', onTrackStop);
canvas.addEventListener('touchmove', onTouchMove);
canvas.addEventListener('touchend', onTrackStop);
canvas.addEventListener('touchcancel', onTrackStop);
onTouchMove(event);
} // Safari doesn't support pointer events.
// https://caniuse.com/#feat=pointer
canvas.addEventListener('touchstart', onTouchStart);
function onTouchMove(event) {
var x = event.changedTouches[0].clientX;
var y = event.changedTouches[0].clientY; // Emulate 'pointerleave' behavior.
if (x < canvasDimensions.x || x > canvasDimensions.x + canvasDimensions.width || y < canvasDimensions.y || y > canvasDimensions.y + canvasDimensions.height) {
onTrackStop();
} else {
onTrack(x, y);
}
}
function onPointerMove(event) {
onTrack(event.clientX, event.clientY);
}
function onTrackStop() {
canvas.removeEventListener('pointermove', onPointerMove);
canvas.removeEventListener('pointerleave', onTrackStop);
canvas.removeEventListener('pointercancel', onTrackStop);
canvas.removeEventListener('touchmove', onTouchMove);
canvas.removeEventListener('touchend', onTrackStop);
canvas.removeEventListener('touchcancel', onTrackStop);
removeTooltip();
}
function onPointerEnter() {
onTrackStart();
canvas.addEventListener('pointermove', onPointerMove);
canvas.addEventListener('pointerleave', onTrackStop);
canvas.addEventListener('pointercancel', onTrackStop);
}
canvas.addEventListener('pointerenter', onPointerEnter);
return function () {
onTrackStop();
canvas.removeEventListener(onPointerEnter);
canvas.removeEventListener(onTouchStart);
};
}
function addTooltip() {
// Create tooltip.
tooltip = document.createElement('div');
tooltip.classList.add('chartogram__tooltip');
tooltipContainer.appendChild(tooltip); // Add tooltip title.
tooltipDate = document.createElement('h1');
tooltipDate.classList.add('chartogram__tooltip-header');
tooltip.appendChild(tooltipDate); // Add graph values.
tooltipValues = document.createElement('dl');
tooltipValues.classList.add('chartogram__tooltip-values');
tooltip.appendChild(tooltipValues); // Add graph values.
for (var _iterator10 = data.y, _isArray10 = Array.isArray(_iterator10), _i11 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) {
var _ref13;
if (_isArray10) {
if (_i11 >= _iterator10.length) break;
_ref13 = _iterator10[_i11++];
} else {
_i11 = _iterator10.next();
if (_i11.done) break;
_ref13 = _i11.value;
}
var y = _ref13;
if (showGraphs[y.id]) {
// Add graph value.
var tooltipValue = document.createElement('dt');
tooltipValue.style.color = y.color;
tooltipValues.appendChild(tooltipValue); // Add graph name.
var tooltipName = document.createElement('dd');
tooltipName.style.color = y.color;
tooltipValues.appendChild(tooltipName);
}
}
}
function removeTooltip() {
if (tooltip) {
tooltipForX = undefined;
tooltipContainer.removeChild(tooltip);
tooltip = undefined;
removeTooltipPoints();
removeTooltipLine();
}
}
function addTooltipLine() {
var xmlns = 'http://www.w3.org/2000/svg';
tooltipLine = document.createElementNS(xmlns, 'line');
tooltipLine.setAttributeNS(null, 'class', 'chartogram__tooltip-line');
canvas.insertBefore(tooltipLine, canvas.querySelector('polyline'));
}
function removeTooltipLine() {
canvas.removeChild(tooltipLine);
tooltipLine = undefined;
}
function addTooltipPoints() {
tooltipPoints = [];
var i = 0;
while (i < timelineWindowGraphs.length) {
var point = document.createElement('div');
point.classList.add('chartogram__tooltip-point');
point.style.color = timelineWindowGraphs[i].color;
tooltipPoints.push(point);
canvasWrapper.appendChild(point);
i++;
}
}
function removeTooltipPoints() {
for (var _iterator11 = tooltipPoints, _isArray11 = Array.isArray(_iterator11), _i12 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) {
var _ref14;
if (_isArray11) {
if (_i12 >= _iterator11.length) break;
_ref14 = _iterator11[_i12++];
} else {
_i12 = _iterator11.next();
if (_i12.done) break;
_ref14 = _i12.value;
}
var point = _ref14;
canvasWrapper.removeChild(point);
}
tooltipPoints = undefined;
}
function updateTooltipLine(x) {
if (!tooltipLine) {
addTooltipLine();
}
tooltipLine.setAttributeNS(null, 'x1', fixSvgCoordinate(x));
tooltipLine.setAttributeNS(null, 'x2', fixSvgCoordinate(x));
tooltipLine.setAttributeNS(null, 'y1', fixSvgCoordinate(timelineWindowMinY));
tooltipLine.setAttributeNS(null, 'y2', fixSvgCoordinate(timelineWindowMaxY));
}
function updateTooltipPoints(xIndex, xRatio) {
if (!tooltipPoints) {
addTooltipPoints();
}
var i = 0;
while (i < tooltipPoints.length) {
var point = tooltipPoints[i];
point.style.left = "".concat(xRatio * 100, "%");
var y = timelineWindowGraphs[i].normalized.points[xIndex];
var yRatio = y / timelineWindowMaxY;
point.style.bottom = "".concat(yRatio * 100, "%");
i++;
}
}
import Chartogram from './Chartogram';
export default function chartogram(rootNode, data, title, options) {
var chartogram = new Chartogram(rootNode, data, title, options);
chartogram.componentDidMount();
chartogram.render();
return function () {
chartogram.componentWillUnmount();
};
}
//# sourceMappingURL=index.js.map
{
"name": "chartogram",
"version": "0.1.4",
"version": "0.1.5",
"description": "Charts in JS with no dependencies",

@@ -5,0 +5,0 @@ "main": "index.commonjs.js",

@@ -82,2 +82,4 @@ # chartogram

The default exported function returns another function which must be called in case of "destroying" the chart (it cleans up global event listeners).
### Browser

@@ -135,7 +137,7 @@

const { data, title } = this.props
chartogram(this.node.current, data, title)
this.cleanUp = chartogram(this.node.current, data, title)
}
componentWillUnmount() {
// Can remove any global event listeners here.
this.cleanUp
}

@@ -186,6 +188,6 @@

Tested in Chrome, Firefox and iOS Safari.
Tested in Chrome, Firefox, Microsoft Edge and iOS Safari.
Won't work in Edge or Internet Explorer.
For some reason doesn't show the `.chartogram__canvas` SVG element when it's wrapped in `.chartogram__canvas-wrapper` in Internet Explorer.
The styles use [CSS variables](https://caniuse.com/#feat=css-variables) which work everywhere except Internet Explorer.

@@ -1,831 +0,10 @@

export default function chartogram(rootNode, data, title = 'Title', options = {}) {
// clearElement(rootNode)
rootNode.innerHTML = `
<header class="chartogram__header">
<h1 class="chartogram__title">${title}</h1>
</header>
<div class="chartogram__plan-with-axes">
<div class="chartogram__plan">
<div class="chartogram__top-border"></div>
<div class="chartogram__canvas-wrapper">
<svg class="chartogram__canvas" preserveAspectRatio="none"></svg>
<div class="chartogram__x"></div>
<div class="chartogram__y-wrapper">
<div class="chartogram__y"></div>
</div>
</div>
</div>
</div>
<div class="chartogram__timeline">
<div class="chartogram__timeline-canvas-padding">
<svg class="chartogram__timeline-canvas" preserveAspectRatio="none"></svg>
</div>
<div class="chartogram__timeline-overlay-left"></div>
<div class="chartogram__timeline-overlay-right"></div>
<div class="chartogram__timeline-window">
<button type="button" class="chartogram__reset-button chartogram__timeline-window__drag"></button>
<button type="button" class="chartogram__reset-button chartogram__timeline-window__left-handle"></button>
<button type="button" class="chartogram__reset-button chartogram__timeline-window__right-handle"></button>
</div>
</div>
<div class="chartogram__chart-togglers"></div>
`
import Chartogram from './Chartogram'
rootNode.classList.add('chartogram')
const GAUGE_TICK_MARKS_COUNT = options.gaugeMarkTicksCount || 6
const TIMELINE_WINDOW_SIZE = options.timelineWindowSize || 40
const TIMELINE_CHART_MAX_POINTS = options.timelineChartMaxPoints || 80
const MONTHS = options.months || [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
]
const WEEKDAYS = options.weekdays || [
'Sun',
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat'
]
const tooltipContainer = document.querySelector('.chartogram__plan')
const canvas = document.querySelector('.chartogram__canvas')
const canvasWrapper = document.querySelector('.chartogram__canvas-wrapper')
const xAxis = document.querySelector('.chartogram__x')
const yAxis = document.querySelector('.chartogram__y')
const timeline = document.querySelector('.chartogram__timeline')
const timelineOverlayLeft = document.querySelector('.chartogram__timeline-overlay-left')
const timelineWindowLeftHandle = document.querySelector('.chartogram__timeline-window__left-handle')
const timelineWindow = document.querySelector('.chartogram__timeline-window')
const timelineWindowDrag = document.querySelector('.chartogram__timeline-window__drag')
const timelineWindowRightHandle = document.querySelector('.chartogram__timeline-window__right-handle')
const timelineOverlayRight = document.querySelector('.chartogram__timeline-overlay-right')
const timelineCanvas = document.querySelector('.chartogram__timeline-canvas')
let timelineWindowFrom
let timelineWindowTo
let showGraphs
let showGraphsNext
let timelineWindowGraphs
let timelineWindowMinX
let timelineWindowMaxX
let timelineWindowMinY
let timelineWindowMaxY
let timelineWindowX
let tooltip
let tooltipDate
let tooltipValues
let tooltipForX
let tooltipPoints
let tooltipLine
// A stub for possible animations.
let yScale = 1
setUpTimelineWindowHandle('left')
setUpTimelineWindowHandle('right')
setUpTimelineWindow()
normalizeDataPoints()
displayGraphs()
setUpCanvas()
function clearElement(element) {
while(element.firstChild) {
element.removeChild(element.firstChild)
}
export default function chartogram(rootNode, data, title, options) {
const chartogram = new Chartogram(rootNode, data, title, options)
chartogram.componentDidMount()
chartogram.render()
return () => {
chartogram.componentWillUnmount()
}
function commaJoin(a, b) {
return a.map((ai, i) => `${ai},${b[i]}`)
}
function createPolylinePoints(x, y) {
// return commaJoin(x, y)
return commaJoin(x.map(fixSvgCoordinate), y.map(fixSvgCoordinate))
}
// Firefox is buggy with too high and too fractional SVG coordinates.
function fixSvgCoordinate(x) {
return Math.round(x * Number.MAX_SAFE_INTEGER) / Number.MAX_SAFE_INTEGER
}
function getLowerSiblingDivisibleBy(n, divider) {
while (true) {
if (n < divider) {
return divider
}
if (n % divider === 0) {
return n
}
n--
}
}
function divideInterval(min, max) {
const points = new Array(GAUGE_TICK_MARKS_COUNT)
let i = 0
while (i < GAUGE_TICK_MARKS_COUNT) {
points[i] = min + i * (max - min) / (GAUGE_TICK_MARKS_COUNT - 1)
i++
}
return points
}
function drawGauge(element, min, max, transform) {
let i = 0
while (i < GAUGE_TICK_MARKS_COUNT) {
const tickMark = document.createElement('div')
let value = min + i * (max - min) / (GAUGE_TICK_MARKS_COUNT - 1)
if (transform) {
value = transform(value)
}
tickMark.appendChild(document.createTextNode(value))
element.appendChild(tickMark)
i++
}
}
// Chrome and Firefox can't handle timestamps in milliseconds for point coordinates (draws nothing).
// Reducing timestamps to lower numbers to work around that bug.
function normalizeDataPoints() {
normalizePoints([data.x])
normalizePoints(data.y)
}
function normalizePoints(all) {
const isX = all[0] === data.x
let min = Infinity
let max = -Infinity
for (const one of all) {
if (isX) {
one.min = one.points[0]
one.max = one.points[one.points.length - 1]
} else {
// For Y min is always 0 by design.
one.min = 0
// one.min = Math.min(...one.points)
one.max = Math.max(...one.points)
}
min = Math.min(min, one.min)
max = Math.max(max, one.max)
}
// For Y min is always 0 by design.
if (!isX) {
min = 0
}
const shift = min
const scale = max - min
for (const one of all) {
one.normalized = {
points: one.points.map(_ => (_ - shift) / scale),
shift,
scale
}
}
}
function displayGraphs() {
showGraphs = {}
for (const y of data.y) {
showGraphs[y.id] = true
}
showGraphsNext = undefined
if (data.x.points.length > TIMELINE_WINDOW_SIZE) {
const xMin = data.x.points[0]
const xMax = data.x.points[data.x.points.length - 1]
const xFrom = data.x.points[data.x.points.length - TIMELINE_WINDOW_SIZE]
timelineWindowFrom = (xFrom - xMin) / (xMax - xMin)
} else {
timelineWindowFrom = 0
}
timelineWindowTo = 1
updateTimelineWindow()
drawGraphs(true)
tooltipLine = undefined
// Add graph togglers.
const graphTogglers = document.querySelector('.chartogram__chart-togglers')
clearElement(graphTogglers)
for (const y of data.y) {
graphTogglers.appendChild(createGraphToggler(y))
}
}
function drawGraphs(redrawTimeline) {
// Clear canvas.
clearElement(canvas)
// Calculate bounds.
const xPoints = data.x.points
const minXOverall = xPoints[0]
const maxXOverall = xPoints[xPoints.length - 1]
const deltaX = maxXOverall - minXOverall
const minX = minXOverall + timelineWindowFrom * deltaX
const maxX = maxXOverall - (1 - timelineWindowTo) * deltaX
let minXIndex = xPoints.findIndex(x => x > minX) - 1
if (minXIndex < 0) {
minXIndex = 0
}
let maxXIndex = xPoints.findIndex(x => x > maxX)
if (maxXIndex < 0) {
maxXIndex = xPoints.length - 1
}
timelineWindowX = data.x.normalized.points.slice(minXIndex, maxXIndex + 1)
// let minY = Infinity
// Min Y is always 0 by design.
const minY = 0
let maxY = -Infinity
timelineWindowGraphs = []
for (const y of data.y) {
if (!showGraphs[y.id]) {
continue
}
const points = y.points.slice(minXIndex, maxXIndex + 1)
// Min Y is always 0 by design.
const min = 0
// const min = Math.min(...points)
const max = Math.max(...points)
timelineWindowGraphs.push({
...y,
points,
min,
max,
normalized: {
...y.normalized,
points: y.normalized.points.slice(minXIndex, maxXIndex + 1)
}
})
// minY = Math.min(minY, ...points)
maxY = Math.max(maxY, ...points)
}
// Set canvas `viewBox`.
const minXNormalized = (minX - data.x.normalized.shift) / data.x.normalized.scale
const maxXNormalized = (maxX - data.x.normalized.shift) / data.x.normalized.scale
const minYNormalized = (minY - data.y[0].normalized.shift) / data.y[0].normalized.scale
const maxYNormalized = (maxY - data.y[0].normalized.shift) / data.y[0].normalized.scale
canvas.setAttribute('viewBox', `${minXNormalized} ${minYNormalized} ${maxXNormalized - minXNormalized} ${maxYNormalized - minYNormalized}`)
// Calculate grid lines' coordinates.
const minY_ = 0
const maxY_ = getLowerSiblingDivisibleBy(maxY, 10)
const yAxisScale = (maxY - minY) / (maxY_ - minY)
const yAxisTickMarks = divideInterval(minY_, maxY_)
// Draw grid lines.
for (const y of yAxisTickMarks) {
canvas.appendChild(createGridLine(
(y - data.y[0].normalized.shift) / data.y[0].normalized.scale,
minXNormalized,
maxXNormalized,
minYNormalized,
maxYNormalized
))
}
// Trim X axis.
const _x = timelineWindowX.slice()
const _minX = _x[0]
const _maxX = _x[_x.length - 1]
const trimLeftRatio = (minXNormalized - _minX) / (_x[1] - _minX)
const trimRightRatio = (_maxX - maxXNormalized) / (_maxX - _x[_x.length - 2])
_x[0] = minXNormalized
_x[_x.length - 1] = maxXNormalized
// Draw charts.
for (const { id, color, normalized: { points } } of timelineWindowGraphs) {
// Trim chart.
const _y = points.slice()
const _minY = _y[0]
const _maxY = _y[_y.length - 1]
_y[0] = _minY + (_y[1] - _minY) * trimLeftRatio
_y[_y.length - 1] = _maxY - (_maxY - _y[_y.length - 2]) * trimRightRatio
// Draw chart.
const graph = document.createElement('polyline')
graph.setAttribute('stroke', color)
graph.setAttribute('points', createPolylinePoints(_x, _y.map(y => maxYNormalized - yScale * y)).join(' '))
graph.classList.add('chartogram__graph')
canvas.appendChild(graph)
}
// A workaround to fix WebKit bug when it's not re-rendering the <svg/>.
// https://stackoverflow.com/questions/30905493/how-to-force-webkit-to-update-svg-use-elements-after-changes-to-original
canvas.innerHTML += ''
// Draw gauges.
drawGauges(
minX,
maxX,
minY_,
maxY_,
yAxisScale
)
// Draw timeline graph.
timelineWindowMinY = minYNormalized
timelineWindowMaxY = maxYNormalized
timelineWindowMinX = minXNormalized
timelineWindowMaxX = maxXNormalized
if (redrawTimeline) {
drawTimeline()
}
}
// function animateScale(scale) {
// console.log(scale)
// animateScaleTo = scale
// animateScaleStartedAt = Date.now()
// previousYScale = yScale
// requestAnimationFrame(animateScaleTick)
// }
// function animateScaleTick() {
// const elapsed = Date.now() - animateScaleStartedAt
// yScale = previousYScale + (animateScaleTo - previousYScale) * elapsed / 300
// drawGraphs(true)
// if (elapsed < 300) {
// requestAnimationFrame(animateScaleTick)
// }
// }
function createGridLine(y, minX, maxX, minY, maxY) {
const line = document.createElement('line')
line.classList.add('chartogram__grid-line')
line.setAttribute('x1', fixSvgCoordinate(minX))
line.setAttribute('x2', fixSvgCoordinate(maxX))
line.setAttribute('y1', fixSvgCoordinate((maxY - minY) - y))
line.setAttribute('y2', fixSvgCoordinate((maxY - minY) - y))
return line
}
function drawGauges(minX, maxX, minY, maxY, yAxisScale) {
clearElement(xAxis)
clearElement(yAxis)
drawGauge(xAxis, minX, maxX, (timestamp) => {
const date = new Date(timestamp)
return `${MONTHS[date.getMonth()]} ${date.getDate()}`
})
drawGauge(yAxis, minY, maxY)
yAxis.style.height = `${100 / yAxisScale}%`
}
function simplifyGraph(x, y, maxPoints, yMax = Math.max(...y), threshold = 0.025, i = 0, _x = new Array(x.length), _y = new Array(x.length), _i = 0) {
if (i + 2 > x.length - 1) {
while (i < y.length) {
_x[_i] = x[i]
_y[_i] = y[i]
_i++
i++
}
_x = _x.slice(0, _i)
_y = _y.slice(0, _i)
if (_x.length <= maxPoints) {
return [_x, _y]
} else {
if (x.length / _x.length < 1.1) {
threshold = Math.min(threshold + 0.025, 1)
}
return simplifyGraph(_x, _y, maxPoints, yMax, threshold)
}
}
const y0 = (y[i + 2] + y[i]) / 2
if (Math.abs(y0 - y[i + 1]) / yMax < threshold) {
_x[_i] = x[i]
_x[_i + 1] = x[i + 2]
_y[_i] = y[i]
_y[_i + 1] = y[i + 2]
return simplifyGraph(x, y, maxPoints, yMax, threshold, i + 2, _x, _y, _i + 1)
} else {
_x[_i] = x[i]
_x[_i + 1] = x[i + 1]
_x[_i + 2] = x[i + 2]
_y[_i] = y[i]
_y[_i + 1] = y[i + 1]
_y[_i + 2] = y[i + 2]
return simplifyGraph(x, y, maxPoints, yMax, threshold, i + 2, _x, _y, _i + 2)
}
}
function drawTimeline() {
const x = data.x.normalized.points
const graphs = data.y.filter(_ => showGraphs[_.id])
const minX = 0
const maxX = 1
const minY = (Math.min(...graphs.map(_ => _.min)) - graphs[0].normalized.shift) / graphs[0].normalized.scale
const maxY = (Math.max(...graphs.map(_ => _.max)) - graphs[0].normalized.shift) / graphs[0].normalized.scale
clearElement(timelineCanvas)
// Set canvas `viewBox`.
timelineCanvas.setAttribute('viewBox', `${minX} ${minY} ${maxX - minX} ${maxY - minY}`)
for (const { id, color, normalized: { points } } of graphs) {
const [_x, _y] = simplifyGraph(x, points, 80)
const graph = document.createElement('polyline')
graph.setAttribute('stroke', color)
graph.setAttribute('points', createPolylinePoints(_x, _y.map(y => (maxY - minY) - y)).join(' '))
graph.classList.add('chartogram__graph')
timelineCanvas.appendChild(graph)
}
// A workaround to fix WebKit bug when it's not re-rendering the <svg/>.
// https://stackoverflow.com/questions/30905493/how-to-force-webkit-to-update-svg-use-elements-after-changes-to-original
timelineCanvas.innerHTML += ''
}
function createGraphToggler({ id, name, color }) {
const toggler = document.createElement('button')
toggler.setAttribute('type', 'button')
toggler.classList.add('chartogram__chart-toggler')
toggler.classList.add('chartogram__chart-toggler--on')
toggler.classList.add('chartogram__reset-button')
// Add check.
const xmlns = 'http://www.w3.org/2000/svg'
const check = document.createElementNS(xmlns, 'svg')
check.setAttributeNS(null, 'viewBox', '0 0 19 19')
check.classList.add('chartogram__chart-toggler-check')
// Add background circle.
const backgroundCircle = document.createElementNS(xmlns, 'circle')
backgroundCircle.setAttribute('cx', '9.5')
backgroundCircle.setAttribute('cy', '9.5')
backgroundCircle.setAttribute('r', '9.5')
backgroundCircle.setAttribute('fill', color)
check.appendChild(backgroundCircle)
// Add check circle.
const checkCircle = document.createElementNS(xmlns, 'circle')
checkCircle.setAttribute('cx', '9.5')
checkCircle.setAttribute('cy', '9.5')
checkCircle.setAttribute('r', '8')
checkCircle.classList.add('chartogram__chart-toggler-check-circle')
check.appendChild(checkCircle)
// Add check mark.
const checkMark = document.createElementNS(xmlns, 'path')
checkMark.setAttribute('d', 'M13.64 4.94l-6.2 6.34-1.69-1.9c-.73-.63-1.89.1-1.36 1.06l2 3.38c.3.43 1.04.85 1.78 0 .32-.42 6.31-7.93 6.31-7.93.74-.84-.2-1.58-.84-.95z')
checkMark.setAttribute('fill', 'white')
checkMark.classList.add('chartogram__chart-toggler-check-mark')
check.appendChild(checkMark)
// Add checkmark.
toggler.appendChild(check)
// Add graph name.
toggler.appendChild(document.createTextNode(name))
// On click.
toggler.addEventListener('click', () => {
const show = !showGraphs[id]
// Won't allow hiding all graphs.
if (!show) {
const graphsShown = Object.keys(showGraphs).filter(id => showGraphs[id] !== false).length
if (graphsShown === 1) {
return
}
}
showGraphs[id] = show
drawGraphs(true)
toggler.classList.toggle('chartogram__chart-toggler--on')
})
return toggler
}
function getMaxY(graphs) {
let maxY = 0
for (const graph of graphs) {
maxY = Math.max(maxY, ...graph.points)
}
return maxY
}
function setUpTimelineWindowHandle(side) {
const handle = side === 'left' ? timelineWindowLeftHandle : timelineWindowRightHandle
let handleWidth = parseFloat(getComputedStyle(timelineWindow).borderLeftWidth)
let timelineCoordinates
let minX
let maxX
let deltaX
let startedX
function onDrag(x) {
x = x - deltaX
x = Math.max(Math.min(x, maxX), minX)
x = (x - timelineCoordinates.x) / timelineCoordinates.width
if (side === 'left') {
timelineWindowFrom = x
} else {
timelineWindowTo = x
}
updateTimelineWindow()
}
function onDragStart(x) {
timelineCoordinates = timeline.getBoundingClientRect()
const timelineWindowCoordinates = timelineWindow.getBoundingClientRect()
if (side === 'left') {
minX = timelineCoordinates.x
maxX = timelineWindowCoordinates.x + timelineWindowCoordinates.width - 2 * handleWidth
deltaX = x - timelineWindowCoordinates.x
} else {
minX = timelineWindowCoordinates.x + 2 * handleWidth
maxX = timelineCoordinates.x + timelineCoordinates.width
deltaX = x - (timelineWindowCoordinates.x + timelineWindowCoordinates.width)
}
}
return setUpDrag(handle, onDragStart, onDrag)
}
function setUpTimelineWindow() {
let timelineCoordinates
let timelineWindowCoordinates
let minX
let maxX
let innerX
function onDrag(x) {
x = x - innerX
x = Math.max(Math.min(x, maxX), minX)
x = (x - timelineCoordinates.x) / timelineCoordinates.width
timelineWindowFrom = x
timelineWindowTo = x + timelineWindowCoordinates.width / timelineCoordinates.width
updateTimelineWindow()
}
function onDragStart(x) {
timelineCoordinates = timeline.getBoundingClientRect()
timelineWindowCoordinates = timelineWindow.getBoundingClientRect()
innerX = x - timelineWindowCoordinates.x
minX = timelineCoordinates.x
maxX = timelineCoordinates.x + (timelineCoordinates.width - timelineWindowCoordinates.width)
}
return setUpDrag(timelineWindowDrag, onDragStart, onDrag)
}
function setUpDrag(element, onDragStart, onDrag) {
function onTouchMove(event) {
onDrag(
event.changedTouches[0].clientX,
event.changedTouches[0].clientY
)
}
function onPointerMove(event) {
onDrag(event.clientX, event.clientY)
}
function onDragStop() {
window.removeEventListener('pointermove', onPointerMove)
window.removeEventListener('touchmove', onTouchMove)
window.removeEventListener('pointerup', onDragStop)
window.removeEventListener('pointercancel', onDragStop)
window.removeEventListener('touchend', onDragStop)
window.removeEventListener('touchcancel', onDragStop)
}
function onTouchStart(event) {
// Ignore multitouch.
if (event.touches.length > 1) {
// Reset.
return onDragStop()
}
onDragStart(
event.changedTouches[0].clientX,
event.changedTouches[0].clientY
)
window.addEventListener('touchmove', onTouchMove)
window.addEventListener('touchend', onDragStop)
window.addEventListener('touchcancel', onDragStop)
}
// Safari doesn't support pointer events.
// https://caniuse.com/#feat=pointer
element.addEventListener('touchstart', onTouchStart)
function onPointerDown(event) {
onDragStart(event.clientX, event.clientY)
window.addEventListener('pointermove', onPointerMove)
window.addEventListener('pointerup', onDragStop)
window.addEventListener('pointercancel', onDragStop)
}
element.addEventListener('pointerdown', onPointerDown)
return () => {
onDragStop()
element.removeEventListener(onPointerDown)
element.removeEventListener(onTouchStart)
}
}
function setTimelineWindowLeft(x) {
timelineOverlayLeft.style.right = `${100 * (1 - x)}%`
timelineWindow.style.left = `${100 * x}%`
}
function setTimelineWindowRight(x) {
timelineOverlayRight.style.left = `${100 * x}%`
timelineWindow.style.right = `${100 * (1 - x)}%`
}
function updateTimelineWindow() {
setTimelineWindowLeft(timelineWindowFrom)
setTimelineWindowRight(timelineWindowTo)
drawGraphs(false)
}
function setUpCanvas() {
let canvasDimensions
let isIndexInBounds
function onTrack(screenX) {
const xScreenRatio = (screenX - canvasDimensions.x) / canvasDimensions.width
let x = timelineWindowMinX + xScreenRatio * (timelineWindowMaxX - timelineWindowMinX)
let xHigherIndex = timelineWindowX.findIndex(_ => _ >= x)
let xLowerIndex = xHigherIndex - 1
if (!isIndexInBounds(xHigherIndex)) {
xHigherIndex = -1
}
if (!isIndexInBounds(xLowerIndex)) {
xLowerIndex = -1
}
if (xHigherIndex < 0) {
if (xLowerIndex < 0) {
return removeTooltip()
} else {
x = timelineWindowX[xLowerIndex]
}
} else {
if (xLowerIndex < 0) {
x = timelineWindowX[xHigherIndex]
} else {
const xLower = timelineWindowX[xLowerIndex]
const xHigher = timelineWindowX[xHigherIndex]
const deltaLower = x - xLower
const deltaHigher = xHigher - x
x = deltaLower > deltaHigher ? xHigher : xLower
}
}
if (x !== tooltipForX) {
tooltipForX = x
if (!tooltip) {
addTooltip()
}
const date = new Date(x * data.x.normalized.scale + data.x.normalized.shift)
tooltipDate.textContent = `${WEEKDAYS[date.getDay()]}, ${MONTHS[date.getMonth()]} ${date.getDate()}`
const xIndex = timelineWindowX.indexOf(x)
let i = 0
while (2 * i < tooltipValues.childNodes.length) {
tooltipValues.childNodes[2 * i].textContent = timelineWindowGraphs[i].points[xIndex]
tooltipValues.childNodes[2 * i + 1].textContent = data.y[i].name
i++
}
const xRatio = (x - timelineWindowMinX) / (timelineWindowMaxX - timelineWindowMinX)
tooltip.style.left = `${xRatio * 100}%`
updateTooltipPoints(xIndex, xRatio)
updateTooltipLine(x)
}
}
function onTrackStart() {
canvasDimensions = canvas.getBoundingClientRect()
isIndexInBounds = (index) => {
if (index < 0) {
return false
}
return timelineWindowX[index] >= timelineWindowMinX &&
timelineWindowX[index] <= timelineWindowMaxX
}
}
function onTouchStart(event) {
// Ignore multitouch.
if (event.touches.length > 1) {
// Reset.
return onTrackStop()
}
onTrackStart()
canvas.addEventListener('touchend', onTrackStop)
canvas.addEventListener('touchmove', onTouchMove)
canvas.addEventListener('touchend', onTrackStop)
canvas.addEventListener('touchcancel', onTrackStop)
onTouchMove(event)
}
// Safari doesn't support pointer events.
// https://caniuse.com/#feat=pointer
canvas.addEventListener('touchstart', onTouchStart)
function onTouchMove(event) {
const x = event.changedTouches[0].clientX
const y = event.changedTouches[0].clientY
// Emulate 'pointerleave' behavior.
if (x < canvasDimensions.x ||
x > canvasDimensions.x + canvasDimensions.width ||
y < canvasDimensions.y ||
y > canvasDimensions.y + canvasDimensions.height) {
onTrackStop()
} else {
onTrack(x, y)
}
}
function onPointerMove(event) {
onTrack(event.clientX, event.clientY)
}
function onTrackStop() {
canvas.removeEventListener('pointermove', onPointerMove)
canvas.removeEventListener('pointerleave', onTrackStop)
canvas.removeEventListener('pointercancel', onTrackStop)
canvas.removeEventListener('touchmove', onTouchMove)
canvas.removeEventListener('touchend', onTrackStop)
canvas.removeEventListener('touchcancel', onTrackStop)
removeTooltip()
}
function onPointerEnter() {
onTrackStart()
canvas.addEventListener('pointermove', onPointerMove)
canvas.addEventListener('pointerleave', onTrackStop)
canvas.addEventListener('pointercancel', onTrackStop)
}
canvas.addEventListener('pointerenter', onPointerEnter)
return () => {
onTrackStop()
canvas.removeEventListener(onPointerEnter)
canvas.removeEventListener(onTouchStart)
}
}
function addTooltip() {
// Create tooltip.
tooltip = document.createElement('div')
tooltip.classList.add('chartogram__tooltip')
tooltipContainer.appendChild(tooltip)
// Add tooltip title.
tooltipDate = document.createElement('h1')
tooltipDate.classList.add('chartogram__tooltip-header')
tooltip.appendChild(tooltipDate)
// Add graph values.
tooltipValues = document.createElement('dl')
tooltipValues.classList.add('chartogram__tooltip-values')
tooltip.appendChild(tooltipValues)
// Add graph values.
for (const y of data.y) {
if (showGraphs[y.id]) {
// Add graph value.
const tooltipValue = document.createElement('dt')
tooltipValue.style.color = y.color
tooltipValues.appendChild(tooltipValue)
// Add graph name.
const tooltipName = document.createElement('dd')
tooltipName.style.color = y.color
tooltipValues.appendChild(tooltipName)
}
}
}
function removeTooltip() {
if (tooltip) {
tooltipForX = undefined
tooltipContainer.removeChild(tooltip)
tooltip = undefined
removeTooltipPoints()
removeTooltipLine()
}
}
function addTooltipLine() {
const xmlns = 'http://www.w3.org/2000/svg'
tooltipLine = document.createElementNS(xmlns, 'line')
tooltipLine.setAttributeNS(null, 'class', 'chartogram__tooltip-line')
canvas.insertBefore(tooltipLine, canvas.querySelector('polyline'))
}
function removeTooltipLine() {
canvas.removeChild(tooltipLine)
tooltipLine = undefined
}
function addTooltipPoints() {
tooltipPoints = []
let i = 0
while (i < timelineWindowGraphs.length) {
const point = document.createElement('div')
point.classList.add('chartogram__tooltip-point')
point.style.color = timelineWindowGraphs[i].color
tooltipPoints.push(point)
canvasWrapper.appendChild(point)
i++
}
}
function removeTooltipPoints() {
for (const point of tooltipPoints) {
canvasWrapper.removeChild(point)
}
tooltipPoints = undefined
}
function updateTooltipLine(x) {
if (!tooltipLine) {
addTooltipLine()
}
tooltipLine.setAttributeNS(null, 'x1', fixSvgCoordinate(x))
tooltipLine.setAttributeNS(null, 'x2', fixSvgCoordinate(x))
tooltipLine.setAttributeNS(null, 'y1', fixSvgCoordinate(timelineWindowMinY))
tooltipLine.setAttributeNS(null, 'y2', fixSvgCoordinate(timelineWindowMaxY))
}
function updateTooltipPoints(xIndex, xRatio) {
if (!tooltipPoints) {
addTooltipPoints()
}
let i = 0
while (i < tooltipPoints.length) {
const point = tooltipPoints[i]
point.style.left = `${xRatio * 100}%`
const y = timelineWindowGraphs[i].normalized.points[xIndex]
const yRatio = y / timelineWindowMaxY
point.style.bottom = `${yRatio * 100}%`
i++
}
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc