From 4db7b649f73c6574a867c18d2b7ba04269c389cb Mon Sep 17 00:00:00 2001 From: Janne Niutanen Date: Tue, 18 Oct 2016 09:17:20 +0300 Subject: [PATCH] Fix drag zoom inaccuracy by offsetting X coordinates --- Chart.Zoom.js | 10 ++++++---- Chart.Zoom.min.js | 2 +- src/chart.zoom.js | 10 ++++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Chart.Zoom.js b/Chart.Zoom.js index 33d5c767..5c045aaa 100644 --- a/Chart.Zoom.js +++ b/Chart.Zoom.js @@ -324,8 +324,9 @@ var zoomPlugin = { var chartArea = chartInstance.chartArea; var yAxis = getYAxis(chartInstance); var beginPoint = chartInstance._dragZoomStart; - var startX = Math.min(beginPoint.x, event.x) ; - var endX = Math.max(beginPoint.x, event.x); + var offsetX = beginPoint.target.getBoundingClientRect().left; + var startX = Math.min(beginPoint.x, event.x) - offsetX; + var endX = Math.max(beginPoint.x, event.x) - offsetX; var dragDistance = endX - startX; var chartDistance = chartArea.right - chartArea.left; var zoom = 1 + ((chartDistance - dragDistance) / chartDistance ); @@ -429,8 +430,9 @@ var zoomPlugin = { var yAxis = getYAxis(chartInstance); var beginPoint = chartInstance._dragZoomStart; var endPoint = chartInstance._dragZoomEnd; - var startX = Math.min(beginPoint.x, endPoint.x); - var endX = Math.max(beginPoint.x, endPoint.x); + var offsetX = beginPoint.target.getBoundingClientRect().left; + var startX = Math.min(beginPoint.x, endPoint.x) - offsetX; + var endX = Math.max(beginPoint.x, endPoint.x) - offsetX; var rectWidth = endX - startX; diff --git a/Chart.Zoom.min.js b/Chart.Zoom.min.js index 3a36bd5a..c4ed8f27 100644 --- a/Chart.Zoom.min.js +++ b/Chart.Zoom.min.js @@ -7,4 +7,4 @@ * Released under the MIT license * https://github.com/chartjs/Chart.Zoom.js/blob/master/LICENSE.md */ -!function t(e,n,a){function o(r,l){if(!n[r]){if(!e[r]){var u="function"==typeof require&&require;if(!l&&u)return u(r,!0);if(i)return i(r,!0);var m=new Error("Cannot find module '"+r+"'");throw m.code="MODULE_NOT_FOUND",m}var s=n[r]={exports:{}};e[r][0].call(s.exports,function(t){var n=e[r][1][t];return o(n?n:t)},s,s.exports,t,e,n,a)}return n[r].exports}for(var i="function"==typeof require&&require,r=0;r1?g.zoomCumulativeDelta+1:g.zoomCumulativeDelta-1,Math.abs(g.zoomCumulativeDelta)>u&&(g.zoomCumulativeDelta<0?(s<=m?i<=0?l=Math.min(r,l+1):i=Math.max(0,i-1):s>m&&(l>=r?i=Math.max(0,i-1):l=Math.min(r,l+1)),g.zoomCumulativeDelta=0):g.zoomCumulativeDelta>0&&(s<=m?i=im&&(l=l>i?l=Math.max(i,l-1):l),g.zoomCumulativeDelta=0),t.options.ticks.min=o[i],t.options.ticks.max=o[l])}function i(t,e,n){var a,o,i=t.options;t.isHorizontal()?(a=t.right-t.left,o=(n.x-t.left)/a):(a=t.bottom-t.top,o=(n.y-t.top)/a);var r=1-o,l=a*(e-1),u=l*o,m=l*r;i.time.min=t.getValueForPixel(t.getPixelForValue(t.firstTick)+u),i.time.max=t.getValueForPixel(t.getPixelForValue(t.lastTick)-m)}function r(t,e,n){var a=t.max-t.min,o=a*(e-1),i=t.isHorizontal()?n.x:n.y,r=(t.getValueForPixel(i)-t.min)/a,l=1-r,u=o*r,m=o*l;t.options.ticks.min=t.min+u,t.options.ticks.max=t.max-m}function l(t,e,n,a){var o=z[t.options.type];o&&o(t,e,n,a)}function u(t,e,n){var o=t.chartArea;n||(n={x:(o.left+o.right)/2,y:(o.top+o.bottom)/2});var i=t.options.zoom;if(i&&x.getValueOrDefault(i.enabled,F.zoom.enabled)){var r=x.getValueOrDefault(t.options.zoom.mode,F.zoom.mode);i.sensitivity=x.getValueOrDefault(t.options.zoom.sensitivity,F.zoom.sensitivity),x.each(t.scales,function(t,o){t.isHorizontal()&&a(r,"x")?l(t,e,n,i):!t.isHorizontal()&&a(r,"y")&&l(t,e,n,i)}),t.update(0)}}function m(t,e,n){var a,o=t.chart.data.labels,i=o.length-1,r=Math.max(t.ticks.length-(t.options.gridLines.offsetGridLines?0:1),1),l=n.speed,u=t.minIndex,m=Math.round(t.width/(r*l));g.panCumulativeDelta+=e,u=g.panCumulativeDelta>m?Math.max(0,u-1):g.panCumulativeDelta<-m?Math.min(i-r+1,u+1):u,g.panCumulativeDelta=u!==t.minIndex?0:g.panCumulativeDelta,a=Math.min(i,u+r-1),t.options.ticks.min=o[u],t.options.ticks.max=o[a]}function s(t,e){var n=t.options;n.time.min=t.getValueForPixel(t.getPixelForValue(t.firstTick)-e),n.time.max=t.getValueForPixel(t.getPixelForValue(t.lastTick)-e)}function c(t,e){var n=t.options.ticks,a=t.start,o=t.end;n.reverse?(n.max=t.getValueForPixel(t.getPixelForValue(a)-e),n.min=t.getValueForPixel(t.getPixelForValue(o)-e)):(n.min=t.getValueForPixel(t.getPixelForValue(a)-e),n.max=t.getValueForPixel(t.getPixelForValue(o)-e))}function p(t,e,n){var a=D[t.options.type];a&&a(t,e,n)}function d(t,e,n){var o=t.options.pan;if(o&&x.getValueOrDefault(o.enabled,F.pan.enabled)){var i=x.getValueOrDefault(t.options.pan.mode,F.pan.mode);o.speed=x.getValueOrDefault(t.options.pan.speed,F.pan.speed),x.each(t.scales,function(t,r){t.isHorizontal()&&a(i,"x")&&0!==e?p(t,e,o):!t.isHorizontal()&&a(i,"y")&&0!==n&&p(t,n,o)}),t.update(0)}}function f(t){var e=t.scales;for(var n in e){var a=e[n];if(!a.isHorizontal())return a}}var v=t("hammerjs");v="function"==typeof v?v:window.Hammer;var h=t("chart.js");h="function"==typeof h?h:window.Chart;var x=h.helpers,g=h.Zoom=h.Zoom||{},z=g.zoomFunctions=g.zoomFunctions||{},D=g.panFunctions=g.panFunctions||{},F=g.defaults={pan:{enabled:!0,mode:"xy",speed:20,threshold:10},zoom:{enabled:!0,mode:"xy",sensitivity:3}};g.zoomFunctions.category=o,g.zoomFunctions.time=i,g.zoomFunctions.linear=r,g.zoomFunctions.logarithmic=r,g.panFunctions.category=m,g.panFunctions.time=s,g.panFunctions.linear=c,g.panFunctions.logarithmic=c,g.panCumulativeDelta=0,g.zoomCumulativeDelta=0;var y={afterInit:function(t){x.each(t.scales,function(t){t.originalOptions=JSON.parse(JSON.stringify(t.options))}),t.resetZoom=function(){x.each(t.scales,function(t,e){var n=t.options.time,a=t.options.ticks;n&&(delete n.min,delete n.max),a&&(delete a.min,delete a.max),t.options=x.configMerge(t.options,t.originalOptions)}),x.each(t.data.datasets,function(t,e){t._meta=null}),t.update()}},beforeInit:function(t){var e=t.chart.ctx.canvas,n=t.options,a=x.getValueOrDefault(n.pan?n.pan.threshold:void 0,g.defaults.pan.threshold);if(n.zoom&&n.zoom.drag)n.zoom.mode="x",e.addEventListener("mousedown",function(e){t._dragZoomStart=e}),e.addEventListener("mousemove",function(e){t._dragZoomStart&&(t._dragZoomEnd=e,t.update(0)),t.update(0)}),e.addEventListener("mouseup",function(e){if(t._dragZoomStart){var n=t.chartArea,a=f(t),o=t._dragZoomStart,i=Math.min(o.x,e.x),r=Math.max(o.x,e.x),l=r-i,m=n.right-n.left,s=1+(m-l)/m;l>0&&u(t,s,{x:l/2+i,y:(a.bottom-a.top)/2}),t._dragZoomStart=null,t._dragZoomEnd=null}});else{var o=function(e){var n=e.target.getBoundingClientRect(),a=e.clientX-n.left,o=e.clientY-n.top,i={x:a,y:o};e.deltaY<0?u(t,1.1,i):u(t,.909,i),e.preventDefault()};t._wheelHandler=o,e.addEventListener("wheel",o)}if(v){var i=new v.Manager(e);i.add(new v.Pinch),i.add(new v.Pan({threshold:a}));var r,l=function(e){var n=1/r*e.scale;u(t,n,e.center),r=e.scale};i.on("pinchstart",function(t){r=1}),i.on("pinch",l),i.on("pinchend",function(t){l(t),r=null,g.zoomCumulativeDelta=0});var m=null,s=null,c=function(e){if(null!==m&&null!==s){var n=e.deltaX-m,a=e.deltaY-s;m=e.deltaX,s=e.deltaY,d(t,n,a)}};i.on("panstart",function(t){m=0,s=0,c(t)}),i.on("panmove",c),i.on("panend",function(t){m=null,s=null,g.panCumulativeDelta=0}),t._mc=i}},beforeDatasetsDraw:function(t){var e=t.chart.ctx,n=t.chartArea;if(e.save(),e.beginPath(),t._dragZoomEnd){var a=f(t),o=t._dragZoomStart,i=t._dragZoomEnd,r=Math.min(o.x,i.x),l=Math.max(o.x,i.x),u=l-r;e.fillStyle="rgba(225,225,225,0.3)",e.lineWidth=5,e.fillRect(r,a.top,u,a.bottom-a.top)}e.rect(n.left,n.top,n.right-n.left,n.bottom-n.top),e.clip()},afterDatasetsDraw:function(t){t.chart.ctx.restore()},destroy:function(t){var e=t.chart.ctx.canvas;e.removeEventListener("wheel",t._wheelHandler);var n=t._mc;n&&(n.remove("pinchstart"),n.remove("pinch"),n.remove("pinchend"),n.remove("panstart"),n.remove("pan"),n.remove("panend"))}};h.pluginService.register(y)},{"chart.js":1,hammerjs:1}]},{},[2]); \ No newline at end of file +!function t(e,n,a){function o(r,l){if(!n[r]){if(!e[r]){var u="function"==typeof require&&require;if(!l&&u)return u(r,!0);if(i)return i(r,!0);var m=new Error("Cannot find module '"+r+"'");throw m.code="MODULE_NOT_FOUND",m}var s=n[r]={exports:{}};e[r][0].call(s.exports,function(t){var n=e[r][1][t];return o(n?n:t)},s,s.exports,t,e,n,a)}return n[r].exports}for(var i="function"==typeof require&&require,r=0;r1?x.zoomCumulativeDelta+1:x.zoomCumulativeDelta-1,Math.abs(x.zoomCumulativeDelta)>u&&(x.zoomCumulativeDelta<0?(s<=m?i<=0?l=Math.min(r,l+1):i=Math.max(0,i-1):s>m&&(l>=r?i=Math.max(0,i-1):l=Math.min(r,l+1)),x.zoomCumulativeDelta=0):x.zoomCumulativeDelta>0&&(s<=m?i=im&&(l=l>i?l=Math.max(i,l-1):l),x.zoomCumulativeDelta=0),t.options.ticks.min=o[i],t.options.ticks.max=o[l])}function i(t,e,n){var a,o,i=t.options;t.isHorizontal()?(a=t.right-t.left,o=(n.x-t.left)/a):(a=t.bottom-t.top,o=(n.y-t.top)/a);var r=1-o,l=a*(e-1),u=l*o,m=l*r;i.time.min=t.getValueForPixel(t.getPixelForValue(t.firstTick)+u),i.time.max=t.getValueForPixel(t.getPixelForValue(t.lastTick)-m)}function r(t,e,n){var a=t.max-t.min,o=a*(e-1),i=t.isHorizontal()?n.x:n.y,r=(t.getValueForPixel(i)-t.min)/a,l=1-r,u=o*r,m=o*l;t.options.ticks.min=t.min+u,t.options.ticks.max=t.max-m}function l(t,e,n,a){var o=z[t.options.type];o&&o(t,e,n,a)}function u(t,e,n){var o=t.chartArea;n||(n={x:(o.left+o.right)/2,y:(o.top+o.bottom)/2});var i=t.options.zoom;if(i&&g.getValueOrDefault(i.enabled,F.zoom.enabled)){var r=g.getValueOrDefault(t.options.zoom.mode,F.zoom.mode);i.sensitivity=g.getValueOrDefault(t.options.zoom.sensitivity,F.zoom.sensitivity),g.each(t.scales,function(t,o){t.isHorizontal()&&a(r,"x")?l(t,e,n,i):!t.isHorizontal()&&a(r,"y")&&l(t,e,n,i)}),t.update(0)}}function m(t,e,n){var a,o=t.chart.data.labels,i=o.length-1,r=Math.max(t.ticks.length-(t.options.gridLines.offsetGridLines?0:1),1),l=n.speed,u=t.minIndex,m=Math.round(t.width/(r*l));x.panCumulativeDelta+=e,u=x.panCumulativeDelta>m?Math.max(0,u-1):x.panCumulativeDelta<-m?Math.min(i-r+1,u+1):u,x.panCumulativeDelta=u!==t.minIndex?0:x.panCumulativeDelta,a=Math.min(i,u+r-1),t.options.ticks.min=o[u],t.options.ticks.max=o[a]}function s(t,e){var n=t.options;n.time.min=t.getValueForPixel(t.getPixelForValue(t.firstTick)-e),n.time.max=t.getValueForPixel(t.getPixelForValue(t.lastTick)-e)}function c(t,e){var n=t.options.ticks,a=t.start,o=t.end;n.reverse?(n.max=t.getValueForPixel(t.getPixelForValue(a)-e),n.min=t.getValueForPixel(t.getPixelForValue(o)-e)):(n.min=t.getValueForPixel(t.getPixelForValue(a)-e),n.max=t.getValueForPixel(t.getPixelForValue(o)-e))}function d(t,e,n){var a=D[t.options.type];a&&a(t,e,n)}function p(t,e,n){var o=t.options.pan;if(o&&g.getValueOrDefault(o.enabled,F.pan.enabled)){var i=g.getValueOrDefault(t.options.pan.mode,F.pan.mode);o.speed=g.getValueOrDefault(t.options.pan.speed,F.pan.speed),g.each(t.scales,function(t,r){t.isHorizontal()&&a(i,"x")&&0!==e?d(t,e,o):!t.isHorizontal()&&a(i,"y")&&0!==n&&d(t,n,o)}),t.update(0)}}function f(t){var e=t.scales;for(var n in e){var a=e[n];if(!a.isHorizontal())return a}}var v=t("hammerjs");v="function"==typeof v?v:window.Hammer;var h=t("chart.js");h="function"==typeof h?h:window.Chart;var g=h.helpers,x=h.Zoom=h.Zoom||{},z=x.zoomFunctions=x.zoomFunctions||{},D=x.panFunctions=x.panFunctions||{},F=x.defaults={pan:{enabled:!0,mode:"xy",speed:20,threshold:10},zoom:{enabled:!0,mode:"xy",sensitivity:3}};x.zoomFunctions.category=o,x.zoomFunctions.time=i,x.zoomFunctions.linear=r,x.zoomFunctions.logarithmic=r,x.panFunctions.category=m,x.panFunctions.time=s,x.panFunctions.linear=c,x.panFunctions.logarithmic=c,x.panCumulativeDelta=0,x.zoomCumulativeDelta=0;var y={afterInit:function(t){g.each(t.scales,function(t){t.originalOptions=JSON.parse(JSON.stringify(t.options))}),t.resetZoom=function(){g.each(t.scales,function(t,e){var n=t.options.time,a=t.options.ticks;n&&(delete n.min,delete n.max),a&&(delete a.min,delete a.max),t.options=g.configMerge(t.options,t.originalOptions)}),g.each(t.data.datasets,function(t,e){t._meta=null}),t.update()}},beforeInit:function(t){var e=t.chart.ctx.canvas,n=t.options,a=g.getValueOrDefault(n.pan?n.pan.threshold:void 0,x.defaults.pan.threshold);if(n.zoom&&n.zoom.drag)n.zoom.mode="x",e.addEventListener("mousedown",function(e){t._dragZoomStart=e}),e.addEventListener("mousemove",function(e){t._dragZoomStart&&(t._dragZoomEnd=e,t.update(0)),t.update(0)}),e.addEventListener("mouseup",function(e){if(t._dragZoomStart){var n=t.chartArea,a=f(t),o=t._dragZoomStart,i=o.target.getBoundingClientRect().left,r=Math.min(o.x,e.x)-i,l=Math.max(o.x,e.x)-i,m=l-r,s=n.right-n.left,c=1+(s-m)/s;m>0&&u(t,c,{x:m/2+r,y:(a.bottom-a.top)/2}),t._dragZoomStart=null,t._dragZoomEnd=null}});else{var o=function(e){var n=e.target.getBoundingClientRect(),a=e.clientX-n.left,o=e.clientY-n.top,i={x:a,y:o};e.deltaY<0?u(t,1.1,i):u(t,.909,i),e.preventDefault()};t._wheelHandler=o,e.addEventListener("wheel",o)}if(v){var i=new v.Manager(e);i.add(new v.Pinch),i.add(new v.Pan({threshold:a}));var r,l=function(e){var n=1/r*e.scale;u(t,n,e.center),r=e.scale};i.on("pinchstart",function(t){r=1}),i.on("pinch",l),i.on("pinchend",function(t){l(t),r=null,x.zoomCumulativeDelta=0});var m=null,s=null,c=function(e){if(null!==m&&null!==s){var n=e.deltaX-m,a=e.deltaY-s;m=e.deltaX,s=e.deltaY,p(t,n,a)}};i.on("panstart",function(t){m=0,s=0,c(t)}),i.on("panmove",c),i.on("panend",function(t){m=null,s=null,x.panCumulativeDelta=0}),t._mc=i}},beforeDatasetsDraw:function(t){var e=t.chart.ctx,n=t.chartArea;if(e.save(),e.beginPath(),t._dragZoomEnd){var a=f(t),o=t._dragZoomStart,i=t._dragZoomEnd,r=o.target.getBoundingClientRect().left,l=Math.min(o.x,i.x)-r,u=Math.max(o.x,i.x)-r,m=u-l;e.fillStyle="rgba(225,225,225,0.3)",e.lineWidth=5,e.fillRect(l,a.top,m,a.bottom-a.top)}e.rect(n.left,n.top,n.right-n.left,n.bottom-n.top),e.clip()},afterDatasetsDraw:function(t){t.chart.ctx.restore()},destroy:function(t){var e=t.chart.ctx.canvas;e.removeEventListener("wheel",t._wheelHandler);var n=t._mc;n&&(n.remove("pinchstart"),n.remove("pinch"),n.remove("pinchend"),n.remove("panstart"),n.remove("pan"),n.remove("panend"))}};h.pluginService.register(y)},{"chart.js":1,hammerjs:1}]},{},[2]); \ No newline at end of file diff --git a/src/chart.zoom.js b/src/chart.zoom.js index 3a8c9f5a..bad7b28a 100644 --- a/src/chart.zoom.js +++ b/src/chart.zoom.js @@ -312,8 +312,9 @@ var zoomPlugin = { var chartArea = chartInstance.chartArea; var yAxis = getYAxis(chartInstance); var beginPoint = chartInstance._dragZoomStart; - var startX = Math.min(beginPoint.x, event.x) ; - var endX = Math.max(beginPoint.x, event.x); + var offsetX = beginPoint.target.getBoundingClientRect().left; + var startX = Math.min(beginPoint.x, event.x) - offsetX; + var endX = Math.max(beginPoint.x, event.x) - offsetX; var dragDistance = endX - startX; var chartDistance = chartArea.right - chartArea.left; var zoom = 1 + ((chartDistance - dragDistance) / chartDistance ); @@ -417,8 +418,9 @@ var zoomPlugin = { var yAxis = getYAxis(chartInstance); var beginPoint = chartInstance._dragZoomStart; var endPoint = chartInstance._dragZoomEnd; - var startX = Math.min(beginPoint.x, endPoint.x); - var endX = Math.max(beginPoint.x, endPoint.x); + var offsetX = beginPoint.target.getBoundingClientRect().left; + var startX = Math.min(beginPoint.x, endPoint.x) - offsetX; + var endX = Math.max(beginPoint.x, endPoint.x) - offsetX; var rectWidth = endX - startX;