chartogram
Advanced tools
Comparing version 0.1.2 to 0.1.3
@@ -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,o=void 0;try{for(var i,c=t[Symbol.iterator]();!(r=(i=c.next()).done)&&(n.push(i.value),!e||n.length!==e);r=!0);}catch(t){a=!0,o=t}finally{try{r||null==c.return||c.return()}finally{if(a)throw o}}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 o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Title",i=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(o,'</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,v,m,g,f,p,_,y,b,w,x,A=i.gaugeMarkTicksCount||6,E=i.timelineWindowSize||40,L=i.timelineChartMaxPoints||80,S=i.months||["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],C=i.weekdays||["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],k=document.querySelector(".chartogram__plan"),M=document.querySelector(".chartogram__canvas"),N=document.querySelector(".chartogram__canvas-wrapper"),T=document.querySelector(".chartogram__x"),q=document.querySelector(".chartogram__y"),O=document.querySelector(".chartogram__timeline"),j=document.querySelector(".chartogram__timeline-overlay-left"),B=document.querySelector(".chartogram__timeline-window__left-handle"),D=document.querySelector(".chartogram__timeline-window"),R=document.querySelector(".chartogram__timeline-window__drag"),X=document.querySelector(".chartogram__timeline-window__right-handle"),Y=document.querySelector(".chartogram__timeline-overlay-right"),I=document.querySelector(".chartogram__timeline-canvas"),P=1;function F(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function H(t,e){return t.map(function(t,n){return"".concat(t,",").concat(e[n])})}function J(t,e,n,r){for(var a=0;a<A;){var o=document.createElement("div"),i=e+a*(n-e)/(A-1);r&&(i=r(i)),o.appendChild(document.createTextNode(i)),t.appendChild(o),a++}}function W(n){var o=a.x.points;g=o[0];var i=o.map(function(t){return(t-g)/1e3});F(M);var p=i[0],_=i[i.length-1],y=_-p,b=p+c*y,w=_-(1-l)*y,x=i.findIndex(function(t){return t>b})-1;x<0&&(x=0);var E=i.findIndex(function(t){return t>w});E<0&&(E=i.length-1);var C=i.slice(x,E+1),k=0,N=0;s=[];var O=[],j=a.lines,B=Array.isArray(j),D=0;for(j=B?j:j[Symbol.iterator]();;){var R;if(B){if(D>=j.length)break;R=j[D++]}else{if((D=j.next()).done)break;R=D.value}var X=R;if(d[X.id]){O.push(X),N=Math.max.apply(Math,[N].concat(r(X.points)));var Y=X.points.slice(x,E+1);s.push(e({},X,{points:Y})),k=Math.max.apply(Math,[k].concat(r(Y)))}}M.setAttribute("viewBox","".concat(b," ").concat(0," ").concat(w-b," ").concat(k-0));var W=function(t,e){for(;;){if(t<e)return e;if(t%e==0)return t;t--}}(k,10),K=(k-0)/(W-0),Q=function(t,e){for(var n=new Array(A),r=0;r<A;)n[r]=t+r*(e-t)/(A-1),r++;return n}(0,W),U=Array.isArray(Q),V=0;for(Q=U?Q:Q[Symbol.iterator]();;){var Z;if(U){if(V>=Q.length)break;Z=Q[V++]}else{if((V=Q.next()).done)break;Z=V.value}var $=Z;M.appendChild(z($,b,w,0,k))}var tt=C.slice(),et=tt[0],nt=tt[tt.length-1],rt=(b-et)/(tt[1]-et),at=(nt-w)/(nt-tt[tt.length-2]);tt[0]=b,tt[tt.length-1]=w;var ot=s,it=Array.isArray(ot),ct=0;for(ot=it?ot:ot[Symbol.iterator]();;){var lt;if(it){if(ct>=ot.length)break;lt=ot[ct++]}else{if((ct=ot.next()).done)break;lt=ct.value}var dt=lt,st=(dt.id,dt.color),ut=dt.points,ht=document.createElement("polyline");ht.setAttribute("stroke",st);var vt=ut.slice(),mt=vt[0],gt=vt[vt.length-1];vt[0]=mt+(vt[1]-mt)*rt,vt[vt.length-1]=gt-(gt-vt[vt.length-2])*at,ht.setAttribute("points",H(tt,vt.map(function(t){return k-P*t})).join(" ")),ht.classList.add("chartogram__graph"),M.appendChild(ht)}M.innerHTML+="",function(t,e,n,r,a){F(T),F(q),J(T,t,e,function(t){var e=new Date(t);return"".concat(S[e.getMonth()]," ").concat(e.getDate())}),J(q,n,r),q.style.height="".concat(100/a,"%")}(o[0],o[o.length-1],0,W,K),v=0,m=k,u=b,h=w,f=C,n&&function(e,n,r,a,o,i){F(I),I.setAttribute("viewBox","".concat(r," ").concat(o," ").concat(a-r," ").concat(i-o));for(var c=e,l=Array.isArray(c),d=0,c=l?c:c[Symbol.iterator]();;){var s;if(l){if(d>=c.length)break;s=c[d++]}else{if((d=c.next()).done)break;s=d.value}var u=s,h=(u.id,u.color),v=u.points,m=G(n,v,L),g=t(m,2),f=g[0],p=g[1],_=document.createElement("polyline");_.setAttribute("stroke",h),_.setAttribute("points",H(f,p.map(function(t){return i-o-t})).join(" ")),_.classList.add("chartogram__graph"),I.appendChild(_)}I.innerHTML+=""}(O,i,p,_,0,N)}function z(t,e,n,r,a){var o=document.createElement("line");return o.classList.add("chartogram__grid-line"),o.setAttribute("x1",e),o.setAttribute("x2",n),o.setAttribute("y1",a-r-t),o.setAttribute("y2",a-r-t),o}function G(t,e,n){var a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Math.max.apply(Math,r(e)),o=arguments.length>4&&void 0!==arguments[4]?arguments[4]:.025,i=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(i+2>t.length-1){for(;i<e.length;)c[d]=t[i],l[d]=e[i],d++,i++;return c=c.slice(0,d),l=l.slice(0,d),c.length<=n?[c,l]:(t.length/c.length<1.1&&(o=Math.min(o+.025,1)),G(c,l,n,a,o))}var s=(e[i+2]+e[i])/2;return Math.abs(s-e[i+1])/a<o?(c[d]=t[i],c[d+1]=t[i+2],l[d]=e[i],l[d+1]=e[i+2],G(t,e,n,a,o,i+2,c,l,d+1)):(c[d]=t[i],c[d+1]=t[i+1],c[d+2]=t[i+2],l[d]=e[i],l[d+1]=e[i+1],l[d+2]=e[i+2],G(t,e,n,a,o,i+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 o="http://www.w3.org/2000/svg",i=document.createElementNS(o,"svg");i.setAttributeNS(null,"viewBox","0 0 19 19"),i.classList.add("chartogram__chart-toggler-check");var c=document.createElementNS(o,"circle");c.setAttribute("cx","9.5"),c.setAttribute("cy","9.5"),c.setAttribute("r","9.5"),c.setAttribute("fill",r),i.appendChild(c);var l=document.createElementNS(o,"circle");l.setAttribute("cx","9.5"),l.setAttribute("cy","9.5"),l.setAttribute("r","8"),l.classList.add("chartogram__chart-toggler-check-circle"),i.appendChild(l);var s=document.createElementNS(o,"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"),i.appendChild(s),a.appendChild(i),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,W(!0),a.classList.toggle("chartogram__chart-toggler--on"))}),a}function Q(t){var e,n,r,a,o="left"===t?B:X,i=parseFloat(getComputedStyle(D).borderLeftWidth);return U(o,function(o){e=O.getBoundingClientRect();var c=D.getBoundingClientRect();"left"===t?(n=e.x,r=c.x+c.width-2*i,a=o-c.x):(n=c.x+2*i,r=e.x+e.width,a=o-(c.x+c.width))},function(o){o-=a,o=((o=Math.max(Math.min(o,r),n))-e.x)/e.width,"left"===t?c=o:l=o,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 o(){window.removeEventListener("pointermove",a),window.removeEventListener("touchmove",r),window.removeEventListener("pointerup",o),window.removeEventListener("pointercancel",o),window.removeEventListener("touchend",o),window.removeEventListener("touchcancel",o)}function i(t){if(t.touches.length>1)return o();e(t.changedTouches[0].clientX,t.changedTouches[0].clientY),window.addEventListener("touchmove",r),window.addEventListener("touchend",o),window.addEventListener("touchcancel",o)}function c(t){e(t.clientX,t.clientY),window.addEventListener("pointermove",a),window.addEventListener("pointerup",o),window.addEventListener("pointercancel",o)}return t.addEventListener("touchstart",i),t.addEventListener("pointerdown",c),function(){o(),t.removeEventListener(c),t.removeEventListener(i)}}function V(){var t;t=c,j.style.right="".concat(100*(1-t),"%"),D.style.left="".concat(100*t,"%"),function(t){Y.style.left="".concat(100*t,"%"),D.style.right="".concat(100*(1-t),"%")}(l),W(!1)}function Z(){p&&(b=void 0,k.removeChild(p),p=void 0,function(){for(var t=w,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;N.removeChild(a)}w=void 0}(),M.removeChild(x),x=void 0)}Q("left"),Q("right"),U(R,function(t){$=O.getBoundingClientRect(),tt=D.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()}),function(){d={};for(var t=a.lines,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 o=r;d[o.id]=!0}if(a.x.points.length>E){var i=a.x.points[0],s=a.x.points[a.x.points.length-1],u=a.x.points[a.x.points.length-E];c=(u-i)/(s-i)}else c=0;l=1,V(),W(!0),x=void 0;var h=document.querySelector(".chartogram__chart-togglers");F(h);for(var v=a.lines,m=Array.isArray(v),g=0,v=m?v:v[Symbol.iterator]();;){var f;if(m){if(g>=v.length)break;f=v[g++]}else{if((g=v.next()).done)break;f=g.value}var p=f;h.appendChild(K(p))}}(),function(){var t,e;function n(n){var r=(n-t.x)/t.width,o=u+r*(h-u),i=f.findIndex(function(t){return t>=o}),c=i-1;if(e(i)||(i=-1),e(c)||(c=-1),i<0){if(c<0)return Z();o=f[c]}else if(c<0)o=f[i];else{var l=f[c],A=f[i],E=o-l,L=A-o;o=E>L?A:l}if(o!==b){b=o,p||function(){(p=document.createElement("div")).classList.add("chartogram__tooltip"),k.appendChild(p),(_=document.createElement("h1")).classList.add("chartogram__tooltip-header"),p.appendChild(_),(y=document.createElement("dl")).classList.add("chartogram__tooltip-values"),p.appendChild(y);for(var t=a.lines,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 o=r;if(d[o.id]){var i=document.createElement("dt");i.style.color=o.color,y.appendChild(i);var c=document.createElement("dd");c.style.color=o.color,y.appendChild(c)}}}();var T=new Date(1e3*o+g);_.textContent="".concat(C[T.getDay()],", ").concat(S[T.getMonth()]," ").concat(T.getDate());for(var q=f.indexOf(o),O=0;2*O<y.childNodes.length;)y.childNodes[2*O].textContent=s[O].points[q],y.childNodes[2*O+1].textContent=a.lines[O].name,O++;var j=(o-u)/(h-u);p.style.left="".concat(100*j,"%"),function(t,e){w||function(){w=[];for(var t=0;t<s.length;){var e=document.createElement("div");e.classList.add("chartogram__tooltip-point"),e.style.color=s[t].color,w.push(e),N.appendChild(e),t++}}();for(var n=0;n<w.length;){var r=w[n];r.style.left="".concat(100*e,"%");var a=s[n].points[t],o=a/m;r.style.bottom="".concat(100*o,"%"),n++}}(q,j),function(t){x||((x=document.createElementNS("http://www.w3.org/2000/svg","line")).setAttributeNS(null,"class","chartogram__tooltip-line"),M.insertBefore(x,M.querySelector("polyline"))),x.setAttributeNS(null,"x1",t),x.setAttributeNS(null,"x2",t),x.setAttributeNS(null,"y1",v),x.setAttributeNS(null,"y2",m)}(o)}}function r(){t=M.getBoundingClientRect(),e=function(t){return!(t<0)&&f[t]>=u&&f[t]<=h}}function o(t){if(t.touches.length>1)return l();r(),M.addEventListener("touchend",l),M.addEventListener("touchmove",i),M.addEventListener("touchend",l),M.addEventListener("touchcancel",l),i(t)}function i(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(){M.removeEventListener("pointermove",c),M.removeEventListener("pointerleave",l),M.removeEventListener("pointercancel",l),M.removeEventListener("touchmove",i),M.removeEventListener("touchend",l),M.removeEventListener("touchcancel",l),Z()}function A(){r(),M.addEventListener("pointermove",c),M.addEventListener("pointerleave",l),M.addEventListener("pointercancel",l)}M.addEventListener("touchstart",o),M.addEventListener("pointerenter",A)}();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,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,_=o+c*p,y=g-(1-l)*p,b=i.findIndex(function(t){return t>_})-1;b<0&&(b=0);var w=i.findIndex(function(t){return t>y});w<0&&(w=i.length-1),f=a.x.normalized.points.slice(b,w+1);var A=-1/0;s=[];var L=a.lines,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=(_-a.x.normalized.shift)/a.x.normalized.scale,B=(y-a.x.normalized.shift)/a.x.normalized.scale,R=(0-a.lines[0].normalized.shift)/a.lines[0].normalized.scale,F=(A-a.lines[0].normalized.shift)/a.lines[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.lines[0].normalized.shift)/a.lines[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.lines.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],_=g[1],y=document.createElement("polyline");y.setAttribute("stroke",m),y.setAttribute("points",Y(p,_.map(function(t){return o-i-t})).join(" ")),y.classList.add("chartogram__graph"),X.appendChild(y)}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&&(y=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.lines),function(){d={};for(var t=a.lines,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.lines,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!==y){y=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),(_=document.createElement("dl")).classList.add("chartogram__tooltip-values"),g.appendChild(_);for(var t=a.lines,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,_.appendChild(o);var c=document.createElement("dd");c.style.color=i.color,_.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<_.childNodes.length;)_.childNodes[2*T].textContent=s[T].points[N],_.childNodes[2*T+1].textContent=a.lines[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}}); | ||
//# sourceMappingURL=chartogram.js.map |
@@ -61,4 +61,3 @@ "use strict"; | ||
var timelineWindowMaxY; | ||
var shiftX; | ||
var timelineWindowXScaled; | ||
var timelineWindowX; | ||
var tooltip; | ||
@@ -75,2 +74,3 @@ var tooltipDate; | ||
setUpTimelineWindow(); | ||
normalizeDataPoints(); | ||
displayGraphs(); | ||
@@ -91,2 +91,12 @@ setUpCanvas(); | ||
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) { | ||
@@ -133,8 +143,17 @@ while (true) { | ||
} | ||
} // 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.lines); | ||
} | ||
function displayGraphs() { | ||
showGraphs = {}; | ||
function normalizePoints(all) { | ||
var isX = all[0] === data.x; | ||
var min = Infinity; | ||
var max = -Infinity; | ||
for (var _iterator = data.lines, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
for (var _iterator = all, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref; | ||
@@ -151,3 +170,65 @@ | ||
var line = _ref; | ||
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.lines, _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 line = _ref3; | ||
showGraphs[line.id] = true; | ||
@@ -175,15 +256,15 @@ } | ||
for (var _iterator2 = data.lines, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { | ||
var _ref2; | ||
for (var _iterator4 = data.lines, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { | ||
var _ref4; | ||
if (_isArray2) { | ||
if (_i3 >= _iterator2.length) break; | ||
_ref2 = _iterator2[_i3++]; | ||
if (_isArray4) { | ||
if (_i5 >= _iterator4.length) break; | ||
_ref4 = _iterator4[_i5++]; | ||
} else { | ||
_i3 = _iterator2.next(); | ||
if (_i3.done) break; | ||
_ref2 = _i3.value; | ||
_i5 = _iterator4.next(); | ||
if (_i5.done) break; | ||
_ref4 = _i5.value; | ||
} | ||
var _line = _ref2; | ||
var _line = _ref4; | ||
graphTogglers.appendChild(createGraphToggler(_line)); | ||
@@ -194,18 +275,12 @@ } | ||
function drawGraphs(redrawTimeline) { | ||
var x = data.x.points; // Chrome can't handle timestamps in milliseconds for point coordinates (draws nothing). | ||
// Reducing timestamps to lower numbers to work around that bug. | ||
shiftX = x[0]; | ||
var xScaledAll = x.map(function (_) { | ||
return (_ - shiftX) / 1000; | ||
}); // Clear canvas. | ||
// Clear canvas. | ||
clearElement(canvas); // Calculate bounds. | ||
var minXOverall = xScaledAll[0]; | ||
var maxXOverall = xScaledAll[xScaledAll.length - 1]; | ||
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 = xScaledAll.findIndex(function (x) { | ||
var minXIndex = xPoints.findIndex(function (x) { | ||
return x > minX; | ||
@@ -218,3 +293,3 @@ }) - 1; | ||
var maxXIndex = xScaledAll.findIndex(function (x) { | ||
var maxXIndex = xPoints.findIndex(function (x) { | ||
return x > maxX; | ||
@@ -224,28 +299,25 @@ }); | ||
if (maxXIndex < 0) { | ||
maxXIndex = xScaledAll.length - 1; | ||
maxXIndex = xPoints.length - 1; | ||
} | ||
var xScaled = xScaledAll.slice(minXIndex, maxXIndex + 1); // let minY = Infinity | ||
// let minYOverall = Infinity | ||
timelineWindowX = data.x.normalized.points.slice(minXIndex, maxXIndex + 1); // let minY = Infinity | ||
// Min Y is always 0 by design. | ||
var minY = 0; | ||
var maxY = 0; | ||
var maxYOverall = 0; | ||
var maxY = -Infinity; | ||
timelineWindowGraphs = []; | ||
var graphsAll = []; | ||
for (var _iterator3 = data.lines, _isArray3 = Array.isArray(_iterator3), _i4 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref3; | ||
for (var _iterator5 = data.lines, _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { | ||
var _ref5; | ||
if (_isArray3) { | ||
if (_i4 >= _iterator3.length) break; | ||
_ref3 = _iterator3[_i4++]; | ||
if (_isArray5) { | ||
if (_i6 >= _iterator5.length) break; | ||
_ref5 = _iterator5[_i6++]; | ||
} else { | ||
_i4 = _iterator3.next(); | ||
if (_i4.done) break; | ||
_ref3 = _i4.value; | ||
_i6 = _iterator5.next(); | ||
if (_i6.done) break; | ||
_ref5 = _i6.value; | ||
} | ||
var line = _ref3; | ||
var line = _ref5; | ||
@@ -256,8 +328,14 @@ if (!showGraphs[line.id]) { | ||
graphsAll.push(line); // minYOverall = Math.min(minYOverall, ...line.points) | ||
var points = line.points.slice(minXIndex, maxXIndex + 1); // Min Y is always 0 by design. | ||
maxYOverall = Math.max.apply(Math, [maxYOverall].concat(_toConsumableArray(line.points))); | ||
var points = line.points.slice(minXIndex, maxXIndex + 1); | ||
var min = 0; // const min = Math.min(...points) | ||
var max = Math.max.apply(Math, _toConsumableArray(points)); | ||
timelineWindowGraphs.push(_objectSpread({}, line, { | ||
points: points | ||
points: points, | ||
min: min, | ||
max: max, | ||
normalized: _objectSpread({}, line.normalized, { | ||
points: line.normalized.points.slice(minXIndex, maxXIndex + 1) | ||
}) | ||
})); // minY = Math.min(minY, ...points) | ||
@@ -267,6 +345,9 @@ | ||
} // Set canvas `viewBox`. | ||
// (add some side padding so that it doesn't trim the graphs on their sides) | ||
canvas.setAttribute('viewBox', "".concat(minX, " ").concat(minY, " ").concat(maxX - minX, " ").concat(maxY - minY)); // Calculate grid lines' coordinates. | ||
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.lines[0].normalized.shift) / data.lines[0].normalized.scale; | ||
var maxYNormalized = (maxY - data.lines[0].normalized.shift) / data.lines[0].normalized.scale; | ||
canvas.setAttribute('viewBox', "".concat(minXNormalized, " ").concat(minYNormalized, " ").concat(maxXNormalized - minXNormalized, " ").concat(maxYNormalized - minYNormalized)); // Calculate grid lines' coordinates. | ||
@@ -278,47 +359,46 @@ var minY_ = 0; | ||
for (var _iterator4 = yAxisTickMarks, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { | ||
var _ref4; | ||
for (var _iterator6 = yAxisTickMarks, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { | ||
var _ref6; | ||
if (_isArray4) { | ||
if (_i5 >= _iterator4.length) break; | ||
_ref4 = _iterator4[_i5++]; | ||
if (_isArray6) { | ||
if (_i7 >= _iterator6.length) break; | ||
_ref6 = _iterator6[_i7++]; | ||
} else { | ||
_i5 = _iterator4.next(); | ||
if (_i5.done) break; | ||
_ref4 = _i5.value; | ||
_i7 = _iterator6.next(); | ||
if (_i7.done) break; | ||
_ref6 = _i7.value; | ||
} | ||
var y = _ref4; | ||
canvas.appendChild(createGridLine(y, minX, maxX, minY, maxY)); | ||
var y = _ref6; | ||
canvas.appendChild(createGridLine((y - data.lines[0].normalized.shift) / data.lines[0].normalized.scale, minXNormalized, maxXNormalized, minYNormalized, maxYNormalized)); | ||
} // Trim X axis. | ||
var _x = xScaled.slice(); | ||
var _x = timelineWindowX.slice(); | ||
var _minX = _x[0]; | ||
var _maxX = _x[_x.length - 1]; | ||
var trimLeftRatio = (minX - _minX) / (_x[1] - _minX); | ||
var trimRightRatio = (_maxX - maxX) / (_maxX - _x[_x.length - 2]); | ||
_x[0] = minX; | ||
_x[_x.length - 1] = maxX; // Draw graphs. | ||
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 _iterator5 = timelineWindowGraphs, _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { | ||
var _ref5; | ||
for (var _iterator7 = timelineWindowGraphs, _isArray7 = Array.isArray(_iterator7), _i8 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { | ||
var _ref7; | ||
if (_isArray5) { | ||
if (_i6 >= _iterator5.length) break; | ||
_ref5 = _iterator5[_i6++]; | ||
if (_isArray7) { | ||
if (_i8 >= _iterator7.length) break; | ||
_ref7 = _iterator7[_i8++]; | ||
} else { | ||
_i6 = _iterator5.next(); | ||
if (_i6.done) break; | ||
_ref5 = _i6.value; | ||
_i8 = _iterator7.next(); | ||
if (_i8.done) break; | ||
_ref7 = _i8.value; | ||
} | ||
var _ref6 = _ref5, | ||
id = _ref6.id, | ||
color = _ref6.color, | ||
_points = _ref6.points; | ||
var graph = document.createElement('polyline'); | ||
graph.setAttribute('stroke', color); | ||
var _ref8 = _ref7, | ||
id = _ref8.id, | ||
color = _ref8.color, | ||
_points = _ref8.normalized.points; | ||
// Trim chart. | ||
var _y = _points.slice(); | ||
@@ -329,5 +409,8 @@ | ||
_y[0] = _minY + (_y[1] - _minY) * trimLeftRatio; | ||
_y[_y.length - 1] = _maxY - (_maxY - _y[_y.length - 2]) * trimRightRatio; | ||
graph.setAttribute('points', commaJoin(_x, _y.map(function (y) { | ||
return maxY - yScale * y; | ||
_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(' ')); | ||
@@ -342,12 +425,11 @@ graph.classList.add('chartogram__graph'); | ||
drawGauges(x[0], x[x.length - 1], minY_, maxY_, yAxisScale); // Draw timeline graph. | ||
drawGauges(minX, maxX, minY_, maxY_, yAxisScale); // Draw timeline graph. | ||
timelineWindowMinY = minY; | ||
timelineWindowMaxY = maxY; | ||
timelineWindowMinX = minX; | ||
timelineWindowMaxX = maxX; | ||
timelineWindowXScaled = xScaled; | ||
timelineWindowMinY = minYNormalized; | ||
timelineWindowMaxY = maxYNormalized; | ||
timelineWindowMinX = minXNormalized; | ||
timelineWindowMaxX = maxXNormalized; | ||
if (redrawTimeline) { | ||
drawTimeline(graphsAll, xScaledAll, minXOverall, maxXOverall, minY, maxYOverall); | ||
drawTimeline(); | ||
} | ||
@@ -374,6 +456,6 @@ } // function animateScale(scale) { | ||
line.classList.add('chartogram__grid-line'); | ||
line.setAttribute('x1', minX); | ||
line.setAttribute('x2', maxX); | ||
line.setAttribute('y1', maxY - minY - y); | ||
line.setAttribute('y2', maxY - minY - y); | ||
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; | ||
@@ -445,3 +527,15 @@ } | ||
function drawTimeline(graphs, x, minX, maxX, minY, maxY) { | ||
function drawTimeline() { | ||
var x = data.x.normalized.points; | ||
var graphs = data.lines.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`. | ||
@@ -451,20 +545,20 @@ | ||
for (var _iterator6 = graphs, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { | ||
var _ref7; | ||
for (var _iterator8 = graphs, _isArray8 = Array.isArray(_iterator8), _i9 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { | ||
var _ref9; | ||
if (_isArray6) { | ||
if (_i7 >= _iterator6.length) break; | ||
_ref7 = _iterator6[_i7++]; | ||
if (_isArray8) { | ||
if (_i9 >= _iterator8.length) break; | ||
_ref9 = _iterator8[_i9++]; | ||
} else { | ||
_i7 = _iterator6.next(); | ||
if (_i7.done) break; | ||
_ref7 = _i7.value; | ||
_i9 = _iterator8.next(); | ||
if (_i9.done) break; | ||
_ref9 = _i9.value; | ||
} | ||
var _ref8 = _ref7, | ||
id = _ref8.id, | ||
color = _ref8.color, | ||
points = _ref8.points; | ||
var _ref10 = _ref9, | ||
id = _ref10.id, | ||
color = _ref10.color, | ||
points = _ref10.normalized.points; | ||
var _simplifyGraph = simplifyGraph(x, points, TIMELINE_CHART_MAX_POINTS), | ||
var _simplifyGraph = simplifyGraph(x, points, 80), | ||
_simplifyGraph2 = _slicedToArray(_simplifyGraph, 2), | ||
@@ -476,3 +570,3 @@ _x = _simplifyGraph2[0], | ||
graph.setAttribute('stroke', color); | ||
graph.setAttribute('points', commaJoin(_x, _y.map(function (y) { | ||
graph.setAttribute('points', createPolylinePoints(_x, _y.map(function (y) { | ||
return maxY - minY - y; | ||
@@ -489,6 +583,6 @@ })).join(' ')); | ||
function createGraphToggler(_ref9) { | ||
var id = _ref9.id, | ||
name = _ref9.name, | ||
color = _ref9.color; | ||
function createGraphToggler(_ref11) { | ||
var id = _ref11.id, | ||
name = _ref11.name, | ||
color = _ref11.color; | ||
var toggler = document.createElement('button'); | ||
@@ -540,11 +634,4 @@ toggler.setAttribute('type', 'button'); | ||
} | ||
} // showGraphsNext = { ...showGraphs } | ||
// showGraphsNext[id] = show | ||
// const maxYNext = getMaxY(timelineWindowGraphs.filter(_ => showGraphsNext[_.id])) | ||
// const scale = timelineWindowMaxY / maxYNext | ||
// if (scale !== 1) { | ||
// animateScale(scale) | ||
// } | ||
} | ||
showGraphs[id] = show; | ||
@@ -560,15 +647,15 @@ drawGraphs(true); | ||
for (var _iterator7 = graphs, _isArray7 = Array.isArray(_iterator7), _i8 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { | ||
var _ref10; | ||
for (var _iterator9 = graphs, _isArray9 = Array.isArray(_iterator9), _i10 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { | ||
var _ref12; | ||
if (_isArray7) { | ||
if (_i8 >= _iterator7.length) break; | ||
_ref10 = _iterator7[_i8++]; | ||
if (_isArray9) { | ||
if (_i10 >= _iterator9.length) break; | ||
_ref12 = _iterator9[_i10++]; | ||
} else { | ||
_i8 = _iterator7.next(); | ||
if (_i8.done) break; | ||
_ref10 = _i8.value; | ||
_i10 = _iterator9.next(); | ||
if (_i10.done) break; | ||
_ref12 = _i10.value; | ||
} | ||
var graph = _ref10; | ||
var graph = _ref12; | ||
maxY = Math.max.apply(Math, [maxY].concat(_toConsumableArray(graph.points))); | ||
@@ -721,3 +808,3 @@ } | ||
var x = timelineWindowMinX + xScreenRatio * (timelineWindowMaxX - timelineWindowMinX); | ||
var xHigherIndex = timelineWindowXScaled.findIndex(function (_) { | ||
var xHigherIndex = timelineWindowX.findIndex(function (_) { | ||
return _ >= x; | ||
@@ -739,10 +826,10 @@ }); | ||
} else { | ||
x = timelineWindowXScaled[xLowerIndex]; | ||
x = timelineWindowX[xLowerIndex]; | ||
} | ||
} else { | ||
if (xLowerIndex < 0) { | ||
x = timelineWindowXScaled[xHigherIndex]; | ||
x = timelineWindowX[xHigherIndex]; | ||
} else { | ||
var xLower = timelineWindowXScaled[xLowerIndex]; | ||
var xHigher = timelineWindowXScaled[xHigherIndex]; | ||
var xLower = timelineWindowX[xLowerIndex]; | ||
var xHigher = timelineWindowX[xHigherIndex]; | ||
var deltaLower = x - xLower; | ||
@@ -761,5 +848,5 @@ var deltaHigher = xHigher - x; | ||
var date = new Date(x * 1000 + shiftX); | ||
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 = timelineWindowXScaled.indexOf(x); | ||
var xIndex = timelineWindowX.indexOf(x); | ||
var i = 0; | ||
@@ -788,3 +875,3 @@ | ||
return timelineWindowXScaled[index] >= timelineWindowMinX && timelineWindowXScaled[index] <= timelineWindowMaxX; | ||
return timelineWindowX[index] >= timelineWindowMinX && timelineWindowX[index] <= timelineWindowMaxX; | ||
}; | ||
@@ -866,15 +953,15 @@ } | ||
for (var _iterator8 = data.lines, _isArray8 = Array.isArray(_iterator8), _i9 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { | ||
var _ref11; | ||
for (var _iterator10 = data.lines, _isArray10 = Array.isArray(_iterator10), _i11 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { | ||
var _ref13; | ||
if (_isArray8) { | ||
if (_i9 >= _iterator8.length) break; | ||
_ref11 = _iterator8[_i9++]; | ||
if (_isArray10) { | ||
if (_i11 >= _iterator10.length) break; | ||
_ref13 = _iterator10[_i11++]; | ||
} else { | ||
_i9 = _iterator8.next(); | ||
if (_i9.done) break; | ||
_ref11 = _i9.value; | ||
_i11 = _iterator10.next(); | ||
if (_i11.done) break; | ||
_ref13 = _i11.value; | ||
} | ||
var line = _ref11; | ||
var line = _ref13; | ||
@@ -931,15 +1018,15 @@ if (showGraphs[line.id]) { | ||
function removeTooltipPoints() { | ||
for (var _iterator9 = tooltipPoints, _isArray9 = Array.isArray(_iterator9), _i10 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { | ||
var _ref12; | ||
for (var _iterator11 = tooltipPoints, _isArray11 = Array.isArray(_iterator11), _i12 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { | ||
var _ref14; | ||
if (_isArray9) { | ||
if (_i10 >= _iterator9.length) break; | ||
_ref12 = _iterator9[_i10++]; | ||
if (_isArray11) { | ||
if (_i12 >= _iterator11.length) break; | ||
_ref14 = _iterator11[_i12++]; | ||
} else { | ||
_i10 = _iterator9.next(); | ||
if (_i10.done) break; | ||
_ref12 = _i10.value; | ||
_i12 = _iterator11.next(); | ||
if (_i12.done) break; | ||
_ref14 = _i12.value; | ||
} | ||
var point = _ref12; | ||
var point = _ref14; | ||
canvasWrapper.removeChild(point); | ||
@@ -956,6 +1043,6 @@ } | ||
tooltipLine.setAttributeNS(null, 'x1', x); | ||
tooltipLine.setAttributeNS(null, 'x2', x); | ||
tooltipLine.setAttributeNS(null, 'y1', timelineWindowMinY); | ||
tooltipLine.setAttributeNS(null, 'y2', timelineWindowMaxY); | ||
tooltipLine.setAttributeNS(null, 'x1', fixSvgCoordinate(x)); | ||
tooltipLine.setAttributeNS(null, 'x2', fixSvgCoordinate(x)); | ||
tooltipLine.setAttributeNS(null, 'y1', fixSvgCoordinate(timelineWindowMinY)); | ||
tooltipLine.setAttributeNS(null, 'y2', fixSvgCoordinate(timelineWindowMaxY)); | ||
} | ||
@@ -973,3 +1060,3 @@ | ||
point.style.left = "".concat(xRatio * 100, "%"); | ||
var y = timelineWindowGraphs[i].points[xIndex]; | ||
var y = timelineWindowGraphs[i].normalized.points[xIndex]; | ||
var yRatio = y / timelineWindowMaxY; | ||
@@ -976,0 +1063,0 @@ point.style.bottom = "".concat(yRatio * 100, "%"); |
@@ -54,4 +54,3 @@ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } | ||
var timelineWindowMaxY; | ||
var shiftX; | ||
var timelineWindowXScaled; | ||
var timelineWindowX; | ||
var tooltip; | ||
@@ -68,2 +67,3 @@ var tooltipDate; | ||
setUpTimelineWindow(); | ||
normalizeDataPoints(); | ||
displayGraphs(); | ||
@@ -84,2 +84,12 @@ setUpCanvas(); | ||
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) { | ||
@@ -126,8 +136,17 @@ while (true) { | ||
} | ||
} // 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.lines); | ||
} | ||
function displayGraphs() { | ||
showGraphs = {}; | ||
function normalizePoints(all) { | ||
var isX = all[0] === data.x; | ||
var min = Infinity; | ||
var max = -Infinity; | ||
for (var _iterator = data.lines, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
for (var _iterator = all, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref; | ||
@@ -144,3 +163,65 @@ | ||
var line = _ref; | ||
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.lines, _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 line = _ref3; | ||
showGraphs[line.id] = true; | ||
@@ -168,15 +249,15 @@ } | ||
for (var _iterator2 = data.lines, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { | ||
var _ref2; | ||
for (var _iterator4 = data.lines, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { | ||
var _ref4; | ||
if (_isArray2) { | ||
if (_i3 >= _iterator2.length) break; | ||
_ref2 = _iterator2[_i3++]; | ||
if (_isArray4) { | ||
if (_i5 >= _iterator4.length) break; | ||
_ref4 = _iterator4[_i5++]; | ||
} else { | ||
_i3 = _iterator2.next(); | ||
if (_i3.done) break; | ||
_ref2 = _i3.value; | ||
_i5 = _iterator4.next(); | ||
if (_i5.done) break; | ||
_ref4 = _i5.value; | ||
} | ||
var _line = _ref2; | ||
var _line = _ref4; | ||
graphTogglers.appendChild(createGraphToggler(_line)); | ||
@@ -187,18 +268,12 @@ } | ||
function drawGraphs(redrawTimeline) { | ||
var x = data.x.points; // Chrome can't handle timestamps in milliseconds for point coordinates (draws nothing). | ||
// Reducing timestamps to lower numbers to work around that bug. | ||
shiftX = x[0]; | ||
var xScaledAll = x.map(function (_) { | ||
return (_ - shiftX) / 1000; | ||
}); // Clear canvas. | ||
// Clear canvas. | ||
clearElement(canvas); // Calculate bounds. | ||
var minXOverall = xScaledAll[0]; | ||
var maxXOverall = xScaledAll[xScaledAll.length - 1]; | ||
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 = xScaledAll.findIndex(function (x) { | ||
var minXIndex = xPoints.findIndex(function (x) { | ||
return x > minX; | ||
@@ -211,3 +286,3 @@ }) - 1; | ||
var maxXIndex = xScaledAll.findIndex(function (x) { | ||
var maxXIndex = xPoints.findIndex(function (x) { | ||
return x > maxX; | ||
@@ -217,28 +292,25 @@ }); | ||
if (maxXIndex < 0) { | ||
maxXIndex = xScaledAll.length - 1; | ||
maxXIndex = xPoints.length - 1; | ||
} | ||
var xScaled = xScaledAll.slice(minXIndex, maxXIndex + 1); // let minY = Infinity | ||
// let minYOverall = Infinity | ||
timelineWindowX = data.x.normalized.points.slice(minXIndex, maxXIndex + 1); // let minY = Infinity | ||
// Min Y is always 0 by design. | ||
var minY = 0; | ||
var maxY = 0; | ||
var maxYOverall = 0; | ||
var maxY = -Infinity; | ||
timelineWindowGraphs = []; | ||
var graphsAll = []; | ||
for (var _iterator3 = data.lines, _isArray3 = Array.isArray(_iterator3), _i4 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref3; | ||
for (var _iterator5 = data.lines, _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { | ||
var _ref5; | ||
if (_isArray3) { | ||
if (_i4 >= _iterator3.length) break; | ||
_ref3 = _iterator3[_i4++]; | ||
if (_isArray5) { | ||
if (_i6 >= _iterator5.length) break; | ||
_ref5 = _iterator5[_i6++]; | ||
} else { | ||
_i4 = _iterator3.next(); | ||
if (_i4.done) break; | ||
_ref3 = _i4.value; | ||
_i6 = _iterator5.next(); | ||
if (_i6.done) break; | ||
_ref5 = _i6.value; | ||
} | ||
var line = _ref3; | ||
var line = _ref5; | ||
@@ -249,8 +321,14 @@ if (!showGraphs[line.id]) { | ||
graphsAll.push(line); // minYOverall = Math.min(minYOverall, ...line.points) | ||
var points = line.points.slice(minXIndex, maxXIndex + 1); // Min Y is always 0 by design. | ||
maxYOverall = Math.max.apply(Math, [maxYOverall].concat(_toConsumableArray(line.points))); | ||
var points = line.points.slice(minXIndex, maxXIndex + 1); | ||
var min = 0; // const min = Math.min(...points) | ||
var max = Math.max.apply(Math, _toConsumableArray(points)); | ||
timelineWindowGraphs.push(_objectSpread({}, line, { | ||
points: points | ||
points: points, | ||
min: min, | ||
max: max, | ||
normalized: _objectSpread({}, line.normalized, { | ||
points: line.normalized.points.slice(minXIndex, maxXIndex + 1) | ||
}) | ||
})); // minY = Math.min(minY, ...points) | ||
@@ -260,6 +338,9 @@ | ||
} // Set canvas `viewBox`. | ||
// (add some side padding so that it doesn't trim the graphs on their sides) | ||
canvas.setAttribute('viewBox', "".concat(minX, " ").concat(minY, " ").concat(maxX - minX, " ").concat(maxY - minY)); // Calculate grid lines' coordinates. | ||
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.lines[0].normalized.shift) / data.lines[0].normalized.scale; | ||
var maxYNormalized = (maxY - data.lines[0].normalized.shift) / data.lines[0].normalized.scale; | ||
canvas.setAttribute('viewBox', "".concat(minXNormalized, " ").concat(minYNormalized, " ").concat(maxXNormalized - minXNormalized, " ").concat(maxYNormalized - minYNormalized)); // Calculate grid lines' coordinates. | ||
@@ -271,47 +352,46 @@ var minY_ = 0; | ||
for (var _iterator4 = yAxisTickMarks, _isArray4 = Array.isArray(_iterator4), _i5 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { | ||
var _ref4; | ||
for (var _iterator6 = yAxisTickMarks, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { | ||
var _ref6; | ||
if (_isArray4) { | ||
if (_i5 >= _iterator4.length) break; | ||
_ref4 = _iterator4[_i5++]; | ||
if (_isArray6) { | ||
if (_i7 >= _iterator6.length) break; | ||
_ref6 = _iterator6[_i7++]; | ||
} else { | ||
_i5 = _iterator4.next(); | ||
if (_i5.done) break; | ||
_ref4 = _i5.value; | ||
_i7 = _iterator6.next(); | ||
if (_i7.done) break; | ||
_ref6 = _i7.value; | ||
} | ||
var y = _ref4; | ||
canvas.appendChild(createGridLine(y, minX, maxX, minY, maxY)); | ||
var y = _ref6; | ||
canvas.appendChild(createGridLine((y - data.lines[0].normalized.shift) / data.lines[0].normalized.scale, minXNormalized, maxXNormalized, minYNormalized, maxYNormalized)); | ||
} // Trim X axis. | ||
var _x = xScaled.slice(); | ||
var _x = timelineWindowX.slice(); | ||
var _minX = _x[0]; | ||
var _maxX = _x[_x.length - 1]; | ||
var trimLeftRatio = (minX - _minX) / (_x[1] - _minX); | ||
var trimRightRatio = (_maxX - maxX) / (_maxX - _x[_x.length - 2]); | ||
_x[0] = minX; | ||
_x[_x.length - 1] = maxX; // Draw graphs. | ||
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 _iterator5 = timelineWindowGraphs, _isArray5 = Array.isArray(_iterator5), _i6 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { | ||
var _ref5; | ||
for (var _iterator7 = timelineWindowGraphs, _isArray7 = Array.isArray(_iterator7), _i8 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { | ||
var _ref7; | ||
if (_isArray5) { | ||
if (_i6 >= _iterator5.length) break; | ||
_ref5 = _iterator5[_i6++]; | ||
if (_isArray7) { | ||
if (_i8 >= _iterator7.length) break; | ||
_ref7 = _iterator7[_i8++]; | ||
} else { | ||
_i6 = _iterator5.next(); | ||
if (_i6.done) break; | ||
_ref5 = _i6.value; | ||
_i8 = _iterator7.next(); | ||
if (_i8.done) break; | ||
_ref7 = _i8.value; | ||
} | ||
var _ref6 = _ref5, | ||
id = _ref6.id, | ||
color = _ref6.color, | ||
_points = _ref6.points; | ||
var graph = document.createElement('polyline'); | ||
graph.setAttribute('stroke', color); | ||
var _ref8 = _ref7, | ||
id = _ref8.id, | ||
color = _ref8.color, | ||
_points = _ref8.normalized.points; | ||
// Trim chart. | ||
var _y = _points.slice(); | ||
@@ -322,5 +402,8 @@ | ||
_y[0] = _minY + (_y[1] - _minY) * trimLeftRatio; | ||
_y[_y.length - 1] = _maxY - (_maxY - _y[_y.length - 2]) * trimRightRatio; | ||
graph.setAttribute('points', commaJoin(_x, _y.map(function (y) { | ||
return maxY - yScale * y; | ||
_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(' ')); | ||
@@ -335,12 +418,11 @@ graph.classList.add('chartogram__graph'); | ||
drawGauges(x[0], x[x.length - 1], minY_, maxY_, yAxisScale); // Draw timeline graph. | ||
drawGauges(minX, maxX, minY_, maxY_, yAxisScale); // Draw timeline graph. | ||
timelineWindowMinY = minY; | ||
timelineWindowMaxY = maxY; | ||
timelineWindowMinX = minX; | ||
timelineWindowMaxX = maxX; | ||
timelineWindowXScaled = xScaled; | ||
timelineWindowMinY = minYNormalized; | ||
timelineWindowMaxY = maxYNormalized; | ||
timelineWindowMinX = minXNormalized; | ||
timelineWindowMaxX = maxXNormalized; | ||
if (redrawTimeline) { | ||
drawTimeline(graphsAll, xScaledAll, minXOverall, maxXOverall, minY, maxYOverall); | ||
drawTimeline(); | ||
} | ||
@@ -367,6 +449,6 @@ } // function animateScale(scale) { | ||
line.classList.add('chartogram__grid-line'); | ||
line.setAttribute('x1', minX); | ||
line.setAttribute('x2', maxX); | ||
line.setAttribute('y1', maxY - minY - y); | ||
line.setAttribute('y2', maxY - minY - y); | ||
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; | ||
@@ -438,3 +520,15 @@ } | ||
function drawTimeline(graphs, x, minX, maxX, minY, maxY) { | ||
function drawTimeline() { | ||
var x = data.x.normalized.points; | ||
var graphs = data.lines.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`. | ||
@@ -444,20 +538,20 @@ | ||
for (var _iterator6 = graphs, _isArray6 = Array.isArray(_iterator6), _i7 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) { | ||
var _ref7; | ||
for (var _iterator8 = graphs, _isArray8 = Array.isArray(_iterator8), _i9 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { | ||
var _ref9; | ||
if (_isArray6) { | ||
if (_i7 >= _iterator6.length) break; | ||
_ref7 = _iterator6[_i7++]; | ||
if (_isArray8) { | ||
if (_i9 >= _iterator8.length) break; | ||
_ref9 = _iterator8[_i9++]; | ||
} else { | ||
_i7 = _iterator6.next(); | ||
if (_i7.done) break; | ||
_ref7 = _i7.value; | ||
_i9 = _iterator8.next(); | ||
if (_i9.done) break; | ||
_ref9 = _i9.value; | ||
} | ||
var _ref8 = _ref7, | ||
id = _ref8.id, | ||
color = _ref8.color, | ||
points = _ref8.points; | ||
var _ref10 = _ref9, | ||
id = _ref10.id, | ||
color = _ref10.color, | ||
points = _ref10.normalized.points; | ||
var _simplifyGraph = simplifyGraph(x, points, TIMELINE_CHART_MAX_POINTS), | ||
var _simplifyGraph = simplifyGraph(x, points, 80), | ||
_simplifyGraph2 = _slicedToArray(_simplifyGraph, 2), | ||
@@ -469,3 +563,3 @@ _x = _simplifyGraph2[0], | ||
graph.setAttribute('stroke', color); | ||
graph.setAttribute('points', commaJoin(_x, _y.map(function (y) { | ||
graph.setAttribute('points', createPolylinePoints(_x, _y.map(function (y) { | ||
return maxY - minY - y; | ||
@@ -482,6 +576,6 @@ })).join(' ')); | ||
function createGraphToggler(_ref9) { | ||
var id = _ref9.id, | ||
name = _ref9.name, | ||
color = _ref9.color; | ||
function createGraphToggler(_ref11) { | ||
var id = _ref11.id, | ||
name = _ref11.name, | ||
color = _ref11.color; | ||
var toggler = document.createElement('button'); | ||
@@ -533,11 +627,4 @@ toggler.setAttribute('type', 'button'); | ||
} | ||
} // showGraphsNext = { ...showGraphs } | ||
// showGraphsNext[id] = show | ||
// const maxYNext = getMaxY(timelineWindowGraphs.filter(_ => showGraphsNext[_.id])) | ||
// const scale = timelineWindowMaxY / maxYNext | ||
// if (scale !== 1) { | ||
// animateScale(scale) | ||
// } | ||
} | ||
showGraphs[id] = show; | ||
@@ -553,15 +640,15 @@ drawGraphs(true); | ||
for (var _iterator7 = graphs, _isArray7 = Array.isArray(_iterator7), _i8 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) { | ||
var _ref10; | ||
for (var _iterator9 = graphs, _isArray9 = Array.isArray(_iterator9), _i10 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { | ||
var _ref12; | ||
if (_isArray7) { | ||
if (_i8 >= _iterator7.length) break; | ||
_ref10 = _iterator7[_i8++]; | ||
if (_isArray9) { | ||
if (_i10 >= _iterator9.length) break; | ||
_ref12 = _iterator9[_i10++]; | ||
} else { | ||
_i8 = _iterator7.next(); | ||
if (_i8.done) break; | ||
_ref10 = _i8.value; | ||
_i10 = _iterator9.next(); | ||
if (_i10.done) break; | ||
_ref12 = _i10.value; | ||
} | ||
var graph = _ref10; | ||
var graph = _ref12; | ||
maxY = Math.max.apply(Math, [maxY].concat(_toConsumableArray(graph.points))); | ||
@@ -714,3 +801,3 @@ } | ||
var x = timelineWindowMinX + xScreenRatio * (timelineWindowMaxX - timelineWindowMinX); | ||
var xHigherIndex = timelineWindowXScaled.findIndex(function (_) { | ||
var xHigherIndex = timelineWindowX.findIndex(function (_) { | ||
return _ >= x; | ||
@@ -732,10 +819,10 @@ }); | ||
} else { | ||
x = timelineWindowXScaled[xLowerIndex]; | ||
x = timelineWindowX[xLowerIndex]; | ||
} | ||
} else { | ||
if (xLowerIndex < 0) { | ||
x = timelineWindowXScaled[xHigherIndex]; | ||
x = timelineWindowX[xHigherIndex]; | ||
} else { | ||
var xLower = timelineWindowXScaled[xLowerIndex]; | ||
var xHigher = timelineWindowXScaled[xHigherIndex]; | ||
var xLower = timelineWindowX[xLowerIndex]; | ||
var xHigher = timelineWindowX[xHigherIndex]; | ||
var deltaLower = x - xLower; | ||
@@ -754,5 +841,5 @@ var deltaHigher = xHigher - x; | ||
var date = new Date(x * 1000 + shiftX); | ||
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 = timelineWindowXScaled.indexOf(x); | ||
var xIndex = timelineWindowX.indexOf(x); | ||
var i = 0; | ||
@@ -781,3 +868,3 @@ | ||
return timelineWindowXScaled[index] >= timelineWindowMinX && timelineWindowXScaled[index] <= timelineWindowMaxX; | ||
return timelineWindowX[index] >= timelineWindowMinX && timelineWindowX[index] <= timelineWindowMaxX; | ||
}; | ||
@@ -859,15 +946,15 @@ } | ||
for (var _iterator8 = data.lines, _isArray8 = Array.isArray(_iterator8), _i9 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) { | ||
var _ref11; | ||
for (var _iterator10 = data.lines, _isArray10 = Array.isArray(_iterator10), _i11 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) { | ||
var _ref13; | ||
if (_isArray8) { | ||
if (_i9 >= _iterator8.length) break; | ||
_ref11 = _iterator8[_i9++]; | ||
if (_isArray10) { | ||
if (_i11 >= _iterator10.length) break; | ||
_ref13 = _iterator10[_i11++]; | ||
} else { | ||
_i9 = _iterator8.next(); | ||
if (_i9.done) break; | ||
_ref11 = _i9.value; | ||
_i11 = _iterator10.next(); | ||
if (_i11.done) break; | ||
_ref13 = _i11.value; | ||
} | ||
var line = _ref11; | ||
var line = _ref13; | ||
@@ -924,15 +1011,15 @@ if (showGraphs[line.id]) { | ||
function removeTooltipPoints() { | ||
for (var _iterator9 = tooltipPoints, _isArray9 = Array.isArray(_iterator9), _i10 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) { | ||
var _ref12; | ||
for (var _iterator11 = tooltipPoints, _isArray11 = Array.isArray(_iterator11), _i12 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) { | ||
var _ref14; | ||
if (_isArray9) { | ||
if (_i10 >= _iterator9.length) break; | ||
_ref12 = _iterator9[_i10++]; | ||
if (_isArray11) { | ||
if (_i12 >= _iterator11.length) break; | ||
_ref14 = _iterator11[_i12++]; | ||
} else { | ||
_i10 = _iterator9.next(); | ||
if (_i10.done) break; | ||
_ref12 = _i10.value; | ||
_i12 = _iterator11.next(); | ||
if (_i12.done) break; | ||
_ref14 = _i12.value; | ||
} | ||
var point = _ref12; | ||
var point = _ref14; | ||
canvasWrapper.removeChild(point); | ||
@@ -949,6 +1036,6 @@ } | ||
tooltipLine.setAttributeNS(null, 'x1', x); | ||
tooltipLine.setAttributeNS(null, 'x2', x); | ||
tooltipLine.setAttributeNS(null, 'y1', timelineWindowMinY); | ||
tooltipLine.setAttributeNS(null, 'y2', timelineWindowMaxY); | ||
tooltipLine.setAttributeNS(null, 'x1', fixSvgCoordinate(x)); | ||
tooltipLine.setAttributeNS(null, 'x2', fixSvgCoordinate(x)); | ||
tooltipLine.setAttributeNS(null, 'y1', fixSvgCoordinate(timelineWindowMinY)); | ||
tooltipLine.setAttributeNS(null, 'y2', fixSvgCoordinate(timelineWindowMaxY)); | ||
} | ||
@@ -966,3 +1053,3 @@ | ||
point.style.left = "".concat(xRatio * 100, "%"); | ||
var y = timelineWindowGraphs[i].points[xIndex]; | ||
var y = timelineWindowGraphs[i].normalized.points[xIndex]; | ||
var yRatio = y / timelineWindowMaxY; | ||
@@ -969,0 +1056,0 @@ point.style.bottom = "".concat(yRatio * 100, "%"); |
{ | ||
"name": "chartogram", | ||
"version": "0.1.2", | ||
"version": "0.1.3", | ||
"description": "Charts in JS with no dependencies", | ||
@@ -5,0 +5,0 @@ "main": "index.commonjs.js", |
@@ -110,10 +110,6 @@ # chartogram | ||
Tested in Chrome and iOS Safari. | ||
Tested in Chrome, Firefox and iOS Safari. | ||
Mostly works in Firefox but SVG canvas drawing is buggy for some reason. | ||
Won't work in Edge or Internet Explorer. | ||
Throws some syntax error in Edge. | ||
Won't support Internet Explorer. | ||
The styles use [CSS variables](https://caniuse.com/#feat=css-variables) which work everywhere except Internet Explorer. |
@@ -88,4 +88,3 @@ export default function chartogram(rootNode, data, title = 'Title', options = {}) { | ||
let timelineWindowMaxY | ||
let shiftX | ||
let timelineWindowXScaled | ||
let timelineWindowX | ||
let tooltip | ||
@@ -105,2 +104,3 @@ let tooltipDate | ||
normalizeDataPoints() | ||
displayGraphs() | ||
@@ -119,2 +119,12 @@ setUpCanvas() | ||
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) { | ||
@@ -156,2 +166,41 @@ while (true) { | ||
// 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.lines) | ||
} | ||
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() { | ||
@@ -184,32 +233,25 @@ showGraphs = {} | ||
function drawGraphs(redrawTimeline) { | ||
const x = data.x.points | ||
// Chrome can't handle timestamps in milliseconds for point coordinates (draws nothing). | ||
// Reducing timestamps to lower numbers to work around that bug. | ||
shiftX = x[0] | ||
const xScaledAll = x.map(_ => (_ - shiftX) / 1000) | ||
// Clear canvas. | ||
clearElement(canvas) | ||
// Calculate bounds. | ||
const minXOverall = xScaledAll[0] | ||
const maxXOverall = xScaledAll[xScaledAll.length - 1] | ||
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 = xScaledAll.findIndex(x => x > minX) - 1 | ||
let minXIndex = xPoints.findIndex(x => x > minX) - 1 | ||
if (minXIndex < 0) { | ||
minXIndex = 0 | ||
} | ||
let maxXIndex = xScaledAll.findIndex(x => x > maxX) | ||
let maxXIndex = xPoints.findIndex(x => x > maxX) | ||
if (maxXIndex < 0) { | ||
maxXIndex = xScaledAll.length - 1 | ||
maxXIndex = xPoints.length - 1 | ||
} | ||
const xScaled = xScaledAll.slice(minXIndex, maxXIndex + 1) | ||
timelineWindowX = data.x.normalized.points.slice(minXIndex, maxXIndex + 1) | ||
// let minY = Infinity | ||
// let minYOverall = Infinity | ||
// Min Y is always 0 by design. | ||
const minY = 0 | ||
let maxY = 0 | ||
let maxYOverall = 0 | ||
let maxY = -Infinity | ||
timelineWindowGraphs = [] | ||
const graphsAll = [] | ||
for (const line of data.lines) { | ||
@@ -219,9 +261,16 @@ if (!showGraphs[line.id]) { | ||
} | ||
graphsAll.push(line) | ||
// minYOverall = Math.min(minYOverall, ...line.points) | ||
maxYOverall = Math.max(maxYOverall, ...line.points) | ||
const points = line.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({ | ||
...line, | ||
points | ||
points, | ||
min, | ||
max, | ||
normalized: { | ||
...line.normalized, | ||
points: line.normalized.points.slice(minXIndex, maxXIndex + 1) | ||
} | ||
}) | ||
@@ -232,4 +281,7 @@ // minY = Math.min(minY, ...points) | ||
// Set canvas `viewBox`. | ||
// (add some side padding so that it doesn't trim the graphs on their sides) | ||
canvas.setAttribute('viewBox', `${minX} ${minY} ${maxX - minX} ${maxY - minY}`) | ||
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.lines[0].normalized.shift) / data.lines[0].normalized.scale | ||
const maxYNormalized = (maxY - data.lines[0].normalized.shift) / data.lines[0].normalized.scale | ||
canvas.setAttribute('viewBox', `${minXNormalized} ${minYNormalized} ${maxXNormalized - minXNormalized} ${maxYNormalized - minYNormalized}`) | ||
// Calculate grid lines' coordinates. | ||
@@ -242,16 +294,21 @@ const minY_ = 0 | ||
for (const y of yAxisTickMarks) { | ||
canvas.appendChild(createGridLine(y, minX, maxX, minY, maxY)) | ||
canvas.appendChild(createGridLine( | ||
(y - data.lines[0].normalized.shift) / data.lines[0].normalized.scale, | ||
minXNormalized, | ||
maxXNormalized, | ||
minYNormalized, | ||
maxYNormalized | ||
)) | ||
} | ||
// Trim X axis. | ||
const _x = xScaled.slice() | ||
const _x = timelineWindowX.slice() | ||
const _minX = _x[0] | ||
const _maxX = _x[_x.length - 1] | ||
const trimLeftRatio = (minX - _minX) / (_x[1] - _minX) | ||
const trimRightRatio = (_maxX - maxX) / (_maxX - _x[_x.length - 2]) | ||
_x[0] = minX | ||
_x[_x.length - 1] = maxX | ||
// Draw graphs. | ||
for (const { id, color, points } of timelineWindowGraphs) { | ||
const graph = document.createElement('polyline') | ||
graph.setAttribute('stroke', color) | ||
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() | ||
@@ -262,3 +319,6 @@ const _minY = _y[0] | ||
_y[_y.length - 1] = _maxY - (_maxY - _y[_y.length - 2]) * trimRightRatio | ||
graph.setAttribute('points', commaJoin(_x, _y.map(y => maxY - yScale * y)).join(' ')) | ||
// 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') | ||
@@ -271,11 +331,16 @@ canvas.appendChild(graph) | ||
// Draw gauges. | ||
drawGauges(x[0], x[x.length - 1], minY_, maxY_, yAxisScale) | ||
drawGauges( | ||
minX, | ||
maxX, | ||
minY_, | ||
maxY_, | ||
yAxisScale | ||
) | ||
// Draw timeline graph. | ||
timelineWindowMinY = minY | ||
timelineWindowMaxY = maxY | ||
timelineWindowMinX = minX | ||
timelineWindowMaxX = maxX | ||
timelineWindowXScaled = xScaled | ||
timelineWindowMinY = minYNormalized | ||
timelineWindowMaxY = maxYNormalized | ||
timelineWindowMinX = minXNormalized | ||
timelineWindowMaxX = maxXNormalized | ||
if (redrawTimeline) { | ||
drawTimeline(graphsAll, xScaledAll, minXOverall, maxXOverall, minY, maxYOverall) | ||
drawTimeline() | ||
} | ||
@@ -304,6 +369,6 @@ } | ||
line.classList.add('chartogram__grid-line') | ||
line.setAttribute('x1', minX) | ||
line.setAttribute('x2', maxX) | ||
line.setAttribute('y1', (maxY - minY) - y) | ||
line.setAttribute('y2', (maxY - minY) - y) | ||
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 | ||
@@ -360,11 +425,17 @@ } | ||
function drawTimeline(graphs, x, minX, maxX, minY, maxY) { | ||
function drawTimeline() { | ||
const x = data.x.normalized.points | ||
const graphs = data.lines.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, points } of graphs) { | ||
const [_x, _y] = simplifyGraph(x, points, TIMELINE_CHART_MAX_POINTS) | ||
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', commaJoin(_x, _y.map(y => (maxY - minY) - y)).join(' ')) | ||
graph.setAttribute('points', createPolylinePoints(_x, _y.map(y => (maxY - minY) - y)).join(' ')) | ||
graph.classList.add('chartogram__graph') | ||
@@ -423,9 +494,2 @@ timelineCanvas.appendChild(graph) | ||
} | ||
// showGraphsNext = { ...showGraphs } | ||
// showGraphsNext[id] = show | ||
// const maxYNext = getMaxY(timelineWindowGraphs.filter(_ => showGraphsNext[_.id])) | ||
// const scale = timelineWindowMaxY / maxYNext | ||
// if (scale !== 1) { | ||
// animateScale(scale) | ||
// } | ||
showGraphs[id] = show | ||
@@ -576,3 +640,3 @@ drawGraphs(true) | ||
let x = timelineWindowMinX + xScreenRatio * (timelineWindowMaxX - timelineWindowMinX) | ||
let xHigherIndex = timelineWindowXScaled.findIndex(_ => _ >= x) | ||
let xHigherIndex = timelineWindowX.findIndex(_ => _ >= x) | ||
let xLowerIndex = xHigherIndex - 1 | ||
@@ -589,10 +653,10 @@ if (!isIndexInBounds(xHigherIndex)) { | ||
} else { | ||
x = timelineWindowXScaled[xLowerIndex] | ||
x = timelineWindowX[xLowerIndex] | ||
} | ||
} else { | ||
if (xLowerIndex < 0) { | ||
x = timelineWindowXScaled[xHigherIndex] | ||
x = timelineWindowX[xHigherIndex] | ||
} else { | ||
const xLower = timelineWindowXScaled[xLowerIndex] | ||
const xHigher = timelineWindowXScaled[xHigherIndex] | ||
const xLower = timelineWindowX[xLowerIndex] | ||
const xHigher = timelineWindowX[xHigherIndex] | ||
const deltaLower = x - xLower | ||
@@ -608,5 +672,5 @@ const deltaHigher = xHigher - x | ||
} | ||
const date = new Date(x * 1000 + shiftX) | ||
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 = timelineWindowXScaled.indexOf(x) | ||
const xIndex = timelineWindowX.indexOf(x) | ||
let i = 0 | ||
@@ -630,4 +694,4 @@ while (2 * i < tooltipValues.childNodes.length) { | ||
} | ||
return timelineWindowXScaled[index] >= timelineWindowMinX && | ||
timelineWindowXScaled[index] <= timelineWindowMaxX | ||
return timelineWindowX[index] >= timelineWindowMinX && | ||
timelineWindowX[index] <= timelineWindowMaxX | ||
} | ||
@@ -764,6 +828,6 @@ } | ||
} | ||
tooltipLine.setAttributeNS(null, 'x1', x) | ||
tooltipLine.setAttributeNS(null, 'x2', x) | ||
tooltipLine.setAttributeNS(null, 'y1', timelineWindowMinY) | ||
tooltipLine.setAttributeNS(null, 'y2', timelineWindowMaxY) | ||
tooltipLine.setAttributeNS(null, 'x1', fixSvgCoordinate(x)) | ||
tooltipLine.setAttributeNS(null, 'x2', fixSvgCoordinate(x)) | ||
tooltipLine.setAttributeNS(null, 'y1', fixSvgCoordinate(timelineWindowMinY)) | ||
tooltipLine.setAttributeNS(null, 'y2', fixSvgCoordinate(timelineWindowMaxY)) | ||
} | ||
@@ -779,3 +843,3 @@ | ||
point.style.left = `${xRatio * 100}%` | ||
const y = timelineWindowGraphs[i].points[xIndex] | ||
const y = timelineWindowGraphs[i].normalized.points[xIndex] | ||
const yRatio = y / timelineWindowMaxY | ||
@@ -782,0 +846,0 @@ point.style.bottom = `${yRatio * 100}%` |
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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
935508
2920
114