Skip to content

Category zoom #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 28, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 96 additions & 53 deletions Chart.Zoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
/*global require*/

// hammer JS for touch support
var Hammer = require('hammerjs');
var Hammer = require('hammerjs');
Hammer = typeof(Hammer) === 'function' ? Hammer : window.Hammer;

// Get the chart variable
Expand All @@ -27,19 +27,20 @@ var zoomNS = Chart.Zoom = Chart.Zoom || {};

// Where we store functions to handle different scale types
var zoomFunctions = zoomNS.zoomFunctions = zoomNS.zoomFunctions || {};
var panFunctions = zoomNS.panFunctions = zoomNS.panFunctions || {};
var panFunctions = zoomNS.panFunctions = zoomNS.panFunctions || {};

// Default options if none are provided
var defaultOptions = zoomNS.defaults = {
pan: {
enabled: true,
mode: 'xy',
speed: 20,
speed: 20,
threshold: 10,
},
zoom: {
enabled: true,
mode: 'xy',
sensitivity: 3,
}
};

Expand All @@ -53,13 +54,50 @@ function directionEnabled(mode, dir) {
return false;
}

function zoomIndexScale(scale, zoom, center) {

function zoomIndexScale(scale, zoom, center, zoomOptions) {
var labels = scale.chart.data.labels;
var minIndex = scale.minIndex;
var lastLabelIndex = labels.length - 1;
var maxIndex = scale.maxIndex;
var sensitivity = zoomOptions.sensitivity;
var chartCenter = scale.isHorizontal() ? scale.left + (scale.width/2) : scale.top + (scale.height/2);
var centerPointer = scale.isHorizontal() ? center.x : center.y;

zoomNS.zoomCumulativeDelta = zoom > 1 ? zoomNS.zoomCumulativeDelta + 1 : zoomNS.zoomCumulativeDelta - 1;

if (Math.abs(zoomNS.zoomCumulativeDelta) > sensitivity){
if(zoomNS.zoomCumulativeDelta < 0){
if(centerPointer <= chartCenter){
if (minIndex <= 0){
maxIndex = Math.min(lastLabelIndex, maxIndex + 1);
} else{
minIndex = Math.max(0, minIndex - 1);
}
} else if(centerPointer > chartCenter){
if (maxIndex >= lastLabelIndex){
minIndex = Math.max(0, minIndex - 1);
} else{
maxIndex = Math.min(lastLabelIndex, maxIndex + 1);
}
}
zoomNS.zoomCumulativeDelta = 0;
}
else if(zoomNS.zoomCumulativeDelta > 0){
if(centerPointer <= chartCenter){
minIndex = minIndex < maxIndex ? minIndex = Math.min(maxIndex, minIndex + 1) : minIndex;
} else if(centerPointer > chartCenter){
maxIndex = maxIndex > minIndex ? maxIndex = Math.max(minIndex, maxIndex - 1) : maxIndex;
}
zoomNS.zoomCumulativeDelta = 0;
}
scale.options.ticks.min = labels[minIndex];
scale.options.ticks.max = labels[maxIndex];
}
}

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

var range;
var min_percent;
if (scale.isHorizontal()) {
Expand Down Expand Up @@ -95,10 +133,10 @@ function zoomNumericalScale(scale, zoom, center) {
scale.options.ticks.max = scale.max - maxDelta;
}

function zoomScale(scale, zoom, center) {
function zoomScale(scale, zoom, center, zoomOptions) {
var fn = zoomFunctions[scale.options.type];
if (fn) {
fn(scale, zoom, center);
fn(scale, zoom, center, zoomOptions);
}
}

Expand All @@ -116,13 +154,14 @@ function doZoom(chartInstance, zoom, center) {
if (zoomOptions && helpers.getValueOrDefault(zoomOptions.enabled, defaultOptions.zoom.enabled)) {
// Do the zoom here
var zoomMode = helpers.getValueOrDefault(chartInstance.options.zoom.mode, defaultOptions.zoom.mode);
zoomOptions.sensitivity = helpers.getValueOrDefault(chartInstance.options.zoom.sensitivity, defaultOptions.zoom.sensitivity);

helpers.each(chartInstance.scales, function(scale, id) {
if (scale.isHorizontal() && directionEnabled(zoomMode, 'x')) {
zoomScale(scale, zoom, center);
} else if (directionEnabled(zoomMode, 'y')) {
zoomScale(scale, zoom, center, zoomOptions);
} else if (!scale.isHorizontal() && directionEnabled(zoomMode, 'y')) {
// Do Y zoom
zoomScale(scale, zoom, center);
zoomScale(scale, zoom, center, zoomOptions);
}
});

Expand All @@ -131,23 +170,23 @@ function doZoom(chartInstance, zoom, center) {
}

function panIndexScale(scale, delta, panOptions) {
var labels = scale.chart.data.labels;
var lastLabelIndex = labels.length - 1;
var offsetAmt = Math.max((scale.ticks.length - ((scale.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
var panSpeed = panOptions.speed;
var minIndex = scale.minIndex;
var step = Math.round(scale.width / (offsetAmt * panSpeed));
var maxIndex;
var labels = scale.chart.data.labels;
var lastLabelIndex = labels.length - 1;
var offsetAmt = Math.max((scale.ticks.length - ((scale.options.gridLines.offsetGridLines) ? 0 : 1)), 1);
var panSpeed = panOptions.speed;
var minIndex = scale.minIndex;
var step = Math.round(scale.width / (offsetAmt * panSpeed));
var maxIndex;

zoomNS.panCumulativeDelta += delta;
zoomNS.panCumulativeDelta += delta;

minIndex = zoomNS.panCumulativeDelta > step ? Math.max(0, minIndex -1) : zoomNS.panCumulativeDelta < -step ? Math.min(lastLabelIndex - offsetAmt + 1, minIndex + 1) : minIndex;
zoomNS.panCumulativeDelta = minIndex !== scale.minIndex ? 0 : zoomNS.panCumulativeDelta;
minIndex = zoomNS.panCumulativeDelta > step ? Math.max(0, minIndex -1) : zoomNS.panCumulativeDelta < -step ? Math.min(lastLabelIndex - offsetAmt + 1, minIndex + 1) : minIndex;
zoomNS.panCumulativeDelta = minIndex !== scale.minIndex ? 0 : zoomNS.panCumulativeDelta;

maxIndex = Math.min(lastLabelIndex, minIndex + offsetAmt - 1);
maxIndex = Math.min(lastLabelIndex, minIndex + offsetAmt - 1);

scale.options.ticks.min = labels[minIndex];
scale.options.ticks.max = labels[maxIndex];
scale.options.ticks.min = labels[minIndex];
scale.options.ticks.max = labels[maxIndex];
}

function panTimeScale(scale, delta) {
Expand Down Expand Up @@ -181,13 +220,13 @@ function doPan(chartInstance, deltaX, deltaY) {
var panOptions = chartInstance.options.pan;
if (panOptions && helpers.getValueOrDefault(panOptions.enabled, defaultOptions.pan.enabled)) {
var panMode = helpers.getValueOrDefault(chartInstance.options.pan.mode, defaultOptions.pan.mode);
panOptions.speed = helpers.getValueOrDefault(chartInstance.options.pan.speed, defaultOptions.pan.speed);
panOptions.speed = helpers.getValueOrDefault(chartInstance.options.pan.speed, defaultOptions.pan.speed);

helpers.each(chartInstance.scales, function(scale, id) {
if (scale.isHorizontal() && directionEnabled(panMode, 'x') && deltaX !== 0) {
panScale(scale, deltaX, panOptions);
} else if (!scale.isHorizontal() && directionEnabled(panMode, 'y') && deltaY !== 0) {
panScale(scale, deltaY);
panScale(scale, deltaY, panOptions);
}
});

Expand All @@ -197,15 +236,15 @@ function doPan(chartInstance, deltaX, deltaY) {

function positionInChartArea(chartInstance, position) {
return (position.x >= chartInstance.chartArea.left && position.x <= chartInstance.chartArea.right) &&
(position.y >= chartInstance.chartArea.top && position.y <= chartInstance.chartArea.bottom);
(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;
}
Expand All @@ -221,38 +260,39 @@ zoomNS.panFunctions.category = panIndexScale;
zoomNS.panFunctions.time = panTimeScale;
zoomNS.panFunctions.linear = panNumericalScale;
zoomNS.panFunctions.logarithmic = panNumericalScale;
//global for catergory pan
// Globals for catergory pan and zoom
zoomNS.panCumulativeDelta = 0;
zoomNS.zoomCumulativeDelta = 0;

// 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();
};

Expand All @@ -265,20 +305,20 @@ var zoomPlugin = {
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;
Expand All @@ -289,14 +329,14 @@ var zoomPlugin = {
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;
}
Expand All @@ -307,20 +347,22 @@ var zoomPlugin = {
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);
}
// Prevent the event from triggering the default behavior (eg. Content scrolling).
e.preventDefault();
};
chartInstance._wheelHandler = wheelHandler;

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

Expand All @@ -340,14 +382,15 @@ var zoomPlugin = {
// Keep track of overall scale
currentPinchScaling = e.scale;
};

mc.on('pinchstart', function(e) {
currentPinchScaling = 1; // reset tracker
});
mc.on('pinch', handlePinch);
mc.on('pinchend', function(e) {
handlePinch(e);
currentPinchScaling = null; // reset
zoomNS.zoomCumulativeDelta = 0;
});

var currentDeltaX = null, currentDeltaY = null;
Expand All @@ -368,9 +411,9 @@ var zoomPlugin = {
});
mc.on('panmove', handlePan);
mc.on('panend', function(e) {
currentDeltaX = null;
currentDeltaY = null;
zoomNS.panCumulativeDelta = 0;
currentDeltaX = null;
currentDeltaY = null;
zoomNS.panCumulativeDelta = 0;
});
chartInstance._mc = mc;
}
Expand All @@ -381,21 +424,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 Down
Loading