@@ -53,32 +53,43 @@ function zoomIndexScale(scale, zoom, center) {
5353
5454}
5555
56-
5756function zoomTimeScale ( scale , zoom , center ) {
5857 var options = scale . options ;
59- var minDelta , maxDelta ;
60- var newDiff ;
61-
58+
59+ var range ;
60+ var min_percent ;
6261 if ( scale . isHorizontal ( ) ) {
63- newDiff = ( scale . right - scale . left ) * ( zoom - 1 ) ;
62+ range = scale . right - scale . left ;
63+ min_percent = ( center . x - scale . left ) / range ;
6464 } else {
65- newDiff = ( scale . bottom - scale . top ) * ( zoom - 1 ) ;
65+ range = scale . bottom - scale . top ;
66+ min_percent = ( center . y - scale . top ) / range ;
6667 }
6768
68- // Apply evenly for now until center is used
69- minDelta = maxDelta = newDiff / 2 ;
69+ var max_percent = 1 - min_percent ;
70+ var newDiff = range * ( zoom - 1 ) ;
71+
72+ var minDelta = newDiff * min_percent ;
73+ var maxDelta = newDiff * max_percent ;
7074
7175 options . time . min = scale . getValueForPixel ( scale . getPixelForValue ( scale . firstTick ) + minDelta ) ;
7276 options . time . max = scale . getValueForPixel ( scale . getPixelForValue ( scale . lastTick ) - maxDelta ) ;
7377}
7478
7579function zoomNumericalScale ( scale , zoom , center ) {
76- var newDiff = ( scale . max - scale . min ) * ( zoom - 1 ) ;
77- scale . options . ticks . min = scale . min + ( newDiff / 2 ) ;
78- scale . options . ticks . max = scale . max - ( newDiff / 2 ) ;
79- }
80+ var range = scale . max - scale . min ;
81+ var newDiff = range * ( zoom - 1 ) ;
82+
83+ var cursorPixel = scale . isHorizontal ( ) ? center . x : center . y ;
84+ var min_percent = ( scale . getValueForPixel ( cursorPixel ) - scale . min ) / range ;
85+ var max_percent = 1 - min_percent ;
8086
87+ var minDelta = newDiff * min_percent ;
88+ var maxDelta = newDiff * max_percent ;
8189
90+ scale . options . ticks . min = scale . min + minDelta ;
91+ scale . options . ticks . max = scale . max - maxDelta ;
92+ }
8293
8394function zoomScale ( scale , zoom , center ) {
8495 var fn = zoomFunctions [ scale . options . type ] ;
@@ -161,7 +172,7 @@ function doPan(chartInstance, deltaX, deltaY) {
161172 helpers . each ( chartInstance . scales , function ( scale , id ) {
162173 if ( scale . isHorizontal ( ) && directionEnabled ( panMode , 'x' ) && deltaX !== 0 ) {
163174 panScale ( scale , deltaX ) ;
164- } else if ( directionEnabled ( panMode , 'y' ) && deltaY !== 0 ) {
175+ } else if ( ! scale . isHorizontal ( ) && directionEnabled ( panMode , 'y' ) && deltaY !== 0 ) {
165176 panScale ( scale , deltaY ) ;
166177 }
167178 } ) ;
@@ -175,6 +186,18 @@ function positionInChartArea(chartInstance, position) {
175186 ( position . y >= chartInstance . chartArea . top && position . y <= chartInstance . chartArea . bottom ) ;
176187}
177188
189+ function getYAxis ( chartInstance ) {
190+ var scales = chartInstance . scales ;
191+
192+ for ( var scaleId in scales ) {
193+ var scale = scales [ scaleId ] ;
194+
195+ if ( ! scale . isHorizontal ( ) ) {
196+ return scale ;
197+ }
198+ }
199+ }
200+
178201// Store these for later
179202zoomNS . zoomFunctions . category = zoomIndexScale ;
180203zoomNS . zoomFunctions . time = zoomTimeScale ;
@@ -187,22 +210,103 @@ zoomNS.panFunctions.logarithmic = panNumericalScale;
187210
188211// Chartjs Zoom Plugin
189212var zoomPlugin = {
213+ afterInit : function ( chartInstance ) {
214+ helpers . each ( chartInstance . scales , function ( scale ) {
215+ scale . originalOptions = JSON . parse ( JSON . stringify ( scale . options ) ) ;
216+ } ) ;
217+
218+ chartInstance . resetZoom = function ( ) {
219+ helpers . each ( chartInstance . scales , function ( scale , id ) {
220+ var timeOptions = scale . options . time ;
221+ var tickOptions = scale . options . ticks ;
222+
223+ if ( timeOptions ) {
224+ delete timeOptions . min ;
225+ delete timeOptions . max ;
226+ }
227+
228+ if ( tickOptions ) {
229+ delete tickOptions . min ;
230+ delete tickOptions . max ;
231+ }
232+
233+ scale . options = helpers . configMerge ( scale . options , scale . originalOptions ) ;
234+ } ) ;
235+
236+ helpers . each ( chartInstance . data . datasets , function ( dataset , id ) {
237+ dataset . _meta = null ;
238+ } ) ;
239+
240+ chartInstance . update ( ) ;
241+ } ;
242+
243+ } ,
190244 beforeInit : function ( chartInstance ) {
191245 var node = chartInstance . chart . ctx . canvas ;
192246 var options = chartInstance . options ;
193247 var panThreshold = helpers . getValueOrDefault ( options . pan ? options . pan . threshold : undefined , zoomNS . defaults . pan . threshold ) ;
194248
195- var wheelHandler = function ( e ) {
196- e . preventDefault ( ) ;
197- if ( e . deltaY < 0 ) {
198- doZoom ( chartInstance , 1.1 ) ;
199- } else {
200- doZoom ( chartInstance , 0.909 ) ;
201- }
202- } ;
203- chartInstance . _wheelHandler = wheelHandler ;
204-
205- node . addEventListener ( 'wheel' , wheelHandler ) ;
249+ if ( options . zoom . drag ) {
250+ // Only want to zoom horizontal axis
251+ options . zoom . mode = 'x' ;
252+
253+ node . addEventListener ( 'mousedown' , function ( event ) {
254+ chartInstance . _dragZoomStart = event ;
255+ } ) ;
256+
257+ node . addEventListener ( 'mousemove' , function ( event ) {
258+ if ( chartInstance . _dragZoomStart ) {
259+ chartInstance . _dragZoomEnd = event ;
260+ chartInstance . update ( 0 ) ;
261+ }
262+
263+ chartInstance . update ( 0 ) ;
264+ } ) ;
265+
266+ node . addEventListener ( 'mouseup' , function ( event ) {
267+ if ( chartInstance . _dragZoomStart ) {
268+ var chartArea = chartInstance . chartArea ;
269+ var yAxis = getYAxis ( chartInstance ) ;
270+ var beginPoint = chartInstance . _dragZoomStart ;
271+ var startX = Math . min ( beginPoint . x , event . x ) ;
272+ var endX = Math . max ( beginPoint . x , event . x ) ;
273+ var dragDistance = endX - startX ;
274+ var chartDistance = chartArea . right - chartArea . left ;
275+ var zoom = 1 + ( ( chartDistance - dragDistance ) / chartDistance ) ;
276+
277+ if ( dragDistance > 0 ) {
278+ doZoom ( chartInstance , zoom , {
279+ x : ( dragDistance / 2 ) + startX ,
280+ y : ( yAxis . bottom - yAxis . top ) / 2 ,
281+ } ) ;
282+ }
283+
284+ chartInstance . _dragZoomStart = null ;
285+ chartInstance . _dragZoomEnd = null ;
286+ }
287+ } ) ;
288+ }
289+ else {
290+ var wheelHandler = function ( e ) {
291+ var rect = e . target . getBoundingClientRect ( ) ;
292+ var offsetX = e . clientX - rect . left ;
293+ var offsetY = e . clientY - rect . top ;
294+
295+ var center = {
296+ x : offsetX ,
297+ y : offsetY
298+ } ;
299+
300+ if ( e . deltaY < 0 ) {
301+ doZoom ( chartInstance , 1.1 , center ) ;
302+ } else {
303+ doZoom ( chartInstance , 0.909 , center ) ;
304+ }
305+ } ;
306+ chartInstance . _wheelHandler = wheelHandler ;
307+
308+ node . addEventListener ( 'wheel' , wheelHandler ) ;
309+ }
206310
207311 if ( Hammer ) {
208312 var mc = new Hammer . Manager ( node ) ;
@@ -261,6 +365,21 @@ var zoomPlugin = {
261365 var chartArea = chartInstance . chartArea ;
262366 ctx . save ( ) ;
263367 ctx . beginPath ( ) ;
368+
369+ if ( chartInstance . _dragZoomEnd ) {
370+ var yAxis = getYAxis ( chartInstance ) ;
371+ var beginPoint = chartInstance . _dragZoomStart ;
372+ var endPoint = chartInstance . _dragZoomEnd ;
373+ var startX = Math . min ( beginPoint . x , endPoint . x ) ;
374+ var endX = Math . max ( beginPoint . x , endPoint . x ) ;
375+ var rectWidth = endX - startX ;
376+
377+
378+ ctx . fillStyle = 'rgba(225,225,225,0.3)' ;
379+ ctx . lineWidth = 5 ;
380+ ctx . fillRect ( startX , yAxis . top , rectWidth , yAxis . bottom - yAxis . top ) ;
381+ }
382+
264383 ctx . rect ( chartArea . left , chartArea . top , chartArea . right - chartArea . left , chartArea . bottom - chartArea . top ) ;
265384 ctx . clip ( ) ;
266385 } ,
@@ -271,6 +390,7 @@ var zoomPlugin = {
271390
272391 destroy : function ( chartInstance ) {
273392 var node = chartInstance . chart . ctx . canvas ;
393+ node . removeEventListener ( 'wheel' , chartInstance . _wheelHandler ) ;
274394
275395 var mc = chartInstance . _mc ;
276396 if ( mc ) {
0 commit comments