Skip to content

Commit

Permalink
Merge branch 'pml984-add-drag-zoom'
Browse files Browse the repository at this point in the history
  • Loading branch information
etimberg committed Aug 9, 2016
2 parents 2c07f9f + 24cd325 commit 7ea251b
Show file tree
Hide file tree
Showing 4 changed files with 271 additions and 49 deletions.
168 changes: 144 additions & 24 deletions Chart.Zoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,32 +53,43 @@ function zoomIndexScale(scale, zoom, center) {

}


function zoomTimeScale(scale, zoom, center) {
var options = scale.options;
var minDelta, maxDelta;
var newDiff;


var range;
var min_percent;
if (scale.isHorizontal()) {
newDiff = (scale.right - scale.left) * (zoom - 1);
range = scale.right - scale.left;
min_percent = (center.x - scale.left) / range;
} else {
newDiff = (scale.bottom - scale.top) * (zoom - 1);
range = scale.bottom - scale.top;
min_percent = (center.y - scale.top) / range;
}

// Apply evenly for now until center is used
minDelta = maxDelta = newDiff / 2;
var max_percent = 1 - min_percent;
var newDiff = range * (zoom - 1);

var minDelta = newDiff * min_percent;
var maxDelta = newDiff * max_percent;

options.time.min = scale.getValueForPixel(scale.getPixelForValue(scale.firstTick) + minDelta);
options.time.max = scale.getValueForPixel(scale.getPixelForValue(scale.lastTick) - maxDelta);
}

function zoomNumericalScale(scale, zoom, center) {
var newDiff = (scale.max - scale.min) * (zoom - 1);
scale.options.ticks.min = scale.min + (newDiff / 2);
scale.options.ticks.max = scale.max - (newDiff / 2);
}
var range = scale.max - scale.min;
var newDiff = range * (zoom - 1);

var cursorPixel = scale.isHorizontal() ? center.x : center.y;
var min_percent = (scale.getValueForPixel(cursorPixel) - scale.min) / range;
var max_percent = 1 - min_percent;

var minDelta = newDiff * min_percent;
var maxDelta = newDiff * max_percent;

scale.options.ticks.min = scale.min + minDelta;
scale.options.ticks.max = scale.max - maxDelta;
}

