Skip to content

Commit 7ea251b

Browse files
committed
Merge branch 'pml984-add-drag-zoom'
2 parents 2c07f9f + 24cd325 commit 7ea251b

File tree

4 files changed

+271
-49
lines changed

4 files changed

+271
-49
lines changed

Chart.Zoom.js

Lines changed: 144 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -53,32 +53,43 @@ function zoomIndexScale(scale, zoom, center) {
5353

5454
}
5555

56-
5756
function 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

7579
function 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

8394
function 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
179202
zoomNS.zoomFunctions.category = zoomIndexScale;
180203
zoomNS.zoomFunctions.time = zoomTimeScale;
@@ -187,22 +210,103 @@ zoomNS.panFunctions.logarithmic = panNumericalScale;
187210

188211
// Chartjs Zoom Plugin
189212
var 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) {

Chart.Zoom.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/zoom-time.html

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<head>
55
<title>Line Chart</title>
66
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
7-
<script src="../node_modules/chart.js/dist/Chart.min.js"></script>
7+
<script src="../node_modules/chart.js/dist/Chart.js"></script>
88
<script src="../node_modules/hammerjs/hammer.min.js"></script>
99
<script src="../Chart.Zoom.js"></script>
1010
<style>
@@ -18,6 +18,7 @@
1818

1919
<body>
2020
<div style="width:75%;">
21+
<button onclick="resetZoom()">Reset Zoom</button>
2122
<canvas id="canvas"></canvas>
2223
</div>
2324
<script>
@@ -46,6 +47,10 @@
4647
function newTimestamp(days) {
4748
return moment().add(days, 'd').unix();
4849
}
50+
51+
function resetZoom() {
52+
window.myLine.resetZoom()
53+
}
4954

5055
var config = {
5156
type: 'line',
@@ -106,13 +111,10 @@
106111
}
107112
}]
108113
},
109-
pan: {
110-
enabled: true,
111-
mode: 'xy'
112-
},
113114
zoom: {
114115
enabled: true,
115-
mode: 'xy',
116+
drag: true,
117+
mode: 'x',
116118
limits: {
117119
max: 10,
118120
min: 0.5

0 commit comments

Comments
 (0)