chartogram
Advanced tools
Comparing version 0.1.8 to 0.1.9
@@ -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){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")}()}function e(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function n(t,e,n,i,a){for(var o=0;o<i;){var r=document.createElement("div"),s=e+o*(n-e)/(i-1);a&&(s=a(s)),r.appendChild(document.createTextNode(s)),t.appendChild(r),o++}}function i(t,e){var n,i=0,a=function(){n=void 0,i=Date.now(),t()};return function(){var o=Date.now(),r=e-(o-i);r<=0?(n&&(clearTimeout(n),n=void 0),i=o,t()):n||(n=setTimeout(a,r))}}function a(t,e,n){function i(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",i),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",i),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 o(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=[],i=!0,a=!1,o=void 0;try{for(var r,s=t[Symbol.iterator]();!(i=(r=s.next()).done)&&(n.push(r.value),!e||n.length!==e);i=!0);}catch(t){a=!0,o=t}finally{try{i||null==s.return||s.return()}finally{if(a)throw o}}return n}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function r(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function s(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var l=function(){function n(t){var e=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,n),s(this,"onResize",function(t){e.setState({aspectRatio:e.getCanvasAspectRatio()})}),s(this,"onResizeThrottled",i(this.onResize,33)),s(this,"setState",function(t){e.state=function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),i.forEach(function(e){s(t,e,n[e])})}return t}({},e.state,t),e.render()}),s(this,"mapX",function(t){var n=e.props,i=n.canvasWidth,a=n.data,o=a.minX;return(t-o)/(a.maxX-o)*i}),s(this,"mapY",function(t){var n=e.props,i=n.canvasWidth,a=n.minYGlobal;return(t-a)/(n.maxYGlobal-a)*i/e.state.aspectRatio}),s(this,"setUpTimelineWindowHandle",function(t){var n,i,o,r,s="left"===t?e.timelineWindowLeftHandle:e.timelineWindowRightHandle,l=parseFloat(getComputedStyle(e.timelineWindow).borderLeftWidth);return a(s,function(a){n=e.timeline.getBoundingClientRect();var s=e.timelineWindow.getBoundingClientRect();"left"===t?(i=n.left,o=s.left+s.width-2*l,r=a-s.left):(i=s.left+2*l,o=n.left+n.width,r=a-(s.left+s.width))},function(a){a-=r;var s=((a=Math.max(Math.min(a,o),i))-n.left)/n.width;"left"===t?e.updateBounds(s,e.props.toRatio):e.updateBounds(e.props.fromRatio,s)})}),s(this,"setUpTimelineWindow",function(){var t,n,i,o,r;return a(e.timelineWindowDrag,function(a){t=e.timeline.getBoundingClientRect(),n=e.timelineWindow.getBoundingClientRect(),r=a-n.left,i=t.left,o=t.left+(t.width-n.width)},function(a){a-=r;var s=((a=Math.max(Math.min(a,o),i))-t.left)/t.width;e.updateBounds(s,s+n.width/t.width)})}),s(this,"setTimelineWindowLeft",function(t){e.timelineOverlayLeft.style.right="".concat(100*(1-t),"%"),e.timelineWindow.style.left="".concat(100*t,"%")}),s(this,"setTimelineWindowRight",function(t){e.timelineOverlayRight.style.left="".concat(100*t,"%"),e.timelineWindow.style.right="".concat(100*(1-t),"%")}),this.props=t}var l,c,h;return l=n,(c=[{key:"componentDidUpdate",value:function(t){this.props!==t&&(this.props=t,this.state={aspectRatio:this.getCanvasAspectRatio()},this.onChangeBounds(this.props.fromRatio,this.props.toRatio),this.render())}},{key:"componentDidMount",value:function(){var t=this.props.rootNode;this.timeline=t.querySelector(".chartogram__timeline"),this.timelineOverlayLeft=t.querySelector(".chartogram__timeline-overlay-left"),this.timelineWindowLeftHandle=t.querySelector(".chartogram__timeline-window__left-handle"),this.timelineWindow=t.querySelector(".chartogram__timeline-window"),this.timelineWindowDrag=t.querySelector(".chartogram__timeline-window__drag"),this.timelineWindowRightHandle=t.querySelector(".chartogram__timeline-window__right-handle"),this.timelineOverlayRight=t.querySelector(".chartogram__timeline-overlay-right"),this.timelineCanvas=t.querySelector(".chartogram__timeline-canvas"),this.state={aspectRatio:this.getCanvasAspectRatio()},this.setUpTimelineWindowHandle("left"),this.setUpTimelineWindowHandle("right"),this.setUpTimelineWindow(),window.addEventListener("resize",this.onResizeThrottled),this.onChangeBounds(this.props.fromRatio,this.props.toRatio),this.render()}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onResizeThrottled)}},{key:"getCanvasAspectRatio",value:function(){var t=this.timelineCanvas.getBoundingClientRect();return t.width/t.height}},{key:"render",value:function(){var n=this,i=this.props,a=i.canvasWidth,r=i.y,s=i.data,l=i.maxYGlobal,c=i.fixSvgCoordinate,h=i.createPolylinePoints,u=i.graphOpacity,d=this.state.aspectRatio;e(this.timelineCanvas),this.timelineCanvas.setAttribute("viewBox","0 0 ".concat(a," ").concat(c(a/d)));for(var p=0,m=function(){var e=s.y[p],i=e.id,a=e.color,c=e.points,d=u[p];if(r.find(function(t){return t.id===i}).isShown||d>0){var m=o(function e(n,i,a){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Math.max.apply(Math,t(i)),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(n.length),c=arguments.length>7&&void 0!==arguments[7]?arguments[7]:new Array(n.length),h=arguments.length>8&&void 0!==arguments[8]?arguments[8]:0;if(s+2>n.length-1){for(;s<i.length;)l[h]=n[s],c[h]=i[s],h++,s++;return l=l.slice(0,h),c=c.slice(0,h),l.length<=a?[l,c]:(n.length/l.length<1.1&&(r=Math.min(r+.025,1)),e(l,c,a,o,r))}var u=(i[s+2]+i[s])/2;return Math.abs(u-i[s+1])/o<r?(l[h]=n[s],l[h+1]=n[s+2],c[h]=i[s],c[h+1]=i[s+2],e(n,i,a,o,r,s+2,l,c,h+1)):(l[h]=n[s],l[h+1]=n[s+1],l[h+2]=n[s+2],c[h]=i[s],c[h+1]=i[s+1],c[h+2]=i[s+2],e(n,i,a,o,r,s+2,l,c,h+2))}(s.x.points,c,80),2),v=m[0],f=m[1],g=document.createElement("polyline");g.setAttribute("stroke",a),g.setAttribute("points",h(v.map(n.mapX),f.map(function(t){return n.mapY(l-t)})).join(" ")),g.classList.add("chartogram__graph"),1!==d&&(g.style.opacity=d),n.timelineCanvas.appendChild(g)}p++};p<s.y.length;)m();this.timelineCanvas.innerHTML+=""}},{key:"onChangeBounds",value:function(t,e){this.setTimelineWindowLeft(t),this.setTimelineWindowRight(e)}},{key:"updateBounds",value:function(t,e){this.props.onChangeBounds(t,e),this.props.fromRatio=t,this.props.toRatio=e,this.onChangeBounds(t,e)}}])&&r(l.prototype,c),h&&r(l,h),n}();function c(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function h(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}l.INITIAL_MARKUP='\n\t<div class="chartogram__timeline">\n\t\t<div class="chartogram__timeline-canvas-padding">\n\t\t\t<svg class="chartogram__timeline-canvas" preserveAspectRatio="none"></svg>\n\t\t</div>\n\t\t<div class="chartogram__timeline-overlay-left"></div>\n\t\t<div class="chartogram__timeline-overlay-right"></div>\n\t\t<div class="chartogram__timeline-window">\n\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__drag"></button>\n\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__left-handle"></button>\n\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__right-handle"></button>\n\t\t</div>\n\t</div>\n';var u=function(){function t(e){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),h(this,"createGraphToggler",function(t){var e=t.id,i=t.name,a=t.color,o=document.createElement("button");o.setAttribute("type","button"),o.classList.add("chartogram__chart-toggler"),o.classList.add("chartogram__chart-toggler--on"),o.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",a),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 h=document.createElementNS(r,"path");return h.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"),h.setAttribute("fill","white"),h.setAttribute("class","chartogram__chart-toggler-check-mark"),s.appendChild(h),o.appendChild(s),o.appendChild(document.createTextNode(i)),o.addEventListener("click",function(){return n.onToggle(e,o)}),o}),h(this,"onToggle",function(t,e){(0,n.props.onToggle)(t)&&e.classList.toggle("chartogram__chart-toggler--on")}),this.props=e}var n,i,a;return n=t,(i=[{key:"componentDidMount",value:function(){var t=this.props,n=t.rootNode,i=t.data,a=n.querySelector(".chartogram__chart-togglers");e(a);var o=i.y,r=Array.isArray(o),s=0;for(o=r?o:o[Symbol.iterator]();;){var l;if(r){if(s>=o.length)break;l=o[s++]}else{if((s=o.next()).done)break;l=s.value}var c=l;a.appendChild(this.createGraphToggler(c))}}}])&&c(n.prototype,i),a&&c(n,a),t}();function d(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function p(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}u.INITIAL_MARKUP='\n\t<div class="chartogram__chart-togglers"></div>\n';var m=function(){function t(e){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),p(this,"setUpListener",function(){var t,e,i=n.props,a=i.canvas,o=i.canvasWidthPx,r=i.weekdays,s=i.months,l=function(i){var a,l=n.props,c=l.minX,h=l.maxX,u=l.xPoints,d=l.y,p=c+(i-t.left)/t.width*(h-c),m=u.findIndex(function(t){return t>=p}),v=m-1;if(e(m)||(m=-1),e(v)||(v=-1),m<0){if(v<0)return n.unmount();a=v}else if(v<0)a=m;else{var f=u[v],g=u[m];a=p-f>g-p?m:v}var y=u[a];if(y!==n.tooltipForX){n.tooltipForX=y,n.tooltip||n.mount();var w=new Date(y);n.tooltipDate.textContent="".concat(r[w.getDay()],", ").concat(s[w.getMonth()]," ").concat(w.getDate());var b=0,x=d,_=Array.isArray(x),S=0;for(x=_?x:x[Symbol.iterator]();;){var A;if(_){if(S>=x.length)break;A=x[S++]}else{if((S=x.next()).done)break;A=S.value}var C=A,L=C.isShown,T=C.points,k=C.name;L&&(n.tooltipValues.childNodes[2*b].textContent=T[a],n.tooltipValues.childNodes[2*b+1].textContent=k,b++)}var R=(y-c)/(h-c),Y=R*o;Y-=40;var E=n.tooltip.getBoundingClientRect().width;Y<-5?Y=-5:Y+E>o+5&&(Y=o+5-E),n.tooltip.style.left=Y+"px",n.updatePoints(a,R),n.updateLine(y)}},c=function(){t=a.getBoundingClientRect(),e=function(t){var e=n.props.xPoints;return t>=0&&t<e.length}},h=function(t){if(t.touches.length>1)return p();c(),a.addEventListener("touchend",p),a.addEventListener("touchmove",u),a.addEventListener("touchend",p),a.addEventListener("touchcancel",p),u(t)};function u(e){var n=e.changedTouches[0].clientX,i=e.changedTouches[0].clientY;n<t.left||n>t.left+t.width||i<t.top||i>t.top+t.height?p():l(n,i)}function d(t){l(t.clientX,t.clientY)}a.addEventListener("touchstart",h);var p=function t(){a.removeEventListener("pointermove",d),a.removeEventListener("pointerleave",t),a.removeEventListener("pointercancel",t),a.removeEventListener("touchmove",u),a.removeEventListener("touchend",t),a.removeEventListener("touchcancel",t),n.unmount()},m=function(){c(),a.addEventListener("pointermove",d),a.addEventListener("pointerleave",p),a.addEventListener("pointercancel",p)};return a.addEventListener("pointerenter",m),function(){p(),a.removeEventListener(m),a.removeEventListener(h)}}),p(this,"unmountLine",function(){n.props.canvas.removeChild(n.line),n.line=void 0}),p(this,"unmountPoints",function(){var t=n.props.pointsContainer,e=n.points,i=Array.isArray(e),a=0;for(e=i?e:e[Symbol.iterator]();;){var o;if(i){if(a>=e.length)break;o=e[a++]}else{if((a=e.next()).done)break;o=a.value}var r=o;t.removeChild(r)}n.points=void 0}),p(this,"updateLine",function(t){n.isLineRendered()||n.renderLine();var e=n.props,i=e.canvasWidth,a=e.aspectRatio,o=e.fixSvgCoordinate,r=e.mapX;n.line.setAttributeNS(null,"x1",o(r(t))),n.line.setAttributeNS(null,"x2",o(r(t))),n.line.setAttributeNS(null,"y1",0),n.line.setAttributeNS(null,"y2",o(i/a))}),p(this,"updatePoints",function(t,e){for(var i=n.props,a=i.maxY,o=i.y,r=0,s=0;r<o.length;){if(o[r].isShown){var l=n.points[s],c=o[r].points[t]/a;l.style.left="".concat(100*e,"%"),l.style.bottom="".concat(100*c,"%"),s++}r++}}),this.props=e}var e,n,i;return e=t,(n=[{key:"componentDidMount",value:function(){this.unlisten=this.setUpListener()}},{key:"componentWillUnmount",value:function(){this.unlisten(),this.unmount()}},{key:"componentDidUpdate",value:function(t){this.props!==t&&(this.props=t)}},{key:"mount",value:function(){this.renderTooltip(),this.renderPoints(),this.isLineRendered()||this.renderLine()}},{key:"renderTooltip",value:function(){var t=this.props,e=t.y,n=t.container;this.tooltip=document.createElement("div"),this.tooltip.classList.add("chartogram__tooltip"),n.appendChild(this.tooltip),this.tooltipDate=document.createElement("h1"),this.tooltipDate.classList.add("chartogram__tooltip-header"),this.tooltip.appendChild(this.tooltipDate),this.tooltipValues=document.createElement("dl"),this.tooltipValues.classList.add("chartogram__tooltip-values"),this.tooltip.appendChild(this.tooltipValues);var i=e,a=Array.isArray(i),o=0;for(i=a?i:i[Symbol.iterator]();;){var r;if(a){if(o>=i.length)break;r=i[o++]}else{if((o=i.next()).done)break;r=o.value}var s=r,l=s.isShown,c=s.color;if(l){var h=document.createElement("dt");h.style.color=c,this.tooltipValues.appendChild(h);var u=document.createElement("dd");u.style.color=c,this.tooltipValues.appendChild(u)}}}},{key:"renderLine",value:function(){var t=this.props.canvas;this.line=document.createElementNS("http://www.w3.org/2000/svg","line"),this.line.setAttribute("class","chartogram__tooltip-line"),t.insertBefore(this.line,t.querySelector("polyline"))}},{key:"unmount",value:function(){if(this.tooltip){var t=this.props.container;this.tooltipForX=void 0,t.removeChild(this.tooltip),this.tooltip=void 0,this.unmountPoints(),this.isLineRendered()&&this.unmountLine()}}},{key:"isLineRendered",value:function(){var t=this.props.canvas;return this.line&&this.line.parentNode===t}},{key:"renderPoints",value:function(){this.points=[];var t=this.props,e=t.pointsContainer,n=t.y,i=Array.isArray(n),a=0;for(n=i?n:n[Symbol.iterator]();;){var o;if(i){if(a>=n.length)break;o=n[a++]}else{if((a=n.next()).done)break;o=a.value}var r=o;if(r.isShown){var s=document.createElement("div");s.classList.add("chartogram__tooltip-point"),s.style.color=r.color,this.points.push(s),e.appendChild(s)}}}}])&&d(e.prototype,n),i&&d(e,i),t}();function v(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")}()}function f(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),i.forEach(function(e){y(t,e,n[e])})}return t}function g(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function y(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var w=function(){function t(a,o){var r=this,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Title",l=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,t),y(this,"onResize",function(t){r.setState({aspectRatio:r.getCanvasAspectRatio(),canvasWidthPx:r.getCanvasWidthPx()},!1)}),y(this,"onResizeThrottled",i(this.onResize,33)),y(this,"onToggle",function(t){var e=r.state.y.find(function(e){return e.id===t});if(e.isShown&&1===r.state.y.filter(function(t){return t.isShown}).length)return;e.isShown=!e.isShown,r.setState({y:r.state.y});var n=r.calculateMinMaxY(r.state.y),i=n.minY,a=n.maxY,o=n.minYGlobal,s=n.maxYGlobal;return r.transitionState(i,a,o,s,r.state.y.map(function(t){return t.isShown?1:0})),!0}),y(this,"onChangeBounds",function(t,e){r.setState(r.createState(t,e),!1)}),y(this,"createPolylinePoints",function(t,e){return n=t.map(r.fixSvgCoordinate),i=e.map(r.fixSvgCoordinate),n.map(function(t,e){return"".concat(t,",").concat(i[e])});var n,i}),y(this,"fixSvgCoordinate",function(t){var e=r.props.precisionFactor;return Math.round(t*e)/e}),y(this,"mapX",function(t){var e=r.props.canvasWidth,n=r.state,i=n.minX;return(t-i)/(n.maxX-i)*e}),y(this,"mapY",function(t){var e=r.props.canvasWidth,n=r.state,i=n.minY;return(t-i)/(n.maxY-i)*e/n.aspectRatio}),y(this,"transitionStateTick",function(){var t=r.props.transitionEasing,e=r.state,n=e.transitionStartedAt,i=e.transitionDuration,a=e.graphOpacityFrom,o=e.graphOpacityTo,s=e.minYFrom,l=e.minYTo,c=e.maxYFrom,h=e.maxYTo,u=e.minYGlobalFrom,d=e.minYGlobalTo,p=e.maxYGlobalFrom,m=e.maxYGlobalTo,v=Date.now()-n,f=Math.min(v/i,1);f=S[t](f),r.setState({graphOpacity:o.map(function(t,e){return a[e]+(o[e]-a[e])*f}),minY:s+(l-s)*f,maxY:c+(h-c)*f,minYGlobal:u+(d-u)*f,maxYGlobal:p+(m-p)*f}),r.transition=f<1?requestAnimationFrame(r.transitionStateTick):void 0}),y(this,"createGridLine",function(t){var e=r.state,n=e.minX,i=e.maxX,a=(e.minY,e.maxY),o=document.createElement("line");return o.classList.add("chartogram__grid-line"),o.setAttribute("x1",r.fixSvgCoordinate(r.mapX(n))),o.setAttribute("x2",r.fixSvgCoordinate(r.mapX(i))),o.setAttribute("y1",r.fixSvgCoordinate(r.mapY(a-t))),o.setAttribute("y2",r.fixSvgCoordinate(r.mapY(a-t))),o}),y(this,"drawGauges",function(t,i,a,o,s){var l=r.props,c=l.gaugeTickMarksCount,h=l.months;e(r.xAxis),e(r.yAxis),n(r.xAxis,t,i,c,function(t){var e=new Date(t);return"".concat(h[e.getMonth()]," ").concat(e.getDate())}),n(r.yAxis,a,o,c),r.yAxis.style.height="".concat(100/s,"%")}),this.props=f({title:s,transitionDuration:300,transitionEasing:"easeOutQuad",gaugeTickMarksCount:6,timelineWindowSize:40,canvasWidth:512,precisionFactor:Math.pow(10,l.precision||3),months:b,weekdays:x},l),this.rootNode=a,this.data=f({},o,{minX:Math.min.apply(Math,v(o.x.points)),maxX:Math.max.apply(Math,v(o.x.points)),y:o.y.map(function(t){return f({},t,{min:Math.min.apply(Math,v(t.points)),max:Math.max.apply(Math,v(t.points))})})})}var a,o,r;return a=t,(o=[{key:"componentDidMount",value:function(){this.rootNode.classList.add("chartogram"),this.rootNode.innerHTML="\n\t\t\t".concat(_.replace("{title}",this.props.title),"\n\t\t\t").concat(l.INITIAL_MARKUP,"\n\t\t\t").concat(u.INITIAL_MARKUP,"\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.state=this.getInitialState(),this.timeline=new l(this.getTimelineProps()),this.timeline.componentDidMount(),this.togglers=new u(this.getTogglersProps()),this.togglers.componentDidMount(),this.tooltip=new m(this.getTooltipProps()),this.tooltip.componentDidMount(),window.addEventListener("resize",this.onResizeThrottled),this.render()}},{key:"componentWillUnmount",value:function(){this.timeline.componentWillUnmount(),this.rootNode.classList.remove("chartogram"),e(this.rootNode),window.removeEventListener("resize",this.onResizeThrottled)}},{key:"getCanvasAspectRatio",value:function(){var t=this.canvas.getBoundingClientRect();return t.width/t.height}},{key:"getCanvasWidthPx",value:function(){return this.canvas.getBoundingClientRect().width}},{key:"setState",value:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.state=f({},this.state,t),this.render(),e&&this.timeline.componentDidUpdate(this.getTimelineProps()),this.tooltip.componentDidUpdate(this.getTooltipProps())}},{key:"getTimelineProps",value:function(){return{rootNode:this.rootNode,data:this.data,canvasWidth:this.props.canvasWidth,fixSvgCoordinate:this.fixSvgCoordinate,createPolylinePoints:this.createPolylinePoints,fromRatio:this.state.fromRatio,toRatio:this.state.toRatio,minYGlobal:this.state.minYGlobal,maxYGlobal:this.state.maxYGlobal,y:this.state.y,graphOpacity:this.state.graphOpacity,onChangeBounds:this.onChangeBounds}}},{key:"getTogglersProps",value:function(){return{rootNode:this.rootNode,data:this.data,onToggle:this.onToggle}}},{key:"getTooltipProps",value:function(){return{canvas:this.canvas,canvasWidthPx:this.state.canvasWidthPx,container:this.tooltipContainer,pointsContainer:this.canvasWrapper,weekdays:this.props.weekdays,months:this.props.months,canvasWidth:this.props.canvasWidth,aspectRatio:this.state.aspectRatio,mapX:this.mapX,fixSvgCoordinate:this.fixSvgCoordinate,minX:this.state.minX,maxX:this.state.maxX,maxY:this.state.maxY,xPoints:this.state.xPoints,y:this.state.y}}},{key:"getInitialState",value:function(){var t,e=this.props.timelineWindowSize,n=this.data,i=n.minX,a=n.maxX;t=this.data.x.points.length>e?this.data.x.points.length-e:0;var o=(this.data.x.points[t]-i)/(a-i);return f({},this.createState(o,1),{aspectRatio:this.getCanvasAspectRatio(),canvasWidthPx:this.getCanvasWidthPx(),graphOpacity:this.data.y.map(function(t){return 1})})}},{key:"createState",value:function(t,e){var n,i,a=this,o=this.data.x,r=this.data.minX+t*(this.data.maxX-this.data.minX),s=this.data.minX+e*(this.data.maxX-this.data.minX);n=r===this.data.minX?0:o.points.findIndex(function(t){return t>r})-1,i=s===this.data.maxX?o.points.length-1:o.points.findIndex(function(t){return t>s});var l=o.points.slice(n,i+1),c=l.slice();l.length>=2&&(o.points[n]!==r&&(c[0]=r),o.points[i]!==s&&(c[c.length-1]=s));var h=this.data.y.map(function(t,e){var c=a.data.y[e].points.slice(n,i+1),h=c.slice();if(l.length>=2){if(o.points[n]!==r){var u=a.data.y[e].points[n],d=u+(a.data.y[e].points[n+1]-u)*((r-a.data.x.points[n])/(a.data.x.points[n+1]-a.data.x.points[n]));h[0]=d}if(o.points[i]!==s){var p=a.data.y[e].points[i],m=a.data.y[e].points[i-1],g=m+(p-m)*((s-a.data.x.points[i-1])/(a.data.x.points[i]-a.data.x.points[i-1]));h[h.length-1]=g}}return f({},a.data.y[e],a.state?a.state.y[e]:{isShown:!0},{points:c,graphPoints:h,min:0,max:Math.max.apply(Math,v(h))})});return f({minX:r,maxX:s,fromIndex:n,toIndex:i,fromRatio:t,toRatio:e,xPoints:l,xGraphPoints:c},this.calculateMinMaxY(h),{y:h})}},{key:"calculateMinMaxY",value:function(t){var e=1/0,n=-1/0,i=t,a=Array.isArray(i),o=0;for(i=a?i:i[Symbol.iterator]();;){var r;if(a){if(o>=i.length)break;r=i[o++]}else{if((o=i.next()).done)break;r=o.value}var s=r;s.isShown&&(e=Math.min(e,s.min),n=Math.max(n,s.max))}var l=1/0,c=-1/0,h=function(){if(d){if(p>=u.length)return"break";m=u[p++]}else{if((p=u.next()).done)return"break";m=p.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))},u=this.data.y,d=Array.isArray(u),p=0;for(u=d?u:u[Symbol.iterator]();;){var m;if("break"===h())break}return{minY:e,maxY:n,minYGlobal:l=0,maxYGlobal:c}}},{key:"render",value:function(){var t=this,n=this.props,i=n.canvasWidth,a=n.gaugeTickMarksCount,o=this.state,r=o.minX,s=o.maxX,l=o.minY,c=o.maxY,h=o.xGraphPoints,u=o.aspectRatio,d=o.graphOpacity;e(this.canvas),this.canvas.setAttribute("viewBox","0 0 ".concat(i," ").concat(this.fixSvgCoordinate(i/u)));var p=l,m=function(t,e){for(t=Math.floor(t);;){if(t<e)return e;if(t%e==0)return t;t--}}(c,10),v=(c-l)/(m-p),f=function(t,e,n){for(var i=new Array(n),a=0;a<n;)i[a]=t+a*(e-t)/(n-1),a++;return i}(p,m,a),g=Array.isArray(f),y=0;for(f=g?f:f[Symbol.iterator]();;){var w;if(g){if(y>=f.length)break;w=f[y++]}else{if((y=f.next()).done)break;w=y.value}var b=w;this.canvas.appendChild(this.createGridLine(b))}for(var x=0;x<this.state.y.length;){var _=this.state.y[x],S=_.color,A=_.graphPoints,C=_.isShown,L=d[x];if(C||L>0){var T=document.createElement("polyline");T.setAttribute("stroke",S),T.setAttribute("points",this.createPolylinePoints(h.map(this.mapX),A.map(function(e){return t.mapY(c-e)})).join(" ")),T.classList.add("chartogram__graph"),1!==L&&(T.style.opacity=L),this.canvas.appendChild(T)}x++}this.canvas.innerHTML+="",this.drawGauges(r,s,p,m,v)}},{key:"transitionState",value:function(t,e,n,i,a){var o=this.props.transitionDuration;this.transition&&cancelAnimationFrame(this.transition);var r=this.state.maxY-this.state.minY,s=Math.abs(e-this.state.maxY)/r,l=Math.abs(t-this.state.minY)/r,c=Math.max(l,s),h=o*Math.max(.1,2*Math.min(c,.5));this.setState({graphOpacityFrom:this.state.graphOpacity,graphOpacityTo:a,minYFrom:this.state.minY,maxYFrom:this.state.maxY,minYTo:t,maxYTo:e,minYGlobalFrom:this.state.minYGlobal,maxYGlobalFrom:this.state.maxYGlobal,minYGlobalTo:n,maxYGlobalTo:i,transitionStartedAt:Date.now(),transitionDuration:h}),this.transition=requestAnimationFrame(this.transitionStateTick)}}])&&g(a.prototype,o),r&&g(a,r),t}(),b=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],x=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],_='\n\t<header class="chartogram__header">\n\t\t<h1 class="chartogram__title">{title}</h1>\n\t</header>\n\t<div class="chartogram__plan-with-axes">\n\t\t<div class="chartogram__plan">\n\t\t\t<div class="chartogram__top-border"></div>\n\t\t\t<div class="chartogram__canvas-wrapper">\n\t\t\t\t<svg class="chartogram__canvas"></svg>\n\t\t\t\t<div class="chartogram__x"></div>\n\t\t\t\t<div class="chartogram__y-wrapper">\n\t\t\t\t\t<div class="chartogram__y"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n',S={linear:function(t){return t},easeInOutSin:function(t){return(1+Math.sin(Math.PI*t-Math.PI/2))/2},easeInOutQuad:function(t){return t<.5?2*t*t:(4-2*t)*t-1},easeInOutCubic:function(t){return t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1},easeOutCubic:function(t){return--t*t*t+1},easeOutQuad:function(t){return t*(2-t)}};return function(t,e,n,i){var a=new w(t,e,n,i);return a.componentDidMount(),function(){a.componentWillUnmount()}}}); | ||
!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,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")}()}function e(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function n(t,e,n,i,a){for(var o=0;o<i;){var r=document.createElement("div"),s=e+o*(n-e)/(i-1);a&&(s=a(s)),r.appendChild(document.createTextNode(s)),t.appendChild(r),o++}}function i(t,e){var n,i=0,a=function(){n=void 0,i=Date.now(),t()};return function(){var o=Date.now(),r=e-(o-i);r<=0?(n&&(clearTimeout(n),n=void 0),i=o,t()):n||(n=setTimeout(a,r))}}function a(t,e,n){function i(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",i),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",i),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 o(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=[],i=!0,a=!1,o=void 0;try{for(var r,s=t[Symbol.iterator]();!(i=(r=s.next()).done)&&(n.push(r.value),!e||n.length!==e);i=!0);}catch(t){a=!0,o=t}finally{try{i||null==s.return||s.return()}finally{if(a)throw o}}return n}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function r(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function s(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var l=function(){function n(t){var e=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,n),s(this,"onResize",function(t){e.setState({aspectRatio:e.getCanvasAspectRatio()})}),s(this,"onResizeThrottled",i(this.onResize,33)),s(this,"setState",function(t){e.state=function(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),i.forEach(function(e){s(t,e,n[e])})}return t}({},e.state,t),e.render()}),s(this,"mapX",function(t){var n=e.props,i=n.canvasWidth,a=n.data,o=a.minX;return(t-o)/(a.maxX-o)*i}),s(this,"mapY",function(t){var n=e.props,i=n.canvasWidth,a=n.minYGlobal;return(t-a)/(n.maxYGlobal-a)*i/e.state.aspectRatio}),s(this,"setUpTimelineWindowHandle",function(t){var n,i,o,r,s="left"===t?e.timelineWindowLeftHandle:e.timelineWindowRightHandle,l=parseFloat(getComputedStyle(e.timelineWindow).borderLeftWidth);return a(s,function(a){n=e.timeline.getBoundingClientRect();var s=e.timelineWindow.getBoundingClientRect();"left"===t?(i=n.left,o=s.left+s.width-2*l,r=a-s.left):(i=s.left+2*l,o=n.left+n.width,r=a-(s.left+s.width))},function(a){a-=r;var s=((a=Math.max(Math.min(a,o),i))-n.left)/n.width;"left"===t?e.updateBounds(s,e.props.toRatio):e.updateBounds(e.props.fromRatio,s)})}),s(this,"setUpTimelineWindow",function(){var t,n,i,o,r;return a(e.timelineWindowDrag,function(a){t=e.timeline.getBoundingClientRect(),n=e.timelineWindow.getBoundingClientRect(),r=a-n.left,i=t.left,o=t.left+(t.width-n.width)},function(a){a-=r;var s=((a=Math.max(Math.min(a,o),i))-t.left)/t.width;e.updateBounds(s,s+n.width/t.width)})}),s(this,"setTimelineWindowLeft",function(t){e.timelineOverlayLeft.style.right="".concat(100*(1-t),"%"),e.timelineWindow.style.left="".concat(100*t,"%")}),s(this,"setTimelineWindowRight",function(t){e.timelineOverlayRight.style.left="".concat(100*t,"%"),e.timelineWindow.style.right="".concat(100*(1-t),"%")}),this.props=t}var l,c,h;return l=n,(c=[{key:"componentDidUpdate",value:function(t){this.props!==t&&(this.props=t,this.state={aspectRatio:this.getCanvasAspectRatio()},this.onChangeBounds(this.props.fromRatio,this.props.toRatio),this.render())}},{key:"componentDidMount",value:function(){var t=this.props.rootNode;this.timeline=t.querySelector(".chartogram__timeline"),this.timelineOverlayLeft=t.querySelector(".chartogram__timeline-overlay-left"),this.timelineWindowLeftHandle=t.querySelector(".chartogram__timeline-window__left-handle"),this.timelineWindow=t.querySelector(".chartogram__timeline-window"),this.timelineWindowDrag=t.querySelector(".chartogram__timeline-window__drag"),this.timelineWindowRightHandle=t.querySelector(".chartogram__timeline-window__right-handle"),this.timelineOverlayRight=t.querySelector(".chartogram__timeline-overlay-right"),this.timelineCanvas=t.querySelector(".chartogram__timeline-canvas"),this.state={aspectRatio:this.getCanvasAspectRatio()},this.setUpTimelineWindowHandle("left"),this.setUpTimelineWindowHandle("right"),this.setUpTimelineWindow(),window.addEventListener("resize",this.onResizeThrottled),this.onChangeBounds(this.props.fromRatio,this.props.toRatio),this.render()}},{key:"componentWillUnmount",value:function(){window.removeEventListener("resize",this.onResizeThrottled)}},{key:"getCanvasAspectRatio",value:function(){var t=this.timelineCanvas.getBoundingClientRect();return t.width/t.height}},{key:"render",value:function(){var n=this,i=this.props,a=i.canvasWidth,r=i.y,s=i.data,l=i.maxYGlobal,c=i.fixSvgCoordinate,h=i.createPolylinePoints,u=i.graphOpacity,d=this.state.aspectRatio;e(this.timelineCanvas),this.timelineCanvas.setAttribute("viewBox","0 0 ".concat(a," ").concat(c(a/d)));for(var p=0,m=function(){var e=s.y[p],i=e.id,a=e.color,c=e.points,d=u[p];if(r.find(function(t){return t.id===i}).isShown||d>0){var m=o(function e(n,i,a){var o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:Math.max.apply(Math,t(i)),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(n.length),c=arguments.length>7&&void 0!==arguments[7]?arguments[7]:new Array(n.length),h=arguments.length>8&&void 0!==arguments[8]?arguments[8]:0;if(s+2>n.length-1){for(;s<i.length;)l[h]=n[s],c[h]=i[s],h++,s++;return l=l.slice(0,h),c=c.slice(0,h),l.length<=a?[l,c]:(n.length/l.length<1.1&&(r=Math.min(r+.025,1)),e(l,c,a,o,r))}var u=(i[s+2]+i[s])/2;return Math.abs(u-i[s+1])/o<r?(l[h]=n[s],l[h+1]=n[s+2],c[h]=i[s],c[h+1]=i[s+2],e(n,i,a,o,r,s+2,l,c,h+1)):(l[h]=n[s],l[h+1]=n[s+1],l[h+2]=n[s+2],c[h]=i[s],c[h+1]=i[s+1],c[h+2]=i[s+2],e(n,i,a,o,r,s+2,l,c,h+2))}(s.x.points,c,80),2),v=m[0],f=m[1],g=document.createElement("polyline");g.setAttribute("stroke",a),g.setAttribute("points",h(v.map(n.mapX),f.map(function(t){return n.mapY(l-t)})).join(" ")),g.classList.add("chartogram__graph"),1!==d&&(g.style.opacity=d),n.timelineCanvas.appendChild(g)}p++};p<s.y.length;)m();this.timelineCanvas.innerHTML+=""}},{key:"onChangeBounds",value:function(t,e){this.setTimelineWindowLeft(t),this.setTimelineWindowRight(e)}},{key:"updateBounds",value:function(t,e){this.props.onChangeBounds(t,e),this.props.fromRatio=t,this.props.toRatio=e,this.onChangeBounds(t,e)}}])&&r(l.prototype,c),h&&r(l,h),n}();function c(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function h(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}l.INITIAL_MARKUP='\n\t<div class="chartogram__timeline">\n\t\t<div class="chartogram__timeline-canvas-padding">\n\t\t\t<svg class="chartogram__timeline-canvas" preserveAspectRatio="none"></svg>\n\t\t</div>\n\t\t<div class="chartogram__timeline-overlay-left"></div>\n\t\t<div class="chartogram__timeline-overlay-right"></div>\n\t\t<div class="chartogram__timeline-window">\n\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__drag"></button>\n\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__left-handle"></button>\n\t\t\t<button type="button" class="chartogram__reset-button chartogram__timeline-window__right-handle"></button>\n\t\t</div>\n\t</div>\n';var u=function(){function t(e){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),h(this,"createGraphToggler",function(t){var e=t.id,i=t.name,a=t.color,o=document.createElement("button");o.setAttribute("type","button"),o.classList.add("chartogram__chart-toggler"),o.classList.add("chartogram__chart-toggler--on"),o.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",a),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 h=document.createElementNS(r,"path");return h.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"),h.setAttribute("fill","white"),h.setAttribute("class","chartogram__chart-toggler-check-mark"),s.appendChild(h),o.appendChild(s),o.appendChild(document.createTextNode(i)),o.addEventListener("click",function(){return n.onToggle(e,o)}),o}),h(this,"onToggle",function(t,e){(0,n.props.onToggle)(t)&&e.classList.toggle("chartogram__chart-toggler--on")}),this.props=e}var n,i,a;return n=t,(i=[{key:"componentDidMount",value:function(){var t=this.props,n=t.rootNode,i=t.data,a=n.querySelector(".chartogram__chart-togglers");e(a);var o=i.y,r=Array.isArray(o),s=0;for(o=r?o:o[Symbol.iterator]();;){var l;if(r){if(s>=o.length)break;l=o[s++]}else{if((s=o.next()).done)break;l=s.value}var c=l;a.appendChild(this.createGraphToggler(c))}}}])&&c(n.prototype,i),a&&c(n,a),t}();function d(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function p(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}u.INITIAL_MARKUP='\n\t<div class="chartogram__chart-togglers"></div>\n';var m=function(){function t(e){var n=this;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),p(this,"setUpListener",function(){!function(t,e,n,i){var a;function o(t,e){n(t,e,a)}function r(){a=t.getBoundingClientRect(),e()}function s(e){if(e.touches.length>1)return h();r(),t.addEventListener("touchend",h),t.addEventListener("touchmove",l),t.addEventListener("touchend",h),t.addEventListener("touchcancel",h),l(e)}function l(t){var e=t.changedTouches[0].clientX,n=t.changedTouches[0].clientY;e<a.left||e>a.left+a.width||n<a.top||n>a.top+a.height?h():o(e,n)}function c(t){o(t.clientX,t.clientY)}function h(){t.removeEventListener("pointermove",c),t.removeEventListener("pointerleave",h),t.removeEventListener("pointercancel",h),t.removeEventListener("touchmove",l),t.removeEventListener("touchend",h),t.removeEventListener("touchcancel",h),i()}function u(){r(),t.addEventListener("pointermove",c),t.addEventListener("pointerleave",h),t.addEventListener("pointercancel",h)}t.addEventListener("touchstart",s),t.addEventListener("pointerenter",u)}(n.props.canvas,function(){},n.onTrack,function(){return n.unmount()})}),p(this,"onTrack",function(t,e,i){var a,o=n.props,r=o.minX,s=o.maxX,l=o.xPoints,c=r+(t-i.left)/i.width*(s-r),h=l.findIndex(function(t){return t>=c}),u=h-1;if((h<0||h>=l.length)&&(h=-1),(u<0||u>=l.length)&&(u=-1),h<0){if(u<0)return n.unmount();a=u}else if(u<0)a=h;else{var d=l[u],p=l[h];a=c-d>p-c?h:u}var m=l[a];m!==n.tooltipForX&&(n.tooltipForX=m,n.tooltip||n.mount(),n.updateTooltip(m,a,i.width))}),p(this,"unmountLine",function(){n.props.canvas.removeChild(n.line),n.line=void 0}),p(this,"mountPoints",function(){var t=n.props.pointsContainer;n.points=n.renderPoints();var e=n.points,i=Array.isArray(e),a=0;for(e=i?e:e[Symbol.iterator]();;){var o;if(i){if(a>=e.length)break;o=e[a++]}else{if((a=e.next()).done)break;o=a.value}var r=o;t.appendChild(r)}}),p(this,"unmountPoints",function(){var t=n.props.pointsContainer,e=n.points,i=Array.isArray(e),a=0;for(e=i?e:e[Symbol.iterator]();;){var o;if(i){if(a>=e.length)break;o=e[a++]}else{if((a=e.next()).done)break;o=a.value}var r=o;t.removeChild(r)}n.points=void 0}),p(this,"updateLinePosition",function(t){n.isLineRendered()||n.mountLine();var e=n.props,i=e.canvasWidth,a=e.aspectRatio,o=e.fixSvgCoordinate,r=e.mapX;n.line.setAttributeNS(null,"x1",o(r(t))),n.line.setAttributeNS(null,"x2",o(r(t))),n.line.setAttributeNS(null,"y1",0),n.line.setAttributeNS(null,"y2",o(i/a))}),p(this,"updatePointPositions",function(t,e){for(var i=n.props,a=i.maxY,o=i.y,r=0,s=0;r<o.length;){if(o[r].isShown){var l=n.points[s],c=o[r].points[t]/a;l.style.left="".concat(100*e,"%"),l.style.bottom="".concat(100*c,"%"),s++}r++}}),this.props=e}var e,n,i;return e=t,(n=[{key:"componentDidMount",value:function(){this.unlisten=this.setUpListener()}},{key:"componentWillUnmount",value:function(){this.unlisten(),this.unmount()}},{key:"componentDidUpdate",value:function(t){this.props!==t&&(this.props=t)}},{key:"mount",value:function(){var t=this.props.container;this.tooltip=this.renderTooltip(),t.appendChild(this.tooltip),this.mountPoints(),this.isLineRendered()||this.mountLine()}},{key:"unmount",value:function(){if(this.tooltip){var t=this.props.container;this.tooltipForX=void 0,t.removeChild(this.tooltip),this.tooltip=void 0,this.unmountPoints(),this.isLineRendered()&&this.unmountLine()}}},{key:"mountLine",value:function(){var t=this.props.canvas;this.line=this.renderLine(),t.insertBefore(this.line,t.querySelector("polyline"))}},{key:"renderTooltip",value:function(){var t=this.props.y,e=document.createElement("div");e.classList.add("chartogram__tooltip");var n=document.createElement("h1");n.classList.add("chartogram__tooltip-header"),e.appendChild(n);var i=document.createElement("dl");i.classList.add("chartogram__tooltip-values"),e.appendChild(i);var a=t,o=Array.isArray(a),r=0;for(a=o?a:a[Symbol.iterator]();;){var s;if(o){if(r>=a.length)break;s=a[r++]}else{if((r=a.next()).done)break;s=r.value}var l=s,c=l.isShown,h=l.color;if(c){var u=document.createElement("dt");u.style.color=h,i.appendChild(u);var d=document.createElement("dd");d.style.color=h,i.appendChild(d)}}return e}},{key:"renderLine",value:function(){var t=document.createElementNS("http://www.w3.org/2000/svg","line");return t.setAttribute("class","chartogram__tooltip-line"),t}},{key:"isLineRendered",value:function(){var t=this.props.canvas;return this.line&&this.line.parentNode===t}},{key:"renderPoints",value:function(){var t=[],e=this.props,n=e.pointsContainer,i=e.y,a=Array.isArray(i),o=0;for(i=a?i:i[Symbol.iterator]();;){var r;if(a){if(o>=i.length)break;r=i[o++]}else{if((o=i.next()).done)break;r=o.value}var s=r;if(s.isShown){var l=document.createElement("div");l.classList.add("chartogram__tooltip-point"),l.style.color=s.color,t.push(l),n.appendChild(l)}}return t}},{key:"updateTooltip",value:function(t,e,n){var i=this.props,a=i.minX,o=(t-a)/(i.maxX-a);this.updateTooltipDate(new Date(t)),this.updateTooltipValues(e),this.updateTooltipPosition(o,n),this.updatePointPositions(e,o),this.updateLinePosition(t)}},{key:"updateTooltipPosition",value:function(t,e){var n=this.props,i=n.tooltipShift,a=n.maxOverflow,o=t*e;o-=void 0===i?40:i;var r=this.tooltip.getBoundingClientRect().width,s=void 0===a?5:a;o<-1*s?o=-1*s:o+r>e+s&&(o=e+s-r),this.tooltip.style.left=o+"px"}},{key:"updateTooltipDate",value:function(t){var e=this.props,n=e.weekdays,i=e.months;this.tooltip.childNodes[0].textContent="".concat(n[t.getDay()],", ").concat(i[t.getMonth()]," ").concat(t.getDate())}},{key:"updateTooltipValues",value:function(t){var e=this.props.y,n=this.tooltip.childNodes[1],i=0,a=e,o=Array.isArray(a),r=0;for(a=o?a:a[Symbol.iterator]();;){var s;if(o){if(r>=a.length)break;s=a[r++]}else{if((r=a.next()).done)break;s=r.value}var l=s,c=l.isShown,h=l.points,u=l.name;c&&(n.childNodes[2*i].textContent=h[t],n.childNodes[2*i+1].textContent=u,i++)}}}])&&d(e.prototype,n),i&&d(e,i),t}();function v(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")}()}function f(t){for(var e=1;e<arguments.length;e++){var n=null!=arguments[e]?arguments[e]:{},i=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(n).filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable}))),i.forEach(function(e){y(t,e,n[e])})}return t}function g(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function y(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var b=function(){function t(a,o){var r=this,s=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"Title",l=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,t),y(this,"onResize",function(t){r.setState({aspectRatio:r.getCanvasAspectRatio()},!1)}),y(this,"onResizeThrottled",i(this.onResize,33)),y(this,"onToggle",function(t){var e=r.state.y.find(function(e){return e.id===t});if(e.isShown&&1===r.state.y.filter(function(t){return t.isShown}).length)return;e.isShown=!e.isShown,r.setState({y:r.state.y});var n=r.calculateMinMaxY(r.state.y),i=n.minY,a=n.maxY,o=n.minYGlobal,s=n.maxYGlobal;return r.transitionState(i,a,o,s,r.state.y.map(function(t){return t.isShown?1:0})),!0}),y(this,"onChangeBounds",function(t,e){var n=r.createState(t,e),i=n.minY,a=n.maxY;delete n.minY,delete n.maxY,r.setState(n,!1),r.transitionState(i,a)}),y(this,"createPolylinePoints",function(t,e){return n=t.map(r.fixSvgCoordinate),i=e.map(r.fixSvgCoordinate),n.map(function(t,e){return"".concat(t,",").concat(i[e])});var n,i}),y(this,"fixSvgCoordinate",function(t){var e=r.props.precisionFactor;return Math.round(t*e)/e}),y(this,"mapX",function(t){var e=r.props.canvasWidth,n=r.state,i=n.minX;return(t-i)/(n.maxX-i)*e}),y(this,"mapY",function(t){var e=r.props.canvasWidth,n=r.state,i=n.minY;return(t-i)/(n.maxY-i)*e/n.aspectRatio}),y(this,"transitionStateTick",function(){var t=r.props.transitionEasing,e=r.state,n=e.transitionStartedAt,i=e.transitionDuration,a=e.graphOpacityFrom,o=e.graphOpacityTo,s=e.minYFrom,l=e.minYTo,c=e.maxYFrom,h=e.maxYTo,u=e.minYGlobalFrom,d=e.minYGlobalTo,p=e.maxYGlobalFrom,m=e.maxYGlobalTo,v=Date.now()-n,f=Math.min(v/i,1);f=S[t](f);var g={};void 0!==l&&(g.minY=s+(l-s)*f,g.maxY=c+(h-c)*f,1===f&&(g.minYFrom=void 0,g.minYTo=void 0,g.maxYFrom=void 0,g.maxYTo=void 0)),void 0!==d&&(g.minYGlobal=u+(d-u)*f,g.maxYGlobal=p+(m-p)*f,1===f&&(g.minYGlobalFrom=void 0,g.minYGlobalTo=void 0,g.maxYGlobalFrom=void 0,g.maxYGlobalTo=void 0)),void 0!==o&&(g.graphOpacity=o.map(function(t,e){return a[e]+(o[e]-a[e])*f}),1===f&&(g.graphOpacityFrom=void 0,g.graphOpacityTo=void 0)),r.setState(g),r.transition=f<1?requestAnimationFrame(r.transitionStateTick):void 0}),y(this,"createGridLine",function(t){var e=r.state,n=e.minX,i=e.maxX,a=(e.minY,e.maxY),o=document.createElement("line");return o.classList.add("chartogram__grid-line"),o.setAttribute("x1",r.fixSvgCoordinate(r.mapX(n))),o.setAttribute("x2",r.fixSvgCoordinate(r.mapX(i))),o.setAttribute("y1",r.fixSvgCoordinate(r.mapY(a-t))),o.setAttribute("y2",r.fixSvgCoordinate(r.mapY(a-t))),o}),y(this,"drawGauges",function(t,i,a,o,s){var l=r.props,c=l.gaugeTickMarksCount,h=l.months;e(r.xAxis),e(r.yAxis),n(r.xAxis,t,i,c,function(t){var e=new Date(t);return"".concat(h[e.getMonth()]," ").concat(e.getDate())}),n(r.yAxis,a,o,c),r.yAxis.style.height="".concat(100/s,"%")}),this.props=f({title:s,transitionDuration:250,transitionEasing:"easeOutQuad",gaugeTickMarksCount:6,timelineWindowSize:40,canvasWidth:512,precisionFactor:Math.pow(10,l.precision||3),months:w,weekdays:x},l),this.rootNode=a,this.data=f({},o,{minX:Math.min.apply(Math,v(o.x.points)),maxX:Math.max.apply(Math,v(o.x.points)),y:o.y.map(function(t){return f({},t,{min:Math.min.apply(Math,v(t.points)),max:Math.max.apply(Math,v(t.points))})})})}var a,o,r;return a=t,(o=[{key:"componentDidMount",value:function(){this.rootNode.classList.add("chartogram"),this.rootNode.innerHTML="\n\t\t\t".concat(_.replace("{title}",this.props.title),"\n\t\t\t").concat(l.INITIAL_MARKUP,"\n\t\t\t").concat(u.INITIAL_MARKUP,"\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.state=this.getInitialState(),this.timeline=new l(this.getTimelineProps()),this.timeline.componentDidMount(),this.togglers=new u(this.getTogglersProps()),this.togglers.componentDidMount(),this.tooltip=new m(this.getTooltipProps()),this.tooltip.componentDidMount(),window.addEventListener("resize",this.onResizeThrottled),this.render()}},{key:"componentWillUnmount",value:function(){this.timeline.componentWillUnmount(),this.rootNode.classList.remove("chartogram"),e(this.rootNode),window.removeEventListener("resize",this.onResizeThrottled),this.transition&&cancelAnimationFrame(this.transition)}},{key:"getCanvasAspectRatio",value:function(){var t=this.canvas.getBoundingClientRect();return t.width/t.height}},{key:"setState",value:function(t){var e=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.state=f({},this.state,t),this.render(),e&&this.timeline.componentDidUpdate(this.getTimelineProps()),this.tooltip.componentDidUpdate(this.getTooltipProps())}},{key:"getTimelineProps",value:function(){return{rootNode:this.rootNode,data:this.data,canvasWidth:this.props.canvasWidth,fixSvgCoordinate:this.fixSvgCoordinate,createPolylinePoints:this.createPolylinePoints,fromRatio:this.state.fromRatio,toRatio:this.state.toRatio,minYGlobal:this.state.minYGlobal,maxYGlobal:this.state.maxYGlobal,y:this.state.y,graphOpacity:this.state.graphOpacity,onChangeBounds:this.onChangeBounds}}},{key:"getTogglersProps",value:function(){return{rootNode:this.rootNode,data:this.data,onToggle:this.onToggle}}},{key:"getTooltipProps",value:function(){return{canvas:this.canvas,container:this.tooltipContainer,pointsContainer:this.canvasWrapper,weekdays:this.props.weekdays,months:this.props.months,canvasWidth:this.props.canvasWidth,aspectRatio:this.state.aspectRatio,mapX:this.mapX,fixSvgCoordinate:this.fixSvgCoordinate,minX:this.state.minX,maxX:this.state.maxX,maxY:this.state.maxY,xPoints:this.state.xPoints,y:this.state.y}}},{key:"getInitialState",value:function(){var t,e=this.props.timelineWindowSize,n=this.data,i=n.minX,a=n.maxX;t=this.data.x.points.length>e?this.data.x.points.length-e:0;var o=(this.data.x.points[t]-i)/(a-i);return f({},this.createState(o,1),{aspectRatio:this.getCanvasAspectRatio(),graphOpacity:this.data.y.map(function(t){return 1})})}},{key:"createState",value:function(t,e){var n,i,a=this,o=this.data.x,r=this.data.minX+t*(this.data.maxX-this.data.minX),s=this.data.minX+e*(this.data.maxX-this.data.minX);n=r===this.data.minX?0:o.points.findIndex(function(t){return t>r})-1,i=s===this.data.maxX?o.points.length-1:o.points.findIndex(function(t){return t>s});var l=o.points.slice(n,i+1),c=l.slice();l.length>=2&&(o.points[n]!==r&&(c[0]=r),o.points[i]!==s&&(c[c.length-1]=s));var h=this.data.y.map(function(t,e){var c=a.data.y[e].points.slice(n,i+1),h=c.slice();if(l.length>=2){if(o.points[n]!==r){var u=a.data.y[e].points[n],d=u+(a.data.y[e].points[n+1]-u)*((r-a.data.x.points[n])/(a.data.x.points[n+1]-a.data.x.points[n]));h[0]=d}if(o.points[i]!==s){var p=a.data.y[e].points[i],m=a.data.y[e].points[i-1],g=m+(p-m)*((s-a.data.x.points[i-1])/(a.data.x.points[i]-a.data.x.points[i-1]));h[h.length-1]=g}}return f({},a.data.y[e],a.state?a.state.y[e]:{isShown:!0},{points:c,graphPoints:h,min:0,max:Math.max.apply(Math,v(h))})});return f({minX:r,maxX:s,fromIndex:n,toIndex:i,fromRatio:t,toRatio:e,xPoints:l,xGraphPoints:c},this.calculateMinMaxY(h),{y:h})}},{key:"calculateMinMaxY",value:function(t){var e=1/0,n=-1/0,i=t,a=Array.isArray(i),o=0;for(i=a?i:i[Symbol.iterator]();;){var r;if(a){if(o>=i.length)break;r=i[o++]}else{if((o=i.next()).done)break;r=o.value}var s=r;s.isShown&&(e=Math.min(e,s.min),n=Math.max(n,s.max))}var l=1/0,c=-1/0,h=function(){if(d){if(p>=u.length)return"break";m=u[p++]}else{if((p=u.next()).done)return"break";m=p.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))},u=this.data.y,d=Array.isArray(u),p=0;for(u=d?u:u[Symbol.iterator]();;){var m;if("break"===h())break}return{minY:e,maxY:n,minYGlobal:l=0,maxYGlobal:c}}},{key:"render",value:function(){var t=this,n=this.props,i=n.canvasWidth,a=n.gaugeTickMarksCount,o=this.state,r=o.minX,s=o.maxX,l=o.minY,c=o.maxY,h=o.xGraphPoints,u=o.aspectRatio,d=o.graphOpacity;e(this.canvas),this.canvas.setAttribute("viewBox","0 0 ".concat(i," ").concat(this.fixSvgCoordinate(i/u)));var p=l,m=function(t,e){for(t=Math.floor(t);;){if(t<e)return e;if(t%e==0)return t;t--}}(c,10),v=(c-l)/(m-p),f=function(t,e,n){for(var i=new Array(n),a=0;a<n;)i[a]=t+a*(e-t)/(n-1),a++;return i}(p,m,a),g=Array.isArray(f),y=0;for(f=g?f:f[Symbol.iterator]();;){var b;if(g){if(y>=f.length)break;b=f[y++]}else{if((y=f.next()).done)break;b=y.value}var w=b;this.canvas.appendChild(this.createGridLine(w))}for(var x=0;x<this.state.y.length;){var _=this.state.y[x],S=_.color,A=_.graphPoints,T=_.isShown,C=d[x];if(T||C>0){var k=document.createElement("polyline");k.setAttribute("stroke",S),k.setAttribute("points",this.createPolylinePoints(h.map(this.mapX),A.map(function(e){return t.mapY(c-e)})).join(" ")),k.classList.add("chartogram__graph"),1!==C&&(k.style.opacity=C),this.canvas.appendChild(k)}x++}this.canvas.innerHTML+="",this.drawGauges(r,s,p,m,v)}},{key:"transitionState",value:function(t,e,n,i,a){var o=this.props.transitionDuration;this.transition&&cancelAnimationFrame(this.transition);var r=o;if(void 0!==t){var s=this.state.maxY-this.state.minY,l=Math.abs(e-this.state.maxY)/s,c=Math.abs(t-this.state.minY)/s,h=Math.max(c,l);r=o*Math.max(.2,2*Math.min(h,.5))}var u={transitionStartedAt:Date.now(),transitionDuration:r};void 0!==t&&(u.minYFrom=this.state.minY,u.maxYFrom=this.state.maxY,u.minYTo=t,u.maxYTo=e),void 0!==a&&(u.graphOpacityFrom=this.state.graphOpacity,u.graphOpacityTo=a),void 0!==n&&(u.minYGlobalFrom=this.state.minYGlobal,u.maxYGlobalFrom=this.state.maxYGlobal,u.minYGlobalTo=n,u.maxYGlobalTo=i),this.setState(u),this.transition=requestAnimationFrame(this.transitionStateTick)}}])&&g(a.prototype,o),r&&g(a,r),t}(),w=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],x=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],_='\n\t<header class="chartogram__header">\n\t\t<h1 class="chartogram__title">{title}</h1>\n\t</header>\n\t<div class="chartogram__plan-with-axes">\n\t\t<div class="chartogram__plan">\n\t\t\t<div class="chartogram__top-border"></div>\n\t\t\t<div class="chartogram__canvas-wrapper">\n\t\t\t\t<svg class="chartogram__canvas"></svg>\n\t\t\t\t<div class="chartogram__x"></div>\n\t\t\t\t<div class="chartogram__y-wrapper">\n\t\t\t\t\t<div class="chartogram__y"></div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n',S={linear:function(t){return t},easeInOutSin:function(t){return(1+Math.sin(Math.PI*t-Math.PI/2))/2},easeInOutQuad:function(t){return t<.5?2*t*t:(4-2*t)*t-1},easeInOutCubic:function(t){return t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1},easeOutCubic:function(t){return--t*t*t+1},easeOutQuad:function(t){return t*(2-t)}};return function(t,e,n,i){var a=new b(t,e,n,i);return a.componentDidMount(),function(){a.componentWillUnmount()}}}); | ||
//# sourceMappingURL=chartogram.js.map |
@@ -49,4 +49,3 @@ "use strict"; | ||
_this.setState({ | ||
aspectRatio: _this.getCanvasAspectRatio(), | ||
canvasWidthPx: _this.getCanvasWidthPx() | ||
aspectRatio: _this.getCanvasAspectRatio() | ||
}, false); | ||
@@ -93,3 +92,12 @@ }); | ||
_defineProperty(this, "onChangeBounds", function (from, to) { | ||
_this.setState(_this.createState(from, to), false); | ||
var state = _this.createState(from, to); | ||
var minY = state.minY; | ||
var maxY = state.maxY; | ||
delete state.minY; | ||
delete state.maxY; | ||
_this.setState(state, false); | ||
_this.transitionState(minY, maxY); | ||
}); | ||
@@ -142,13 +150,41 @@ | ||
ratio = EASING[transitionEasing](ratio); | ||
var state = {}; | ||
_this.setState({ | ||
graphOpacity: graphOpacityTo.map(function (_, i) { | ||
if (minYTo !== undefined) { | ||
state.minY = minYFrom + (minYTo - minYFrom) * ratio; | ||
state.maxY = maxYFrom + (maxYTo - maxYFrom) * ratio; | ||
if (ratio === 1) { | ||
state.minYFrom = undefined; | ||
state.minYTo = undefined; | ||
state.maxYFrom = undefined; | ||
state.maxYTo = undefined; | ||
} | ||
} | ||
if (minYGlobalTo !== undefined) { | ||
state.minYGlobal = minYGlobalFrom + (minYGlobalTo - minYGlobalFrom) * ratio; | ||
state.maxYGlobal = maxYGlobalFrom + (maxYGlobalTo - maxYGlobalFrom) * ratio; | ||
if (ratio === 1) { | ||
state.minYGlobalFrom = undefined; | ||
state.minYGlobalTo = undefined; | ||
state.maxYGlobalFrom = undefined; | ||
state.maxYGlobalTo = undefined; | ||
} | ||
} | ||
if (graphOpacityTo !== undefined) { | ||
state.graphOpacity = graphOpacityTo.map(function (_, i) { | ||
return graphOpacityFrom[i] + (graphOpacityTo[i] - graphOpacityFrom[i]) * ratio; | ||
}), | ||
minY: minYFrom + (minYTo - minYFrom) * ratio, | ||
maxY: maxYFrom + (maxYTo - maxYFrom) * ratio, | ||
minYGlobal: minYGlobalFrom + (minYGlobalTo - minYGlobalFrom) * ratio, | ||
maxYGlobal: maxYGlobalFrom + (maxYGlobalTo - maxYGlobalFrom) * ratio | ||
}); | ||
}); | ||
if (ratio === 1) { | ||
state.graphOpacityFrom = undefined; | ||
state.graphOpacityTo = undefined; | ||
} | ||
} | ||
_this.setState(state); | ||
if (ratio < 1) { | ||
@@ -192,3 +228,3 @@ _this.transition = requestAnimationFrame(_this.transitionStateTick); | ||
title: title, | ||
transitionDuration: 300, | ||
transitionDuration: 250, | ||
transitionEasing: 'easeOutQuad', | ||
@@ -245,2 +281,6 @@ gaugeTickMarksCount: 6, | ||
window.removeEventListener('resize', this.onResizeThrottled); | ||
if (this.transition) { | ||
cancelAnimationFrame(this.transition); | ||
} | ||
} | ||
@@ -254,8 +294,2 @@ }, { | ||
}, { | ||
key: "getCanvasWidthPx", | ||
value: function getCanvasWidthPx() { | ||
var canvasDimensions = this.canvas.getBoundingClientRect(); | ||
return canvasDimensions.width; | ||
} | ||
}, { | ||
key: "setState", | ||
@@ -305,3 +339,2 @@ value: function setState(newState) { | ||
canvas: this.canvas, | ||
canvasWidthPx: this.state.canvasWidthPx, | ||
container: this.tooltipContainer, | ||
@@ -342,3 +375,2 @@ pointsContainer: this.canvasWrapper, | ||
aspectRatio: this.getCanvasAspectRatio(), | ||
canvasWidthPx: this.getCanvasWidthPx(), | ||
graphOpacity: this.data.y.map(function (_) { | ||
@@ -591,22 +623,38 @@ return 1; | ||
var heightBefore = this.state.maxY - this.state.minY; | ||
var deltaMaxY = Math.abs(maxY - this.state.maxY) / heightBefore; | ||
var deltaMinY = Math.abs(minY - this.state.minY) / heightBefore; | ||
var deltaY = Math.max(deltaMinY, deltaMaxY); | ||
var transitionDuration = maxTransitionDuration * Math.max(0.1, Math.min(deltaY, 0.5) * 2); | ||
this.setState({ | ||
graphOpacityFrom: this.state.graphOpacity, | ||
graphOpacityTo: graphOpacity, | ||
minYFrom: this.state.minY, | ||
maxYFrom: this.state.maxY, | ||
minYTo: minY, | ||
maxYTo: maxY, | ||
minYGlobalFrom: this.state.minYGlobal, | ||
maxYGlobalFrom: this.state.maxYGlobal, | ||
minYGlobalTo: minYGlobal, | ||
maxYGlobalTo: maxYGlobal, | ||
var transitionDuration = maxTransitionDuration; | ||
if (minY !== undefined) { | ||
var heightBefore = this.state.maxY - this.state.minY; | ||
var deltaMaxY = Math.abs(maxY - this.state.maxY) / heightBefore; | ||
var deltaMinY = Math.abs(minY - this.state.minY) / heightBefore; | ||
var deltaY = Math.max(deltaMinY, deltaMaxY); | ||
transitionDuration = maxTransitionDuration * Math.max(0.2, Math.min(deltaY, 0.5) * 2); | ||
} | ||
var state = { | ||
transitionStartedAt: Date.now(), | ||
transitionDuration: transitionDuration | ||
}); // Place in a `setState()` callback in case of React. | ||
}; | ||
if (minY !== undefined) { | ||
state.minYFrom = this.state.minY; | ||
state.maxYFrom = this.state.maxY; | ||
state.minYTo = minY; | ||
state.maxYTo = maxY; | ||
} | ||
if (graphOpacity !== undefined) { | ||
state.graphOpacityFrom = this.state.graphOpacity; | ||
state.graphOpacityTo = graphOpacity; | ||
} | ||
if (minYGlobal !== undefined) { | ||
state.minYGlobalFrom = this.state.minYGlobal; | ||
state.maxYGlobalFrom = this.state.maxYGlobal; | ||
state.minYGlobalTo = minYGlobal; | ||
state.maxYGlobalTo = maxYGlobal; | ||
} | ||
this.setState(state); // Place in a `setState()` callback in case of React. | ||
this.transition = requestAnimationFrame(this.transitionStateTick); | ||
@@ -613,0 +661,0 @@ } |
@@ -8,2 +8,4 @@ "use strict"; | ||
var _utility = require("./utility"); | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -26,185 +28,88 @@ | ||
_defineProperty(this, "setUpListener", function () { | ||
var canvas = _this.props.canvas; | ||
(0, _utility.setUpTouchMove)(canvas, function () {}, _this.onTrack, function () { | ||
return _this.unmount(); | ||
}); | ||
}); | ||
_defineProperty(this, "onTrack", function (screenX, screenY, canvasDimensions) { | ||
var _this$props = _this.props, | ||
canvas = _this$props.canvas, | ||
canvasWidthPx = _this$props.canvasWidthPx, | ||
weekdays = _this$props.weekdays, | ||
months = _this$props.months; | ||
var canvasDimensions; | ||
var isIndexInBounds; | ||
minX = _this$props.minX, | ||
maxX = _this$props.maxX, | ||
xPoints = _this$props.xPoints; | ||
var xScreenRatio = (screenX - canvasDimensions.left) / canvasDimensions.width; | ||
var xPoint = minX + xScreenRatio * (maxX - minX); | ||
var xHigherIndex = xPoints.findIndex(function (_) { | ||
return _ >= xPoint; | ||
}); | ||
var xLowerIndex = xHigherIndex - 1; | ||
var onTrack = function onTrack(screenX) { | ||
var _this$props2 = _this.props, | ||
minX = _this$props2.minX, | ||
maxX = _this$props2.maxX, | ||
xPoints = _this$props2.xPoints, | ||
y = _this$props2.y; | ||
var xScreenRatio = (screenX - canvasDimensions.left) / canvasDimensions.width; | ||
var xPoint = minX + xScreenRatio * (maxX - minX); | ||
var xHigherIndex = xPoints.findIndex(function (_) { | ||
return _ >= xPoint; | ||
}); | ||
var xLowerIndex = xHigherIndex - 1; | ||
if (xHigherIndex < 0 || xHigherIndex >= xPoints.length) { | ||
xHigherIndex = -1; | ||
} | ||
if (!isIndexInBounds(xHigherIndex)) { | ||
xHigherIndex = -1; | ||
} | ||
if (xLowerIndex < 0 || xLowerIndex >= xPoints.length) { | ||
xLowerIndex = -1; | ||
} | ||
if (!isIndexInBounds(xLowerIndex)) { | ||
xLowerIndex = -1; | ||
} | ||
var xIndex; | ||
var xIndex; | ||
if (xHigherIndex < 0) { | ||
if (xLowerIndex < 0) { | ||
return _this.unmount(); | ||
} else { | ||
xIndex = xLowerIndex; | ||
} | ||
if (xHigherIndex < 0) { | ||
if (xLowerIndex < 0) { | ||
return _this.unmount(); | ||
} else { | ||
if (xLowerIndex < 0) { | ||
xIndex = xHigherIndex; | ||
} else { | ||
var xLower = xPoints[xLowerIndex]; | ||
var xHigher = xPoints[xHigherIndex]; | ||
var deltaLower = xPoint - xLower; | ||
var deltaHigher = xHigher - xPoint; | ||
xIndex = deltaLower > deltaHigher ? xHigherIndex : xLowerIndex; | ||
} | ||
xIndex = xLowerIndex; | ||
} | ||
var x = xPoints[xIndex]; | ||
if (x !== _this.tooltipForX) { | ||
_this.tooltipForX = x; | ||
if (!_this.tooltip) { | ||
_this.mount(); | ||
} | ||
var date = new Date(x); | ||
_this.tooltipDate.textContent = "".concat(weekdays[date.getDay()], ", ").concat(months[date.getMonth()], " ").concat(date.getDate()); | ||
var i = 0; | ||
for (var _iterator = y, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref; | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref = _i.value; | ||
} | ||
var _ref2 = _ref, | ||
isShown = _ref2.isShown, | ||
points = _ref2.points, | ||
name = _ref2.name; | ||
if (isShown) { | ||
_this.tooltipValues.childNodes[2 * i].textContent = points[xIndex]; | ||
_this.tooltipValues.childNodes[2 * i + 1].textContent = name; | ||
i++; | ||
} | ||
} | ||
var xRatio = (x - minX) / (maxX - minX); | ||
var left = xRatio * canvasWidthPx; | ||
left -= 40; | ||
var tooltipWidth = _this.tooltip.getBoundingClientRect().width; | ||
var overflow = 5; | ||
if (left < -1 * overflow) { | ||
left = -1 * overflow; | ||
} else if (left + tooltipWidth > canvasWidthPx + overflow) { | ||
left = canvasWidthPx + overflow - tooltipWidth; | ||
} | ||
_this.tooltip.style.left = left + 'px'; | ||
_this.updatePoints(xIndex, xRatio); | ||
_this.updateLine(x); | ||
} else { | ||
if (xLowerIndex < 0) { | ||
xIndex = xHigherIndex; | ||
} else { | ||
var xLower = xPoints[xLowerIndex]; | ||
var xHigher = xPoints[xHigherIndex]; | ||
var deltaLower = xPoint - xLower; | ||
var deltaHigher = xHigher - xPoint; | ||
xIndex = deltaLower > deltaHigher ? xHigherIndex : xLowerIndex; | ||
} | ||
}; | ||
} | ||
var onTrackStart = function onTrackStart() { | ||
canvasDimensions = canvas.getBoundingClientRect(); | ||
var x = xPoints[xIndex]; | ||
isIndexInBounds = function isIndexInBounds(index) { | ||
var xPoints = _this.props.xPoints; | ||
return index >= 0 && index < xPoints.length; | ||
}; | ||
}; | ||
if (x !== _this.tooltipForX) { | ||
_this.tooltipForX = x; | ||
var onTouchStart = function onTouchStart(event) { | ||
// Ignore multitouch. | ||
if (event.touches.length > 1) { | ||
// Reset. | ||
return onTrackStop(); | ||
if (!_this.tooltip) { | ||
_this.mount(); | ||
} | ||
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 | ||
_this.updateTooltip(x, xIndex, canvasDimensions.width); | ||
} | ||
}); | ||
_defineProperty(this, "unmountLine", function () { | ||
var canvas = _this.props.canvas; | ||
canvas.removeChild(_this.line); | ||
_this.line = undefined; | ||
}); | ||
canvas.addEventListener('touchstart', onTouchStart); | ||
_defineProperty(this, "mountPoints", function () { | ||
var pointsContainer = _this.props.pointsContainer; | ||
_this.points = _this.renderPoints(); | ||
function onTouchMove(event) { | ||
var x = event.changedTouches[0].clientX; | ||
var y = event.changedTouches[0].clientY; // Emulate 'pointerleave' behavior. | ||
for (var _iterator = _this.points, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref; | ||
if (x < canvasDimensions.left || x > canvasDimensions.left + canvasDimensions.width || y < canvasDimensions.top || y > canvasDimensions.top + canvasDimensions.height) { | ||
onTrackStop(); | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref = _iterator[_i++]; | ||
} else { | ||
onTrack(x, y); | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref = _i.value; | ||
} | ||
} | ||
function onPointerMove(event) { | ||
onTrack(event.clientX, event.clientY); | ||
var point = _ref; | ||
pointsContainer.appendChild(point); | ||
} | ||
var onTrackStop = 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); | ||
_this.unmount(); | ||
}; | ||
var onPointerEnter = 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); | ||
}; | ||
}); | ||
_defineProperty(this, "unmountLine", function () { | ||
var canvas = _this.props.canvas; | ||
canvas.removeChild(_this.line); | ||
_this.line = undefined; | ||
}); | ||
_defineProperty(this, "unmountPoints", function () { | ||
@@ -214,14 +119,14 @@ var pointsContainer = _this.props.pointsContainer; | ||
for (var _iterator2 = _this.points, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { | ||
var _ref3; | ||
var _ref2; | ||
if (_isArray2) { | ||
if (_i2 >= _iterator2.length) break; | ||
_ref3 = _iterator2[_i2++]; | ||
_ref2 = _iterator2[_i2++]; | ||
} else { | ||
_i2 = _iterator2.next(); | ||
if (_i2.done) break; | ||
_ref3 = _i2.value; | ||
_ref2 = _i2.value; | ||
} | ||
var point = _ref3; | ||
var point = _ref2; | ||
pointsContainer.removeChild(point); | ||
@@ -233,12 +138,12 @@ } | ||
_defineProperty(this, "updateLine", function (x) { | ||
_defineProperty(this, "updateLinePosition", function (x) { | ||
if (!_this.isLineRendered()) { | ||
_this.renderLine(); | ||
_this.mountLine(); | ||
} | ||
var _this$props3 = _this.props, | ||
canvasWidth = _this$props3.canvasWidth, | ||
aspectRatio = _this$props3.aspectRatio, | ||
fixSvgCoordinate = _this$props3.fixSvgCoordinate, | ||
mapX = _this$props3.mapX; | ||
var _this$props2 = _this.props, | ||
canvasWidth = _this$props2.canvasWidth, | ||
aspectRatio = _this$props2.aspectRatio, | ||
fixSvgCoordinate = _this$props2.fixSvgCoordinate, | ||
mapX = _this$props2.mapX; | ||
@@ -254,6 +159,6 @@ _this.line.setAttributeNS(null, 'x1', fixSvgCoordinate(mapX(x))); | ||
_defineProperty(this, "updatePoints", function (xIndex, xRatio) { | ||
var _this$props4 = _this.props, | ||
maxY = _this$props4.maxY, | ||
y = _this$props4.y; | ||
_defineProperty(this, "updatePointPositions", function (xIndex, xRatio) { | ||
var _this$props3 = _this.props, | ||
maxY = _this$props3.maxY, | ||
y = _this$props3.y; | ||
var i = 0; | ||
@@ -300,43 +205,66 @@ var j = 0; | ||
value: function mount() { | ||
this.renderTooltip(); | ||
this.renderPoints(); | ||
var container = this.props.container; | ||
this.tooltip = this.renderTooltip(); | ||
container.appendChild(this.tooltip); | ||
this.mountPoints(); | ||
if (!this.isLineRendered()) { | ||
this.renderLine(); | ||
this.mountLine(); | ||
} | ||
} | ||
}, { | ||
key: "unmount", | ||
value: function unmount() { | ||
if (!this.tooltip) { | ||
return; | ||
} | ||
var container = this.props.container; | ||
this.tooltipForX = undefined; | ||
container.removeChild(this.tooltip); | ||
this.tooltip = undefined; | ||
this.unmountPoints(); | ||
if (this.isLineRendered()) { | ||
this.unmountLine(); | ||
} | ||
} | ||
}, { | ||
key: "mountLine", | ||
value: function mountLine() { | ||
var canvas = this.props.canvas; | ||
this.line = this.renderLine(); | ||
canvas.insertBefore(this.line, canvas.querySelector('polyline')); | ||
} | ||
}, { | ||
key: "renderTooltip", | ||
value: function renderTooltip() { | ||
var _this$props5 = this.props, | ||
y = _this$props5.y, | ||
container = _this$props5.container; // Create tooltip. | ||
var y = this.props.y; // Create tooltip. | ||
this.tooltip = document.createElement('div'); | ||
this.tooltip.classList.add('chartogram__tooltip'); | ||
container.appendChild(this.tooltip); // Add tooltip title. | ||
var tooltip = document.createElement('div'); | ||
tooltip.classList.add('chartogram__tooltip'); // Add tooltip title. | ||
this.tooltipDate = document.createElement('h1'); | ||
this.tooltipDate.classList.add('chartogram__tooltip-header'); | ||
this.tooltip.appendChild(this.tooltipDate); // Add graph values. | ||
var tooltipDate = document.createElement('h1'); | ||
tooltipDate.classList.add('chartogram__tooltip-header'); | ||
tooltip.appendChild(tooltipDate); // Add graph values. | ||
this.tooltipValues = document.createElement('dl'); | ||
this.tooltipValues.classList.add('chartogram__tooltip-values'); | ||
this.tooltip.appendChild(this.tooltipValues); // Add graph values. | ||
var tooltipValues = document.createElement('dl'); | ||
tooltipValues.classList.add('chartogram__tooltip-values'); | ||
tooltip.appendChild(tooltipValues); // Add graph values. | ||
for (var _iterator3 = y, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref4; | ||
var _ref3; | ||
if (_isArray3) { | ||
if (_i3 >= _iterator3.length) break; | ||
_ref4 = _iterator3[_i3++]; | ||
_ref3 = _iterator3[_i3++]; | ||
} else { | ||
_i3 = _iterator3.next(); | ||
if (_i3.done) break; | ||
_ref4 = _i3.value; | ||
_ref3 = _i3.value; | ||
} | ||
var _ref5 = _ref4, | ||
isShown = _ref5.isShown, | ||
color = _ref5.color; | ||
var _ref4 = _ref3, | ||
isShown = _ref4.isShown, | ||
color = _ref4.color; | ||
@@ -347,9 +275,11 @@ if (isShown) { | ||
tooltipValue.style.color = color; | ||
this.tooltipValues.appendChild(tooltipValue); // Add graph name. | ||
tooltipValues.appendChild(tooltipValue); // Add graph name. | ||
var tooltipName = document.createElement('dd'); | ||
tooltipName.style.color = color; | ||
this.tooltipValues.appendChild(tooltipName); | ||
tooltipValues.appendChild(tooltipName); | ||
} | ||
} | ||
return tooltip; | ||
} | ||
@@ -359,24 +289,8 @@ }, { | ||
value: function renderLine() { | ||
var canvas = this.props.canvas; | ||
var xmlns = 'http://www.w3.org/2000/svg'; | ||
this.line = document.createElementNS(xmlns, 'line'); | ||
this.line.setAttribute('class', 'chartogram__tooltip-line'); | ||
canvas.insertBefore(this.line, canvas.querySelector('polyline')); | ||
var line = document.createElementNS(xmlns, 'line'); | ||
line.setAttribute('class', 'chartogram__tooltip-line'); | ||
return line; | ||
} | ||
}, { | ||
key: "unmount", | ||
value: function unmount() { | ||
if (this.tooltip) { | ||
var container = this.props.container; | ||
this.tooltipForX = undefined; | ||
container.removeChild(this.tooltip); | ||
this.tooltip = undefined; | ||
this.unmountPoints(); | ||
if (this.isLineRendered()) { | ||
this.unmountLine(); | ||
} | ||
} | ||
} | ||
}, { | ||
key: "isLineRendered", | ||
@@ -390,20 +304,20 @@ value: function isLineRendered() { | ||
value: function renderPoints() { | ||
this.points = []; | ||
var _this$props6 = this.props, | ||
pointsContainer = _this$props6.pointsContainer, | ||
y = _this$props6.y; | ||
var points = []; | ||
var _this$props4 = this.props, | ||
pointsContainer = _this$props4.pointsContainer, | ||
y = _this$props4.y; | ||
for (var _iterator4 = y, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { | ||
var _ref6; | ||
var _ref5; | ||
if (_isArray4) { | ||
if (_i4 >= _iterator4.length) break; | ||
_ref6 = _iterator4[_i4++]; | ||
_ref5 = _iterator4[_i4++]; | ||
} else { | ||
_i4 = _iterator4.next(); | ||
if (_i4.done) break; | ||
_ref6 = _i4.value; | ||
_ref5 = _i4.value; | ||
} | ||
var _y = _ref6; | ||
var _y = _ref5; | ||
@@ -414,7 +328,81 @@ if (_y.isShown) { | ||
point.style.color = _y.color; | ||
this.points.push(point); | ||
points.push(point); | ||
pointsContainer.appendChild(point); | ||
} | ||
} | ||
return points; | ||
} | ||
}, { | ||
key: "updateTooltip", | ||
value: function updateTooltip(x, xIndex, canvasWidth) { | ||
var _this$props5 = this.props, | ||
minX = _this$props5.minX, | ||
maxX = _this$props5.maxX; | ||
var xRatio = (x - minX) / (maxX - minX); | ||
this.updateTooltipDate(new Date(x)); | ||
this.updateTooltipValues(xIndex); | ||
this.updateTooltipPosition(xRatio, canvasWidth); | ||
this.updatePointPositions(xIndex, xRatio); | ||
this.updateLinePosition(x); | ||
} | ||
}, { | ||
key: "updateTooltipPosition", | ||
value: function updateTooltipPosition(xRatio, canvasWidth) { | ||
var _this$props6 = this.props, | ||
tooltipShift = _this$props6.tooltipShift, | ||
maxOverflow = _this$props6.maxOverflow; | ||
var left = xRatio * canvasWidth; | ||
left -= tooltipShift === undefined ? 40 : tooltipShift; | ||
var tooltipWidth = this.tooltip.getBoundingClientRect().width; | ||
var overflow = maxOverflow === undefined ? 5 : maxOverflow; | ||
if (left < -1 * overflow) { | ||
left = -1 * overflow; | ||
} else if (left + tooltipWidth > canvasWidth + overflow) { | ||
left = canvasWidth + overflow - tooltipWidth; | ||
} | ||
this.tooltip.style.left = left + 'px'; | ||
} | ||
}, { | ||
key: "updateTooltipDate", | ||
value: function updateTooltipDate(date) { | ||
var _this$props7 = this.props, | ||
weekdays = _this$props7.weekdays, | ||
months = _this$props7.months; | ||
var tooltipDate = this.tooltip.childNodes[0]; | ||
tooltipDate.textContent = "".concat(weekdays[date.getDay()], ", ").concat(months[date.getMonth()], " ").concat(date.getDate()); | ||
} | ||
}, { | ||
key: "updateTooltipValues", | ||
value: function updateTooltipValues(xIndex) { | ||
var y = this.props.y; | ||
var tooltipValues = this.tooltip.childNodes[1]; | ||
var i = 0; | ||
for (var _iterator5 = y, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { | ||
var _ref6; | ||
if (_isArray5) { | ||
if (_i5 >= _iterator5.length) break; | ||
_ref6 = _iterator5[_i5++]; | ||
} else { | ||
_i5 = _iterator5.next(); | ||
if (_i5.done) break; | ||
_ref6 = _i5.value; | ||
} | ||
var _ref7 = _ref6, | ||
isShown = _ref7.isShown, | ||
points = _ref7.points, | ||
name = _ref7.name; | ||
if (isShown) { | ||
tooltipValues.childNodes[2 * i].textContent = points[xIndex]; | ||
tooltipValues.childNodes[2 * i + 1].textContent = name; | ||
i++; | ||
} | ||
} | ||
} | ||
}]); | ||
@@ -421,0 +409,0 @@ |
@@ -14,2 +14,3 @@ "use strict"; | ||
exports.setUpDrag = setUpDrag; | ||
exports.setUpTouchMove = setUpTouchMove; | ||
@@ -210,2 +211,75 @@ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
} | ||
function setUpTouchMove(element, _onTrackStart, _onTrack, _onTrackStop) { | ||
var elementBounds; | ||
function onTrack(x, y) { | ||
_onTrack(x, y, elementBounds); | ||
} | ||
function onTrackStart() { | ||
elementBounds = element.getBoundingClientRect(); | ||
_onTrackStart(); | ||
} | ||
function onTouchStart(event) { | ||
// Ignore multitouch. | ||
if (event.touches.length > 1) { | ||
// Reset. | ||
return onTrackStop(); | ||
} | ||
onTrackStart(); | ||
element.addEventListener('touchend', onTrackStop); | ||
element.addEventListener('touchmove', onTouchMove); | ||
element.addEventListener('touchend', onTrackStop); | ||
element.addEventListener('touchcancel', onTrackStop); | ||
onTouchMove(event); | ||
} // Safari doesn't support pointer events. | ||
// https://caniuse.com/#feat=pointer | ||
element.addEventListener('touchstart', onTouchStart); | ||
function onTouchMove(event) { | ||
var x = event.changedTouches[0].clientX; | ||
var y = event.changedTouches[0].clientY; // Emulate 'pointerleave' behavior. | ||
if (x < elementBounds.left || x > elementBounds.left + elementBounds.width || y < elementBounds.top || y > elementBounds.top + elementBounds.height) { | ||
onTrackStop(); | ||
} else { | ||
onTrack(x, y); | ||
} | ||
} | ||
function onPointerMove(event) { | ||
onTrack(event.clientX, event.clientY); | ||
} | ||
function onTrackStop() { | ||
element.removeEventListener('pointermove', onPointerMove); | ||
element.removeEventListener('pointerleave', onTrackStop); | ||
element.removeEventListener('pointercancel', onTrackStop); | ||
element.removeEventListener('touchmove', onTouchMove); | ||
element.removeEventListener('touchend', onTrackStop); | ||
element.removeEventListener('touchcancel', onTrackStop); | ||
_onTrackStop(); | ||
} | ||
function onPointerEnter() { | ||
onTrackStart(); | ||
element.addEventListener('pointermove', onPointerMove); | ||
element.addEventListener('pointerleave', onTrackStop); | ||
element.addEventListener('pointercancel', onTrackStop); | ||
} | ||
element.addEventListener('pointerenter', onPointerEnter); | ||
return function () { | ||
onTrackStop(); | ||
element.removeEventListener(onPointerEnter); | ||
element.removeEventListener(onTouchStart); | ||
}; | ||
} | ||
//# sourceMappingURL=utility.js.map |
@@ -37,4 +37,3 @@ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
_this.setState({ | ||
aspectRatio: _this.getCanvasAspectRatio(), | ||
canvasWidthPx: _this.getCanvasWidthPx() | ||
aspectRatio: _this.getCanvasAspectRatio() | ||
}, false); | ||
@@ -81,3 +80,12 @@ }); | ||
_defineProperty(this, "onChangeBounds", function (from, to) { | ||
_this.setState(_this.createState(from, to), false); | ||
var state = _this.createState(from, to); | ||
var minY = state.minY; | ||
var maxY = state.maxY; | ||
delete state.minY; | ||
delete state.maxY; | ||
_this.setState(state, false); | ||
_this.transitionState(minY, maxY); | ||
}); | ||
@@ -130,13 +138,41 @@ | ||
ratio = EASING[transitionEasing](ratio); | ||
var state = {}; | ||
_this.setState({ | ||
graphOpacity: graphOpacityTo.map(function (_, i) { | ||
if (minYTo !== undefined) { | ||
state.minY = minYFrom + (minYTo - minYFrom) * ratio; | ||
state.maxY = maxYFrom + (maxYTo - maxYFrom) * ratio; | ||
if (ratio === 1) { | ||
state.minYFrom = undefined; | ||
state.minYTo = undefined; | ||
state.maxYFrom = undefined; | ||
state.maxYTo = undefined; | ||
} | ||
} | ||
if (minYGlobalTo !== undefined) { | ||
state.minYGlobal = minYGlobalFrom + (minYGlobalTo - minYGlobalFrom) * ratio; | ||
state.maxYGlobal = maxYGlobalFrom + (maxYGlobalTo - maxYGlobalFrom) * ratio; | ||
if (ratio === 1) { | ||
state.minYGlobalFrom = undefined; | ||
state.minYGlobalTo = undefined; | ||
state.maxYGlobalFrom = undefined; | ||
state.maxYGlobalTo = undefined; | ||
} | ||
} | ||
if (graphOpacityTo !== undefined) { | ||
state.graphOpacity = graphOpacityTo.map(function (_, i) { | ||
return graphOpacityFrom[i] + (graphOpacityTo[i] - graphOpacityFrom[i]) * ratio; | ||
}), | ||
minY: minYFrom + (minYTo - minYFrom) * ratio, | ||
maxY: maxYFrom + (maxYTo - maxYFrom) * ratio, | ||
minYGlobal: minYGlobalFrom + (minYGlobalTo - minYGlobalFrom) * ratio, | ||
maxYGlobal: maxYGlobalFrom + (maxYGlobalTo - maxYGlobalFrom) * ratio | ||
}); | ||
}); | ||
if (ratio === 1) { | ||
state.graphOpacityFrom = undefined; | ||
state.graphOpacityTo = undefined; | ||
} | ||
} | ||
_this.setState(state); | ||
if (ratio < 1) { | ||
@@ -180,3 +216,3 @@ _this.transition = requestAnimationFrame(_this.transitionStateTick); | ||
title: title, | ||
transitionDuration: 300, | ||
transitionDuration: 250, | ||
transitionEasing: 'easeOutQuad', | ||
@@ -233,2 +269,6 @@ gaugeTickMarksCount: 6, | ||
window.removeEventListener('resize', this.onResizeThrottled); | ||
if (this.transition) { | ||
cancelAnimationFrame(this.transition); | ||
} | ||
} | ||
@@ -242,8 +282,2 @@ }, { | ||
}, { | ||
key: "getCanvasWidthPx", | ||
value: function getCanvasWidthPx() { | ||
var canvasDimensions = this.canvas.getBoundingClientRect(); | ||
return canvasDimensions.width; | ||
} | ||
}, { | ||
key: "setState", | ||
@@ -293,3 +327,2 @@ value: function setState(newState) { | ||
canvas: this.canvas, | ||
canvasWidthPx: this.state.canvasWidthPx, | ||
container: this.tooltipContainer, | ||
@@ -330,3 +363,2 @@ pointsContainer: this.canvasWrapper, | ||
aspectRatio: this.getCanvasAspectRatio(), | ||
canvasWidthPx: this.getCanvasWidthPx(), | ||
graphOpacity: this.data.y.map(function (_) { | ||
@@ -579,22 +611,38 @@ return 1; | ||
var heightBefore = this.state.maxY - this.state.minY; | ||
var deltaMaxY = Math.abs(maxY - this.state.maxY) / heightBefore; | ||
var deltaMinY = Math.abs(minY - this.state.minY) / heightBefore; | ||
var deltaY = Math.max(deltaMinY, deltaMaxY); | ||
var transitionDuration = maxTransitionDuration * Math.max(0.1, Math.min(deltaY, 0.5) * 2); | ||
this.setState({ | ||
graphOpacityFrom: this.state.graphOpacity, | ||
graphOpacityTo: graphOpacity, | ||
minYFrom: this.state.minY, | ||
maxYFrom: this.state.maxY, | ||
minYTo: minY, | ||
maxYTo: maxY, | ||
minYGlobalFrom: this.state.minYGlobal, | ||
maxYGlobalFrom: this.state.maxYGlobal, | ||
minYGlobalTo: minYGlobal, | ||
maxYGlobalTo: maxYGlobal, | ||
var transitionDuration = maxTransitionDuration; | ||
if (minY !== undefined) { | ||
var heightBefore = this.state.maxY - this.state.minY; | ||
var deltaMaxY = Math.abs(maxY - this.state.maxY) / heightBefore; | ||
var deltaMinY = Math.abs(minY - this.state.minY) / heightBefore; | ||
var deltaY = Math.max(deltaMinY, deltaMaxY); | ||
transitionDuration = maxTransitionDuration * Math.max(0.2, Math.min(deltaY, 0.5) * 2); | ||
} | ||
var state = { | ||
transitionStartedAt: Date.now(), | ||
transitionDuration: transitionDuration | ||
}); // Place in a `setState()` callback in case of React. | ||
}; | ||
if (minY !== undefined) { | ||
state.minYFrom = this.state.minY; | ||
state.maxYFrom = this.state.maxY; | ||
state.minYTo = minY; | ||
state.maxYTo = maxY; | ||
} | ||
if (graphOpacity !== undefined) { | ||
state.graphOpacityFrom = this.state.graphOpacity; | ||
state.graphOpacityTo = graphOpacity; | ||
} | ||
if (minYGlobal !== undefined) { | ||
state.minYGlobalFrom = this.state.minYGlobal; | ||
state.maxYGlobalFrom = this.state.maxYGlobal; | ||
state.minYGlobalTo = minYGlobal; | ||
state.maxYGlobalTo = maxYGlobal; | ||
} | ||
this.setState(state); // Place in a `setState()` callback in case of React. | ||
this.transition = requestAnimationFrame(this.transitionStateTick); | ||
@@ -601,0 +649,0 @@ } |
@@ -9,2 +9,4 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
import { setUpTouchMove } from './utility'; | ||
var Tooltip = | ||
@@ -19,185 +21,88 @@ /*#__PURE__*/ | ||
_defineProperty(this, "setUpListener", function () { | ||
var canvas = _this.props.canvas; | ||
setUpTouchMove(canvas, function () {}, _this.onTrack, function () { | ||
return _this.unmount(); | ||
}); | ||
}); | ||
_defineProperty(this, "onTrack", function (screenX, screenY, canvasDimensions) { | ||
var _this$props = _this.props, | ||
canvas = _this$props.canvas, | ||
canvasWidthPx = _this$props.canvasWidthPx, | ||
weekdays = _this$props.weekdays, | ||
months = _this$props.months; | ||
var canvasDimensions; | ||
var isIndexInBounds; | ||
minX = _this$props.minX, | ||
maxX = _this$props.maxX, | ||
xPoints = _this$props.xPoints; | ||
var xScreenRatio = (screenX - canvasDimensions.left) / canvasDimensions.width; | ||
var xPoint = minX + xScreenRatio * (maxX - minX); | ||
var xHigherIndex = xPoints.findIndex(function (_) { | ||
return _ >= xPoint; | ||
}); | ||
var xLowerIndex = xHigherIndex - 1; | ||
var onTrack = function onTrack(screenX) { | ||
var _this$props2 = _this.props, | ||
minX = _this$props2.minX, | ||
maxX = _this$props2.maxX, | ||
xPoints = _this$props2.xPoints, | ||
y = _this$props2.y; | ||
var xScreenRatio = (screenX - canvasDimensions.left) / canvasDimensions.width; | ||
var xPoint = minX + xScreenRatio * (maxX - minX); | ||
var xHigherIndex = xPoints.findIndex(function (_) { | ||
return _ >= xPoint; | ||
}); | ||
var xLowerIndex = xHigherIndex - 1; | ||
if (xHigherIndex < 0 || xHigherIndex >= xPoints.length) { | ||
xHigherIndex = -1; | ||
} | ||
if (!isIndexInBounds(xHigherIndex)) { | ||
xHigherIndex = -1; | ||
} | ||
if (xLowerIndex < 0 || xLowerIndex >= xPoints.length) { | ||
xLowerIndex = -1; | ||
} | ||
if (!isIndexInBounds(xLowerIndex)) { | ||
xLowerIndex = -1; | ||
} | ||
var xIndex; | ||
var xIndex; | ||
if (xHigherIndex < 0) { | ||
if (xLowerIndex < 0) { | ||
return _this.unmount(); | ||
} else { | ||
xIndex = xLowerIndex; | ||
} | ||
if (xHigherIndex < 0) { | ||
if (xLowerIndex < 0) { | ||
return _this.unmount(); | ||
} else { | ||
if (xLowerIndex < 0) { | ||
xIndex = xHigherIndex; | ||
} else { | ||
var xLower = xPoints[xLowerIndex]; | ||
var xHigher = xPoints[xHigherIndex]; | ||
var deltaLower = xPoint - xLower; | ||
var deltaHigher = xHigher - xPoint; | ||
xIndex = deltaLower > deltaHigher ? xHigherIndex : xLowerIndex; | ||
} | ||
xIndex = xLowerIndex; | ||
} | ||
var x = xPoints[xIndex]; | ||
if (x !== _this.tooltipForX) { | ||
_this.tooltipForX = x; | ||
if (!_this.tooltip) { | ||
_this.mount(); | ||
} | ||
var date = new Date(x); | ||
_this.tooltipDate.textContent = "".concat(weekdays[date.getDay()], ", ").concat(months[date.getMonth()], " ").concat(date.getDate()); | ||
var i = 0; | ||
for (var _iterator = y, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref; | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref = _iterator[_i++]; | ||
} else { | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref = _i.value; | ||
} | ||
var _ref2 = _ref, | ||
isShown = _ref2.isShown, | ||
points = _ref2.points, | ||
name = _ref2.name; | ||
if (isShown) { | ||
_this.tooltipValues.childNodes[2 * i].textContent = points[xIndex]; | ||
_this.tooltipValues.childNodes[2 * i + 1].textContent = name; | ||
i++; | ||
} | ||
} | ||
var xRatio = (x - minX) / (maxX - minX); | ||
var left = xRatio * canvasWidthPx; | ||
left -= 40; | ||
var tooltipWidth = _this.tooltip.getBoundingClientRect().width; | ||
var overflow = 5; | ||
if (left < -1 * overflow) { | ||
left = -1 * overflow; | ||
} else if (left + tooltipWidth > canvasWidthPx + overflow) { | ||
left = canvasWidthPx + overflow - tooltipWidth; | ||
} | ||
_this.tooltip.style.left = left + 'px'; | ||
_this.updatePoints(xIndex, xRatio); | ||
_this.updateLine(x); | ||
} else { | ||
if (xLowerIndex < 0) { | ||
xIndex = xHigherIndex; | ||
} else { | ||
var xLower = xPoints[xLowerIndex]; | ||
var xHigher = xPoints[xHigherIndex]; | ||
var deltaLower = xPoint - xLower; | ||
var deltaHigher = xHigher - xPoint; | ||
xIndex = deltaLower > deltaHigher ? xHigherIndex : xLowerIndex; | ||
} | ||
}; | ||
} | ||
var onTrackStart = function onTrackStart() { | ||
canvasDimensions = canvas.getBoundingClientRect(); | ||
var x = xPoints[xIndex]; | ||
isIndexInBounds = function isIndexInBounds(index) { | ||
var xPoints = _this.props.xPoints; | ||
return index >= 0 && index < xPoints.length; | ||
}; | ||
}; | ||
if (x !== _this.tooltipForX) { | ||
_this.tooltipForX = x; | ||
var onTouchStart = function onTouchStart(event) { | ||
// Ignore multitouch. | ||
if (event.touches.length > 1) { | ||
// Reset. | ||
return onTrackStop(); | ||
if (!_this.tooltip) { | ||
_this.mount(); | ||
} | ||
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 | ||
_this.updateTooltip(x, xIndex, canvasDimensions.width); | ||
} | ||
}); | ||
_defineProperty(this, "unmountLine", function () { | ||
var canvas = _this.props.canvas; | ||
canvas.removeChild(_this.line); | ||
_this.line = undefined; | ||
}); | ||
canvas.addEventListener('touchstart', onTouchStart); | ||
_defineProperty(this, "mountPoints", function () { | ||
var pointsContainer = _this.props.pointsContainer; | ||
_this.points = _this.renderPoints(); | ||
function onTouchMove(event) { | ||
var x = event.changedTouches[0].clientX; | ||
var y = event.changedTouches[0].clientY; // Emulate 'pointerleave' behavior. | ||
for (var _iterator = _this.points, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) { | ||
var _ref; | ||
if (x < canvasDimensions.left || x > canvasDimensions.left + canvasDimensions.width || y < canvasDimensions.top || y > canvasDimensions.top + canvasDimensions.height) { | ||
onTrackStop(); | ||
if (_isArray) { | ||
if (_i >= _iterator.length) break; | ||
_ref = _iterator[_i++]; | ||
} else { | ||
onTrack(x, y); | ||
_i = _iterator.next(); | ||
if (_i.done) break; | ||
_ref = _i.value; | ||
} | ||
} | ||
function onPointerMove(event) { | ||
onTrack(event.clientX, event.clientY); | ||
var point = _ref; | ||
pointsContainer.appendChild(point); | ||
} | ||
var onTrackStop = 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); | ||
_this.unmount(); | ||
}; | ||
var onPointerEnter = 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); | ||
}; | ||
}); | ||
_defineProperty(this, "unmountLine", function () { | ||
var canvas = _this.props.canvas; | ||
canvas.removeChild(_this.line); | ||
_this.line = undefined; | ||
}); | ||
_defineProperty(this, "unmountPoints", function () { | ||
@@ -207,14 +112,14 @@ var pointsContainer = _this.props.pointsContainer; | ||
for (var _iterator2 = _this.points, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) { | ||
var _ref3; | ||
var _ref2; | ||
if (_isArray2) { | ||
if (_i2 >= _iterator2.length) break; | ||
_ref3 = _iterator2[_i2++]; | ||
_ref2 = _iterator2[_i2++]; | ||
} else { | ||
_i2 = _iterator2.next(); | ||
if (_i2.done) break; | ||
_ref3 = _i2.value; | ||
_ref2 = _i2.value; | ||
} | ||
var point = _ref3; | ||
var point = _ref2; | ||
pointsContainer.removeChild(point); | ||
@@ -226,12 +131,12 @@ } | ||
_defineProperty(this, "updateLine", function (x) { | ||
_defineProperty(this, "updateLinePosition", function (x) { | ||
if (!_this.isLineRendered()) { | ||
_this.renderLine(); | ||
_this.mountLine(); | ||
} | ||
var _this$props3 = _this.props, | ||
canvasWidth = _this$props3.canvasWidth, | ||
aspectRatio = _this$props3.aspectRatio, | ||
fixSvgCoordinate = _this$props3.fixSvgCoordinate, | ||
mapX = _this$props3.mapX; | ||
var _this$props2 = _this.props, | ||
canvasWidth = _this$props2.canvasWidth, | ||
aspectRatio = _this$props2.aspectRatio, | ||
fixSvgCoordinate = _this$props2.fixSvgCoordinate, | ||
mapX = _this$props2.mapX; | ||
@@ -247,6 +152,6 @@ _this.line.setAttributeNS(null, 'x1', fixSvgCoordinate(mapX(x))); | ||
_defineProperty(this, "updatePoints", function (xIndex, xRatio) { | ||
var _this$props4 = _this.props, | ||
maxY = _this$props4.maxY, | ||
y = _this$props4.y; | ||
_defineProperty(this, "updatePointPositions", function (xIndex, xRatio) { | ||
var _this$props3 = _this.props, | ||
maxY = _this$props3.maxY, | ||
y = _this$props3.y; | ||
var i = 0; | ||
@@ -293,43 +198,66 @@ var j = 0; | ||
value: function mount() { | ||
this.renderTooltip(); | ||
this.renderPoints(); | ||
var container = this.props.container; | ||
this.tooltip = this.renderTooltip(); | ||
container.appendChild(this.tooltip); | ||
this.mountPoints(); | ||
if (!this.isLineRendered()) { | ||
this.renderLine(); | ||
this.mountLine(); | ||
} | ||
} | ||
}, { | ||
key: "unmount", | ||
value: function unmount() { | ||
if (!this.tooltip) { | ||
return; | ||
} | ||
var container = this.props.container; | ||
this.tooltipForX = undefined; | ||
container.removeChild(this.tooltip); | ||
this.tooltip = undefined; | ||
this.unmountPoints(); | ||
if (this.isLineRendered()) { | ||
this.unmountLine(); | ||
} | ||
} | ||
}, { | ||
key: "mountLine", | ||
value: function mountLine() { | ||
var canvas = this.props.canvas; | ||
this.line = this.renderLine(); | ||
canvas.insertBefore(this.line, canvas.querySelector('polyline')); | ||
} | ||
}, { | ||
key: "renderTooltip", | ||
value: function renderTooltip() { | ||
var _this$props5 = this.props, | ||
y = _this$props5.y, | ||
container = _this$props5.container; // Create tooltip. | ||
var y = this.props.y; // Create tooltip. | ||
this.tooltip = document.createElement('div'); | ||
this.tooltip.classList.add('chartogram__tooltip'); | ||
container.appendChild(this.tooltip); // Add tooltip title. | ||
var tooltip = document.createElement('div'); | ||
tooltip.classList.add('chartogram__tooltip'); // Add tooltip title. | ||
this.tooltipDate = document.createElement('h1'); | ||
this.tooltipDate.classList.add('chartogram__tooltip-header'); | ||
this.tooltip.appendChild(this.tooltipDate); // Add graph values. | ||
var tooltipDate = document.createElement('h1'); | ||
tooltipDate.classList.add('chartogram__tooltip-header'); | ||
tooltip.appendChild(tooltipDate); // Add graph values. | ||
this.tooltipValues = document.createElement('dl'); | ||
this.tooltipValues.classList.add('chartogram__tooltip-values'); | ||
this.tooltip.appendChild(this.tooltipValues); // Add graph values. | ||
var tooltipValues = document.createElement('dl'); | ||
tooltipValues.classList.add('chartogram__tooltip-values'); | ||
tooltip.appendChild(tooltipValues); // Add graph values. | ||
for (var _iterator3 = y, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) { | ||
var _ref4; | ||
var _ref3; | ||
if (_isArray3) { | ||
if (_i3 >= _iterator3.length) break; | ||
_ref4 = _iterator3[_i3++]; | ||
_ref3 = _iterator3[_i3++]; | ||
} else { | ||
_i3 = _iterator3.next(); | ||
if (_i3.done) break; | ||
_ref4 = _i3.value; | ||
_ref3 = _i3.value; | ||
} | ||
var _ref5 = _ref4, | ||
isShown = _ref5.isShown, | ||
color = _ref5.color; | ||
var _ref4 = _ref3, | ||
isShown = _ref4.isShown, | ||
color = _ref4.color; | ||
@@ -340,9 +268,11 @@ if (isShown) { | ||
tooltipValue.style.color = color; | ||
this.tooltipValues.appendChild(tooltipValue); // Add graph name. | ||
tooltipValues.appendChild(tooltipValue); // Add graph name. | ||
var tooltipName = document.createElement('dd'); | ||
tooltipName.style.color = color; | ||
this.tooltipValues.appendChild(tooltipName); | ||
tooltipValues.appendChild(tooltipName); | ||
} | ||
} | ||
return tooltip; | ||
} | ||
@@ -352,24 +282,8 @@ }, { | ||
value: function renderLine() { | ||
var canvas = this.props.canvas; | ||
var xmlns = 'http://www.w3.org/2000/svg'; | ||
this.line = document.createElementNS(xmlns, 'line'); | ||
this.line.setAttribute('class', 'chartogram__tooltip-line'); | ||
canvas.insertBefore(this.line, canvas.querySelector('polyline')); | ||
var line = document.createElementNS(xmlns, 'line'); | ||
line.setAttribute('class', 'chartogram__tooltip-line'); | ||
return line; | ||
} | ||
}, { | ||
key: "unmount", | ||
value: function unmount() { | ||
if (this.tooltip) { | ||
var container = this.props.container; | ||
this.tooltipForX = undefined; | ||
container.removeChild(this.tooltip); | ||
this.tooltip = undefined; | ||
this.unmountPoints(); | ||
if (this.isLineRendered()) { | ||
this.unmountLine(); | ||
} | ||
} | ||
} | ||
}, { | ||
key: "isLineRendered", | ||
@@ -383,20 +297,20 @@ value: function isLineRendered() { | ||
value: function renderPoints() { | ||
this.points = []; | ||
var _this$props6 = this.props, | ||
pointsContainer = _this$props6.pointsContainer, | ||
y = _this$props6.y; | ||
var points = []; | ||
var _this$props4 = this.props, | ||
pointsContainer = _this$props4.pointsContainer, | ||
y = _this$props4.y; | ||
for (var _iterator4 = y, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) { | ||
var _ref6; | ||
var _ref5; | ||
if (_isArray4) { | ||
if (_i4 >= _iterator4.length) break; | ||
_ref6 = _iterator4[_i4++]; | ||
_ref5 = _iterator4[_i4++]; | ||
} else { | ||
_i4 = _iterator4.next(); | ||
if (_i4.done) break; | ||
_ref6 = _i4.value; | ||
_ref5 = _i4.value; | ||
} | ||
var _y = _ref6; | ||
var _y = _ref5; | ||
@@ -407,7 +321,81 @@ if (_y.isShown) { | ||
point.style.color = _y.color; | ||
this.points.push(point); | ||
points.push(point); | ||
pointsContainer.appendChild(point); | ||
} | ||
} | ||
return points; | ||
} | ||
}, { | ||
key: "updateTooltip", | ||
value: function updateTooltip(x, xIndex, canvasWidth) { | ||
var _this$props5 = this.props, | ||
minX = _this$props5.minX, | ||
maxX = _this$props5.maxX; | ||
var xRatio = (x - minX) / (maxX - minX); | ||
this.updateTooltipDate(new Date(x)); | ||
this.updateTooltipValues(xIndex); | ||
this.updateTooltipPosition(xRatio, canvasWidth); | ||
this.updatePointPositions(xIndex, xRatio); | ||
this.updateLinePosition(x); | ||
} | ||
}, { | ||
key: "updateTooltipPosition", | ||
value: function updateTooltipPosition(xRatio, canvasWidth) { | ||
var _this$props6 = this.props, | ||
tooltipShift = _this$props6.tooltipShift, | ||
maxOverflow = _this$props6.maxOverflow; | ||
var left = xRatio * canvasWidth; | ||
left -= tooltipShift === undefined ? 40 : tooltipShift; | ||
var tooltipWidth = this.tooltip.getBoundingClientRect().width; | ||
var overflow = maxOverflow === undefined ? 5 : maxOverflow; | ||
if (left < -1 * overflow) { | ||
left = -1 * overflow; | ||
} else if (left + tooltipWidth > canvasWidth + overflow) { | ||
left = canvasWidth + overflow - tooltipWidth; | ||
} | ||
this.tooltip.style.left = left + 'px'; | ||
} | ||
}, { | ||
key: "updateTooltipDate", | ||
value: function updateTooltipDate(date) { | ||
var _this$props7 = this.props, | ||
weekdays = _this$props7.weekdays, | ||
months = _this$props7.months; | ||
var tooltipDate = this.tooltip.childNodes[0]; | ||
tooltipDate.textContent = "".concat(weekdays[date.getDay()], ", ").concat(months[date.getMonth()], " ").concat(date.getDate()); | ||
} | ||
}, { | ||
key: "updateTooltipValues", | ||
value: function updateTooltipValues(xIndex) { | ||
var y = this.props.y; | ||
var tooltipValues = this.tooltip.childNodes[1]; | ||
var i = 0; | ||
for (var _iterator5 = y, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) { | ||
var _ref6; | ||
if (_isArray5) { | ||
if (_i5 >= _iterator5.length) break; | ||
_ref6 = _iterator5[_i5++]; | ||
} else { | ||
_i5 = _iterator5.next(); | ||
if (_i5.done) break; | ||
_ref6 = _i5.value; | ||
} | ||
var _ref7 = _ref6, | ||
isShown = _ref7.isShown, | ||
points = _ref7.points, | ||
name = _ref7.name; | ||
if (isShown) { | ||
tooltipValues.childNodes[2 * i].textContent = points[xIndex]; | ||
tooltipValues.childNodes[2 * i + 1].textContent = name; | ||
i++; | ||
} | ||
} | ||
} | ||
}]); | ||
@@ -414,0 +402,0 @@ |
@@ -188,2 +188,74 @@ function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } | ||
} | ||
export function setUpTouchMove(element, _onTrackStart, _onTrack, _onTrackStop) { | ||
var elementBounds; | ||
function onTrack(x, y) { | ||
_onTrack(x, y, elementBounds); | ||
} | ||
function onTrackStart() { | ||
elementBounds = element.getBoundingClientRect(); | ||
_onTrackStart(); | ||
} | ||
function onTouchStart(event) { | ||
// Ignore multitouch. | ||
if (event.touches.length > 1) { | ||
// Reset. | ||
return onTrackStop(); | ||
} | ||
onTrackStart(); | ||
element.addEventListener('touchend', onTrackStop); | ||
element.addEventListener('touchmove', onTouchMove); | ||
element.addEventListener('touchend', onTrackStop); | ||
element.addEventListener('touchcancel', onTrackStop); | ||
onTouchMove(event); | ||
} // Safari doesn't support pointer events. | ||
// https://caniuse.com/#feat=pointer | ||
element.addEventListener('touchstart', onTouchStart); | ||
function onTouchMove(event) { | ||
var x = event.changedTouches[0].clientX; | ||
var y = event.changedTouches[0].clientY; // Emulate 'pointerleave' behavior. | ||
if (x < elementBounds.left || x > elementBounds.left + elementBounds.width || y < elementBounds.top || y > elementBounds.top + elementBounds.height) { | ||
onTrackStop(); | ||
} else { | ||
onTrack(x, y); | ||
} | ||
} | ||
function onPointerMove(event) { | ||
onTrack(event.clientX, event.clientY); | ||
} | ||
function onTrackStop() { | ||
element.removeEventListener('pointermove', onPointerMove); | ||
element.removeEventListener('pointerleave', onTrackStop); | ||
element.removeEventListener('pointercancel', onTrackStop); | ||
element.removeEventListener('touchmove', onTouchMove); | ||
element.removeEventListener('touchend', onTrackStop); | ||
element.removeEventListener('touchcancel', onTrackStop); | ||
_onTrackStop(); | ||
} | ||
function onPointerEnter() { | ||
onTrackStart(); | ||
element.addEventListener('pointermove', onPointerMove); | ||
element.addEventListener('pointerleave', onTrackStop); | ||
element.addEventListener('pointercancel', onTrackStop); | ||
} | ||
element.addEventListener('pointerenter', onPointerEnter); | ||
return function () { | ||
onTrackStop(); | ||
element.removeEventListener(onPointerEnter); | ||
element.removeEventListener(onTouchStart); | ||
}; | ||
} | ||
//# sourceMappingURL=utility.js.map |
{ | ||
"name": "chartogram", | ||
"version": "0.1.8", | ||
"version": "0.1.9", | ||
"description": "Charts in JS with no dependencies", | ||
@@ -5,0 +5,0 @@ "main": "index.commonjs.js", |
@@ -18,3 +18,3 @@ import { | ||
title, | ||
transitionDuration: 300, | ||
transitionDuration: 250, | ||
transitionEasing: 'easeOutQuad', | ||
@@ -83,2 +83,5 @@ gaugeTickMarksCount: 6, | ||
window.removeEventListener('resize', this.onResizeThrottled) | ||
if (this.transition) { | ||
cancelAnimationFrame(this.transition) | ||
} | ||
} | ||
@@ -88,4 +91,3 @@ | ||
this.setState({ | ||
aspectRatio: this.getCanvasAspectRatio(), | ||
canvasWidthPx: this.getCanvasWidthPx() | ||
aspectRatio: this.getCanvasAspectRatio() | ||
}, false) | ||
@@ -101,7 +103,2 @@ } | ||
getCanvasWidthPx() { | ||
const canvasDimensions = this.canvas.getBoundingClientRect() | ||
return canvasDimensions.width | ||
} | ||
setState(newState, renderTimeline = true) { | ||
@@ -147,3 +144,2 @@ this.state = { | ||
canvas: this.canvas, | ||
canvasWidthPx: this.state.canvasWidthPx, | ||
container: this.tooltipContainer, | ||
@@ -180,3 +176,2 @@ pointsContainer: this.canvasWrapper, | ||
aspectRatio: this.getCanvasAspectRatio(), | ||
canvasWidthPx: this.getCanvasWidthPx(), | ||
graphOpacity: this.data.y.map(_ => 1) | ||
@@ -312,3 +307,9 @@ } | ||
onChangeBounds = (from, to) => { | ||
this.setState(this.createState(from, to), false) | ||
const state = this.createState(from, to) | ||
const minY = state.minY | ||
const maxY = state.maxY | ||
delete state.minY | ||
delete state.maxY | ||
this.setState(state, false) | ||
this.transitionState(minY, maxY) | ||
} | ||
@@ -394,21 +395,31 @@ | ||
} | ||
const heightBefore = this.state.maxY - this.state.minY | ||
const deltaMaxY = Math.abs(maxY - this.state.maxY) / heightBefore | ||
const deltaMinY = Math.abs(minY - this.state.minY) / heightBefore | ||
const deltaY = Math.max(deltaMinY, deltaMaxY) | ||
const transitionDuration = maxTransitionDuration * Math.max(0.1, Math.min(deltaY, 0.5) * 2) | ||
this.setState({ | ||
graphOpacityFrom: this.state.graphOpacity, | ||
graphOpacityTo: graphOpacity, | ||
minYFrom: this.state.minY, | ||
maxYFrom: this.state.maxY, | ||
minYTo: minY, | ||
maxYTo: maxY, | ||
minYGlobalFrom: this.state.minYGlobal, | ||
maxYGlobalFrom: this.state.maxYGlobal, | ||
minYGlobalTo: minYGlobal, | ||
maxYGlobalTo: maxYGlobal, | ||
let transitionDuration = maxTransitionDuration | ||
if (minY !== undefined) { | ||
const heightBefore = this.state.maxY - this.state.minY | ||
const deltaMaxY = Math.abs(maxY - this.state.maxY) / heightBefore | ||
const deltaMinY = Math.abs(minY - this.state.minY) / heightBefore | ||
const deltaY = Math.max(deltaMinY, deltaMaxY) | ||
transitionDuration = maxTransitionDuration * Math.max(0.2, Math.min(deltaY, 0.5) * 2) | ||
} | ||
const state = { | ||
transitionStartedAt: Date.now(), | ||
transitionDuration | ||
}) | ||
} | ||
if (minY !== undefined) { | ||
state.minYFrom = this.state.minY | ||
state.maxYFrom = this.state.maxY | ||
state.minYTo = minY | ||
state.maxYTo = maxY | ||
} | ||
if (graphOpacity !== undefined) { | ||
state.graphOpacityFrom = this.state.graphOpacity | ||
state.graphOpacityTo = graphOpacity | ||
} | ||
if (minYGlobal !== undefined) { | ||
state.minYGlobalFrom = this.state.minYGlobal | ||
state.maxYGlobalFrom = this.state.maxYGlobal | ||
state.minYGlobalTo = minYGlobal | ||
state.maxYGlobalTo = maxYGlobal | ||
} | ||
this.setState(state) | ||
// Place in a `setState()` callback in case of React. | ||
@@ -439,9 +450,31 @@ this.transition = requestAnimationFrame(this.transitionStateTick) | ||
ratio = EASING[transitionEasing](ratio) | ||
this.setState({ | ||
graphOpacity: graphOpacityTo.map((_, i) => graphOpacityFrom[i] + (graphOpacityTo[i] - graphOpacityFrom[i]) * ratio), | ||
minY: minYFrom + (minYTo - minYFrom) * ratio, | ||
maxY: maxYFrom + (maxYTo - maxYFrom) * ratio, | ||
minYGlobal: minYGlobalFrom + (minYGlobalTo - minYGlobalFrom) * ratio, | ||
maxYGlobal: maxYGlobalFrom + (maxYGlobalTo - maxYGlobalFrom) * ratio | ||
}) | ||
const state = {} | ||
if (minYTo !== undefined) { | ||
state.minY = minYFrom + (minYTo - minYFrom) * ratio | ||
state.maxY = maxYFrom + (maxYTo - maxYFrom) * ratio | ||
if (ratio === 1) { | ||
state.minYFrom = undefined | ||
state.minYTo = undefined | ||
state.maxYFrom = undefined | ||
state.maxYTo = undefined | ||
} | ||
} | ||
if (minYGlobalTo !== undefined) { | ||
state.minYGlobal = minYGlobalFrom + (minYGlobalTo - minYGlobalFrom) * ratio | ||
state.maxYGlobal = maxYGlobalFrom + (maxYGlobalTo - maxYGlobalFrom) * ratio | ||
if (ratio === 1) { | ||
state.minYGlobalFrom = undefined | ||
state.minYGlobalTo = undefined | ||
state.maxYGlobalFrom = undefined | ||
state.maxYGlobalTo = undefined | ||
} | ||
} | ||
if (graphOpacityTo !== undefined) { | ||
state.graphOpacity = graphOpacityTo.map((_, i) => graphOpacityFrom[i] + (graphOpacityTo[i] - graphOpacityFrom[i]) * ratio) | ||
if (ratio === 1) { | ||
state.graphOpacityFrom = undefined | ||
state.graphOpacityTo = undefined | ||
} | ||
} | ||
this.setState(state) | ||
if (ratio < 1) { | ||
@@ -448,0 +481,0 @@ this.transition = requestAnimationFrame(this.transitionStateTick) |
@@ -0,1 +1,3 @@ | ||
import { setUpTouchMove } from './utility' | ||
export default class Tooltip { | ||
@@ -22,150 +24,116 @@ constructor(props) { | ||
setUpListener = () => { | ||
const { canvas, canvasWidthPx, weekdays, months } = this.props | ||
let canvasDimensions | ||
let isIndexInBounds | ||
const onTrack = (screenX) => { | ||
const { minX, maxX, xPoints, y } = this.props | ||
const xScreenRatio = (screenX - canvasDimensions.left) / canvasDimensions.width | ||
const xPoint = minX + xScreenRatio * (maxX - minX) | ||
let xHigherIndex = xPoints.findIndex(_ => _ >= xPoint) | ||
let xLowerIndex = xHigherIndex - 1 | ||
if (!isIndexInBounds(xHigherIndex)) { | ||
xHigherIndex = -1 | ||
} | ||
if (!isIndexInBounds(xLowerIndex)) { | ||
xLowerIndex = -1 | ||
} | ||
let xIndex | ||
if (xHigherIndex < 0) { | ||
if (xLowerIndex < 0) { | ||
return this.unmount() | ||
} else { | ||
xIndex = xLowerIndex | ||
} | ||
} else { | ||
if (xLowerIndex < 0) { | ||
xIndex = xHigherIndex | ||
} else { | ||
const xLower = xPoints[xLowerIndex] | ||
const xHigher = xPoints[xHigherIndex] | ||
const deltaLower = xPoint - xLower | ||
const deltaHigher = xHigher - xPoint | ||
xIndex = deltaLower > deltaHigher ? xHigherIndex : xLowerIndex | ||
} | ||
} | ||
const x = xPoints[xIndex] | ||
if (x !== this.tooltipForX) { | ||
this.tooltipForX = x | ||
if (!this.tooltip) { | ||
this.mount() | ||
} | ||
const date = new Date(x) | ||
this.tooltipDate.textContent = `${weekdays[date.getDay()]}, ${months[date.getMonth()]} ${date.getDate()}` | ||
let i = 0 | ||
for (const { isShown, points, name } of y) { | ||
if (isShown) { | ||
this.tooltipValues.childNodes[2 * i].textContent = points[xIndex] | ||
this.tooltipValues.childNodes[2 * i + 1].textContent = name | ||
i++ | ||
} | ||
} | ||
const xRatio = (x - minX) / (maxX - minX) | ||
let left = xRatio * canvasWidthPx | ||
left -= 40 | ||
const tooltipWidth = this.tooltip.getBoundingClientRect().width | ||
const overflow = 5 | ||
if (left < -1 * overflow) { | ||
left = -1 * overflow | ||
} else if (left + tooltipWidth > canvasWidthPx + overflow) { | ||
left = (canvasWidthPx + overflow) - tooltipWidth | ||
} | ||
this.tooltip.style.left = left + 'px' | ||
this.updatePoints(xIndex, xRatio) | ||
this.updateLine(x) | ||
} | ||
const { canvas } = this.props | ||
setUpTouchMove( | ||
canvas, | ||
() => {}, | ||
this.onTrack, | ||
() => this.unmount() | ||
) | ||
} | ||
onTrack = (screenX, screenY, canvasDimensions) => { | ||
const { minX, maxX, xPoints } = this.props | ||
const xScreenRatio = (screenX - canvasDimensions.left) / canvasDimensions.width | ||
const xPoint = minX + xScreenRatio * (maxX - minX) | ||
let xHigherIndex = xPoints.findIndex(_ => _ >= xPoint) | ||
let xLowerIndex = xHigherIndex - 1 | ||
if (xHigherIndex < 0 || xHigherIndex >= xPoints.length) { | ||
xHigherIndex = -1 | ||
} | ||
const onTrackStart = () => { | ||
canvasDimensions = canvas.getBoundingClientRect() | ||
isIndexInBounds = (index) => { | ||
const { xPoints } = this.props | ||
return index >= 0 && index < xPoints.length | ||
} | ||
if (xLowerIndex < 0 || xLowerIndex >= xPoints.length) { | ||
xLowerIndex = -1 | ||
} | ||
const onTouchStart = (event) => { | ||
// Ignore multitouch. | ||
if (event.touches.length > 1) { | ||
// Reset. | ||
return onTrackStop() | ||
let xIndex | ||
if (xHigherIndex < 0) { | ||
if (xLowerIndex < 0) { | ||
return this.unmount() | ||
} else { | ||
xIndex = xLowerIndex | ||
} | ||
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.left || | ||
x > canvasDimensions.left + canvasDimensions.width || | ||
y < canvasDimensions.top || | ||
y > canvasDimensions.top + canvasDimensions.height) { | ||
onTrackStop() | ||
} else { | ||
if (xLowerIndex < 0) { | ||
xIndex = xHigherIndex | ||
} else { | ||
onTrack(x, y) | ||
const xLower = xPoints[xLowerIndex] | ||
const xHigher = xPoints[xHigherIndex] | ||
const deltaLower = xPoint - xLower | ||
const deltaHigher = xHigher - xPoint | ||
xIndex = deltaLower > deltaHigher ? xHigherIndex : xLowerIndex | ||
} | ||
} | ||
function onPointerMove(event) { | ||
onTrack(event.clientX, event.clientY) | ||
const x = xPoints[xIndex] | ||
if (x !== this.tooltipForX) { | ||
this.tooltipForX = x | ||
if (!this.tooltip) { | ||
this.mount() | ||
} | ||
this.updateTooltip(x, xIndex, canvasDimensions.width) | ||
} | ||
const 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) | ||
this.unmount() | ||
} | ||
mount() { | ||
const { container } = this.props | ||
this.tooltip = this.renderTooltip() | ||
container.appendChild(this.tooltip) | ||
this.mountPoints() | ||
if (!this.isLineRendered()) { | ||
this.mountLine() | ||
} | ||
const onPointerEnter = () => { | ||
onTrackStart() | ||
canvas.addEventListener('pointermove', onPointerMove) | ||
canvas.addEventListener('pointerleave', onTrackStop) | ||
canvas.addEventListener('pointercancel', onTrackStop) | ||
} | ||
unmount() { | ||
if (!this.tooltip) { | ||
return | ||
} | ||
canvas.addEventListener('pointerenter', onPointerEnter) | ||
return () => { | ||
onTrackStop() | ||
canvas.removeEventListener(onPointerEnter) | ||
canvas.removeEventListener(onTouchStart) | ||
const { container } = this.props | ||
this.tooltipForX = undefined | ||
container.removeChild(this.tooltip) | ||
this.tooltip = undefined | ||
this.unmountPoints() | ||
if (this.isLineRendered()) { | ||
this.unmountLine() | ||
} | ||
} | ||
mount() { | ||
this.renderTooltip() | ||
this.renderPoints() | ||
if (!this.isLineRendered()) { | ||
this.renderLine() | ||
mountLine() { | ||
const { canvas } = this.props | ||
this.line = this.renderLine() | ||
canvas.insertBefore(this.line, canvas.querySelector('polyline')) | ||
} | ||
unmountLine = () => { | ||
const { canvas } = this.props | ||
canvas.removeChild(this.line) | ||
this.line = undefined | ||
} | ||
mountPoints = () => { | ||
const { pointsContainer } = this.props | ||
this.points = this.renderPoints() | ||
for (const point of this.points) { | ||
pointsContainer.appendChild(point) | ||
} | ||
} | ||
unmountPoints = () => { | ||
const { pointsContainer } = this.props | ||
for (const point of this.points) { | ||
pointsContainer.removeChild(point) | ||
} | ||
this.points = undefined | ||
} | ||
renderTooltip() { | ||
const { y, container } = this.props | ||
const { y } = this.props | ||
// Create tooltip. | ||
this.tooltip = document.createElement('div') | ||
this.tooltip.classList.add('chartogram__tooltip') | ||
container.appendChild(this.tooltip) | ||
const tooltip = document.createElement('div') | ||
tooltip.classList.add('chartogram__tooltip') | ||
// Add tooltip title. | ||
this.tooltipDate = document.createElement('h1') | ||
this.tooltipDate.classList.add('chartogram__tooltip-header') | ||
this.tooltip.appendChild(this.tooltipDate) | ||
const tooltipDate = document.createElement('h1') | ||
tooltipDate.classList.add('chartogram__tooltip-header') | ||
tooltip.appendChild(tooltipDate) | ||
// Add graph values. | ||
this.tooltipValues = document.createElement('dl') | ||
this.tooltipValues.classList.add('chartogram__tooltip-values') | ||
this.tooltip.appendChild(this.tooltipValues) | ||
const tooltipValues = document.createElement('dl') | ||
tooltipValues.classList.add('chartogram__tooltip-values') | ||
tooltip.appendChild(tooltipValues) | ||
// Add graph values. | ||
@@ -177,32 +145,19 @@ for (const { isShown, color } of y) { | ||
tooltipValue.style.color = color | ||
this.tooltipValues.appendChild(tooltipValue) | ||
tooltipValues.appendChild(tooltipValue) | ||
// Add graph name. | ||
const tooltipName = document.createElement('dd') | ||
tooltipName.style.color = color | ||
this.tooltipValues.appendChild(tooltipName) | ||
tooltipValues.appendChild(tooltipName) | ||
} | ||
} | ||
return tooltip | ||
} | ||
renderLine() { | ||
const { canvas } = this.props | ||
const xmlns = 'http://www.w3.org/2000/svg' | ||
this.line = document.createElementNS(xmlns, 'line') | ||
this.line.setAttribute('class', 'chartogram__tooltip-line') | ||
canvas.insertBefore(this.line, canvas.querySelector('polyline')) | ||
const line = document.createElementNS(xmlns, 'line') | ||
line.setAttribute('class', 'chartogram__tooltip-line') | ||
return line | ||
} | ||
unmount() { | ||
if (this.tooltip) { | ||
const { container } = this.props | ||
this.tooltipForX = undefined | ||
container.removeChild(this.tooltip) | ||
this.tooltip = undefined | ||
this.unmountPoints() | ||
if (this.isLineRendered()) { | ||
this.unmountLine() | ||
} | ||
} | ||
} | ||
isLineRendered() { | ||
@@ -213,10 +168,4 @@ const { canvas } = this.props | ||
unmountLine = () => { | ||
const { canvas } = this.props | ||
canvas.removeChild(this.line) | ||
this.line = undefined | ||
} | ||
renderPoints() { | ||
this.points = [] | ||
const points = [] | ||
const { pointsContainer, y } = this.props | ||
@@ -228,19 +177,55 @@ for (const _y of y) { | ||
point.style.color = _y.color | ||
this.points.push(point) | ||
points.push(point) | ||
pointsContainer.appendChild(point) | ||
} | ||
} | ||
return points | ||
} | ||
unmountPoints = () => { | ||
const { pointsContainer } = this.props | ||
for (const point of this.points) { | ||
pointsContainer.removeChild(point) | ||
updateTooltip(x, xIndex, canvasWidth) { | ||
const { minX, maxX } = this.props | ||
const xRatio = (x - minX) / (maxX - minX) | ||
this.updateTooltipDate(new Date(x)) | ||
this.updateTooltipValues(xIndex) | ||
this.updateTooltipPosition(xRatio, canvasWidth) | ||
this.updatePointPositions(xIndex, xRatio) | ||
this.updateLinePosition(x) | ||
} | ||
updateTooltipPosition(xRatio, canvasWidth) { | ||
const { tooltipShift, maxOverflow } = this.props | ||
let left = xRatio * canvasWidth | ||
left -= tooltipShift === undefined ? 40 : tooltipShift | ||
const tooltipWidth = this.tooltip.getBoundingClientRect().width | ||
const overflow = maxOverflow === undefined ? 5 : maxOverflow | ||
if (left < -1 * overflow) { | ||
left = -1 * overflow | ||
} else if (left + tooltipWidth > canvasWidth + overflow) { | ||
left = (canvasWidth + overflow) - tooltipWidth | ||
} | ||
this.points = undefined | ||
this.tooltip.style.left = left + 'px' | ||
} | ||
updateLine = (x) => { | ||
updateTooltipDate(date) { | ||
const { weekdays, months } = this.props | ||
const tooltipDate = this.tooltip.childNodes[0] | ||
tooltipDate.textContent = `${weekdays[date.getDay()]}, ${months[date.getMonth()]} ${date.getDate()}` | ||
} | ||
updateTooltipValues(xIndex) { | ||
const { y } = this.props | ||
const tooltipValues = this.tooltip.childNodes[1] | ||
let i = 0 | ||
for (const { isShown, points, name } of y) { | ||
if (isShown) { | ||
tooltipValues.childNodes[2 * i].textContent = points[xIndex] | ||
tooltipValues.childNodes[2 * i + 1].textContent = name | ||
i++ | ||
} | ||
} | ||
} | ||
updateLinePosition = (x) => { | ||
if (!this.isLineRendered()) { | ||
this.renderLine() | ||
this.mountLine() | ||
} | ||
@@ -254,3 +239,3 @@ const { canvasWidth, aspectRatio, fixSvgCoordinate, mapX } = this.props | ||
updatePoints = (xIndex, xRatio) => { | ||
updatePointPositions = (xIndex, xRatio) => { | ||
const { maxY, y } = this.props | ||
@@ -257,0 +242,0 @@ let i = 0 |
@@ -156,2 +156,66 @@ export function clearElement(element) { | ||
} | ||
} | ||
export function setUpTouchMove(element, _onTrackStart, _onTrack, _onTrackStop) { | ||
let elementBounds | ||
function onTrack(x, y) { | ||
_onTrack(x, y, elementBounds) | ||
} | ||
function onTrackStart() { | ||
elementBounds = element.getBoundingClientRect() | ||
_onTrackStart() | ||
} | ||
function onTouchStart(event) { | ||
// Ignore multitouch. | ||
if (event.touches.length > 1) { | ||
// Reset. | ||
return onTrackStop() | ||
} | ||
onTrackStart() | ||
element.addEventListener('touchend', onTrackStop) | ||
element.addEventListener('touchmove', onTouchMove) | ||
element.addEventListener('touchend', onTrackStop) | ||
element.addEventListener('touchcancel', onTrackStop) | ||
onTouchMove(event) | ||
} | ||
// Safari doesn't support pointer events. | ||
// https://caniuse.com/#feat=pointer | ||
element.addEventListener('touchstart', onTouchStart) | ||
function onTouchMove(event) { | ||
const x = event.changedTouches[0].clientX | ||
const y = event.changedTouches[0].clientY | ||
// Emulate 'pointerleave' behavior. | ||
if (x < elementBounds.left || | ||
x > elementBounds.left + elementBounds.width || | ||
y < elementBounds.top || | ||
y > elementBounds.top + elementBounds.height) { | ||
onTrackStop() | ||
} else { | ||
onTrack(x, y) | ||
} | ||
} | ||
function onPointerMove(event) { | ||
onTrack(event.clientX, event.clientY) | ||
} | ||
function onTrackStop() { | ||
element.removeEventListener('pointermove', onPointerMove) | ||
element.removeEventListener('pointerleave', onTrackStop) | ||
element.removeEventListener('pointercancel', onTrackStop) | ||
element.removeEventListener('touchmove', onTouchMove) | ||
element.removeEventListener('touchend', onTrackStop) | ||
element.removeEventListener('touchcancel', onTrackStop) | ||
_onTrackStop() | ||
} | ||
function onPointerEnter() { | ||
onTrackStart() | ||
element.addEventListener('pointermove', onPointerMove) | ||
element.addEventListener('pointerleave', onTrackStop) | ||
element.addEventListener('pointercancel', onTrackStop) | ||
} | ||
element.addEventListener('pointerenter', onPointerEnter) | ||
return () => { | ||
onTrackStop() | ||
element.removeEventListener(onPointerEnter) | ||
element.removeEventListener(onTouchStart) | ||
} | ||
} |
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
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
1120849
4610