function zoomScale(scale, zoom, center) {
var fn = zoomFunctions[scale.options.type];
Expand Down Expand Up @@ -161,7 +172,7 @@ function doPan(chartInstance, deltaX, deltaY) {
helpers.each(chartInstance.scales, function(scale, id) {
if (scale.isHorizontal() && directionEnabled(panMode, 'x') && deltaX !== 0) {
panScale(scale, deltaX);
} else if (directionEnabled(panMode, 'y') && deltaY !== 0) {
} else if (!scale.isHorizontal() && directionEnabled(panMode, 'y') && deltaY !== 0) {
panScale(scale, deltaY);
}
});
Expand All @@ -175,6 +186,18 @@ function positionInChartArea(chartInstance, position) {
(position.y >= chartInstance.chartArea.top && position.y <= chartInstance.chartArea.bottom);
}

function getYAxis(chartInstance) {
var scales = chartInstance.scales;

for (var scaleId in scales) {
var scale = scales[scaleId];

if (!scale.isHorizontal()) {
return scale;
}
}
}

// Store these for later
zoomNS.zoomFunctions.category = zoomIndexScale;
zoomNS.zoomFunctions.time = zoomTimeScale;
Expand All @@ -187,22 +210,103 @@ zoomNS.panFunctions.logarithmic = panNumericalScale;

// Chartjs Zoom Plugin
var zoomPlugin = {
afterInit: function(chartInstance) {
helpers.each(chartInstance.scales, function(scale) {
scale.originalOptions = JSON.parse(JSON.stringify(scale.options));
});

chartInstance.resetZoom = function() {
helpers.each(chartInstance.scales, function(scale, id) {
var timeOptions = scale.options.time;
var tickOptions = scale.options.ticks;

if (timeOptions) {
delete timeOptions.min;
delete timeOptions.max;
}

if (tickOptions) {
delete tickOptions.min;
delete tickOptions.max;
}

scale.options = helpers.configMerge(scale.options, scale.originalOptions);
});

helpers.each(chartInstance.data.datasets, function(dataset, id) {
dataset._meta = null;
});

chartInstance.update();
};

},
beforeInit: function(chartInstance) {
var node = chartInstance.chart.ctx.canvas;
var options = chartInstance.options;
var panThreshold = helpers.getValueOrDefault(options.pan ? options.pan.threshold : undefined, zoomNS.defaults.pan.threshold);

var wheelHandler = function(e) {
e.preventDefault();
if (e.deltaY < 0) {
doZoom(chartInstance, 1.1);
} else {
doZoom(chartInstance, 0.909);
}
};
chartInstance._wheelHandler = wheelHandler;

node.addEventListener('wheel', wheelHandler);
if (options.zoom.drag) {
// Only want to zoom horizontal axis
options.zoom.mode = 'x';

node.addEventListener('mousedown', function(event){
chartInstance._dragZoomStart = event;
});

node.addEventListener('mousemove', function(event){
if (chartInstance._dragZoomStart) {
chartInstance._dragZoomEnd = event;
chartInstance.update(0);
}

chartInstance.update(0);
});

node.addEventListener('mouseup', function(event){
if (chartInstance._dragZoomStart) {
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 dragDistance = endX - startX;
var chartDistance = chartArea.right - chartArea.left;
var zoom = 1 + ((chartDistance - dragDistance) / chartDistance );

if (dragDistance > 0) {
doZoom(chartInstance, zoom, {
x: (dragDistance / 2) + startX,
y: (yAxis.bottom - yAxis.top) / 2,
});
}

chartInstance._dragZoomStart = null;
chartInstance._dragZoomEnd = null;
}
});
}
else {
var wheelHandler = function(e) {
var rect = e.target.getBoundingClientRect();
var offsetX = e.clientX - rect.left;
var offsetY = e.clientY - rect.top;

var center = {
x : offsetX,
y : offsetY
};

if (e.deltaY < 0) {
doZoom(chartInstance, 1.1, center);
} else {
doZoom(chartInstance, 0.909, center);
}
};
chartInstance._wheelHandler = wheelHandler;

node.addEventListener('wheel', wheelHandler);
}

if (Hammer) {
var mc = new Hammer.Manager(node);
Expand Down Expand Up @@ -261,6 +365,21 @@ var zoomPlugin = {
var chartArea = chartInstance.chartArea;
ctx.save();
ctx.beginPath();

if (chartInstance._dragZoomEnd) {
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 rectWidth = endX - startX;


ctx.fillStyle = 'rgba(225,225,225,0.3)';
ctx.lineWidth = 5;
ctx.fillRect(startX, yAxis.top, rectWidth, yAxis.bottom - yAxis.top);
}

ctx.rect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
ctx.clip();
},
Expand All @@ -271,6 +390,7 @@ var zoomPlugin = {

destroy: function(chartInstance) {
var node = chartInstance.chart.ctx.canvas;
node.removeEventListener('wheel', chartInstance._wheelHandler);

var mc = chartInstance._mc;
if (mc) {
Expand Down
2 changes: 1 addition & 1 deletion Chart.Zoom.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 8 additions & 6 deletions samples/zoom-time.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<head>
<title>Line Chart</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.min.js"></script>
<script src="../node_modules/chart.js/dist/Chart.min.js"></script>
<script src="../node_modules/chart.js/dist/Chart.js"></script>
<script src="../node_modules/hammerjs/hammer.min.js"></script>
<script src="../Chart.Zoom.js"></script>
<style>
Expand All @@ -18,6 +18,7 @@

<body>
<div style="width:75%;">
<button onclick="resetZoom()">Reset Zoom</button>
<canvas id="canvas"></canvas>
</div>
<script>
Expand Down Expand Up @@ -46,6 +47,10 @@
function newTimestamp(days) {
return moment().add(days, 'd').unix();
}

function resetZoom() {
window.myLine.resetZoom()
}

var config = {
type: 'line',
Expand Down Expand Up @@ -106,13 +111,10 @@
}
}]
},
pan: {
enabled: true,
mode: 'xy'
},
zoom: {
enabled: true,
mode: 'xy',
drag: true,
mode: 'x',
limits: {
max: 10,
min: 0.5
Expand Down
Loading

0 comments on commit 7ea251b

Please sign in to comment.