Skip to content
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
14 changes: 10 additions & 4 deletions docs/samples/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,15 +84,21 @@ const actions = [
chart.zoom({x: 0.9});
},
}, {
name: 'Pan x 100px',
name: 'Pan x 100px (anim)',
handler(chart) {
chart.pan({x: 100});
chart.pan({x: 100}, undefined, 'default');
}
}, {
name: 'Pan x -100px',
name: 'Pan x -100px (anim)',
handler(chart) {
chart.pan({x: -100});
chart.pan({x: -100}, undefined, 'default');
},
}, {
name: 'Zoom x: 0..-100, y: 0..100',
handler(chart) {
chart.zoomScale('x', {min: -100, max: 0}, 'default');
chart.zoomScale('y', {min: 0, max: 100}, 'default');
}
}, {
name: 'Reset zoom',
handler(chart) {
Expand Down
13 changes: 13 additions & 0 deletions docs/samples/time.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,20 @@ const actions = [
handler(chart) {
chart.resetZoom();
}
}, {
name: 'Zoom to next week',
handler(chart) {
chart.zoomScale('x', Utils.nextWeek(), 'default');
chart.update();
}
}, {
name: 'Zoom to 400-600',
handler(chart) {
chart.zoomScale('y', {min: 400, max: 600}, 'default');
chart.update();
}
}

];

module.exports = {
Expand Down
11 changes: 10 additions & 1 deletion docs/scripts/utils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {valueOrDefault} from 'chart.js/helpers';
import {addHours} from 'date-fns';
import {addHours, startOfWeek, endOfWeek} from 'date-fns';

// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
let _seed = Date.now();
Expand Down Expand Up @@ -86,3 +86,12 @@ export function hourlyPoints(config) {
const start = new Date().valueOf();
return ys.map((y, i) => ({x: addHours(start, i), y}));
}

export function nextWeek() {
const now = new Date().valueOf();
const min = startOfWeek(addHours(endOfWeek(now), 24));
return {
min: +min,
max: +endOfWeek(min)
};
}
39 changes: 24 additions & 15 deletions src/core.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {each, callback as call} from 'chart.js/helpers';
import {panFunctions, zoomFunctions} from './scale.types';
import {panFunctions, updateRange, zoomFunctions} from './scale.types';
import {getState} from './state';
import {directionEnabled, getEnabledScalesByPoint} from './utils';

Expand All @@ -18,9 +18,9 @@ function storeOriginalScaleLimits(chart) {
return originalScaleLimits;
}

function zoomScale(scale, zoom, center, limits) {
function doZoom(scale, amount, center, limits) {
const fn = zoomFunctions[scale.type] || zoomFunctions.default;
call(fn, [scale, zoom, center, limits]);
call(fn, [scale, amount, center, limits]);
}

function getCenter(chart) {
Expand All @@ -33,11 +33,11 @@ function getCenter(chart) {

/**
* @param chart The chart instance
* @param {number | {x?: number, y?: number, focalPoint?: {x: number, y: number}}} zoom The zoom percentage or percentages and focal point
* @param {boolean} [useTransition] Whether to use `zoom` transition
* @param {number | {x?: number, y?: number, focalPoint?: {x: number, y: number}}} amount The zoom percentage or percentages and focal point
* @param {string} [transition] Which transiton mode to use. Defaults to 'none'
*/
export function doZoom(chart, zoom, useTransition) {
const {x = 1, y = 1, focalPoint = getCenter(chart)} = typeof zoom === 'number' ? {x: zoom, y: zoom} : zoom;
export function zoom(chart, amount, transition = 'none') {
const {x = 1, y = 1, focalPoint = getCenter(chart)} = typeof amount === 'number' ? {x: amount, y: amount} : amount;
const {options: {limits, zoom: zoomOptions}} = getState(chart);
const {mode = 'xy', overScaleMode} = zoomOptions || {};

Expand All @@ -49,18 +49,27 @@ export function doZoom(chart, zoom, useTransition) {

each(enabledScales || chart.scales, function(scale) {
if (scale.isHorizontal() && xEnabled) {
zoomScale(scale, x, focalPoint, limits);
doZoom(scale, x, focalPoint, limits);
} else if (!scale.isHorizontal() && yEnabled) {
zoomScale(scale, y, focalPoint, limits);
doZoom(scale, y, focalPoint, limits);
}
});

chart.update(useTransition ? 'zoom' : 'none');
chart.update(transition);

call(zoomOptions.onZoom, [{chart}]);
}

export function resetZoom(chart) {

export function zoomScale(chart, scaleId, range, transition = 'none') {
storeOriginalScaleLimits(chart);
const scale = chart.scales[scaleId];
updateRange(scale, range, undefined, true);
chart.update(transition);
}


export function resetZoom(chart, transition = 'default') {
const originalScaleLimits = storeOriginalScaleLimits(chart);

each(chart.scales, function(scale) {
Expand All @@ -73,7 +82,7 @@ export function resetZoom(chart) {
delete scaleOptions.max;
}
});
chart.update();
chart.update(transition);
}

function panScale(scale, delta, limits) {
Expand All @@ -90,8 +99,8 @@ function panScale(scale, delta, limits) {
}
}

export function doPan(chart, pan, enabledScales) {
const {x = 0, y = 0} = typeof pan === 'number' ? {x: pan, y: pan} : pan;
export function pan(chart, delta, enabledScales, transition = 'none') {
const {x = 0, y = 0} = typeof delta === 'number' ? {x: delta, y: delta} : delta;
const {options: {pan: panOptions, limits}} = getState(chart);
const {mode = 'xy', onPan} = panOptions || {};

Expand All @@ -108,7 +117,7 @@ export function doPan(chart, pan, enabledScales) {
}
});

chart.update('none');
chart.update(transition);

call(onPan, [{chart}]);
}
Expand Down
8 changes: 4 additions & 4 deletions src/hammer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {callback as call} from 'chart.js/helpers';
import Hammer from 'hammerjs';
import {doPan, doZoom} from './core';
import {pan, zoom} from './core';
import {getState} from './state';
import {directionEnabled, getEnabledScalesByPoint} from './utils';

Expand Down Expand Up @@ -50,7 +50,7 @@ function handlePinch(chart, state, e) {
const rect = e.target.getBoundingClientRect();
const pinch = pinchAxes(pointers[0], pointers[1]);
const mode = state.options.zoom.mode;
const zoom = {
const amount = {
x: pinch.x && directionEnabled(mode, 'x', chart) ? zoomPercent : 1,
y: pinch.y && directionEnabled(mode, 'y', chart) ? zoomPercent : 1,
focalPoint: {
Expand All @@ -59,7 +59,7 @@ function handlePinch(chart, state, e) {
}
};

doZoom(chart, zoom);
zoom(chart, amount);

// Keep track of overall scale
state.scale = e.scale;
Expand All @@ -84,7 +84,7 @@ function handlePan(chart, state, e) {
const delta = state.delta;
if (delta !== null) {
state.panning = true;
doPan(chart, {x: e.deltaX - delta.x, y: e.deltaY - delta.y}, state.panScales);
pan(chart, {x: e.deltaX - delta.x, y: e.deltaY - delta.y}, state.panScales);
state.delta = {x: e.deltaX, y: e.deltaY};
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/handlers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {directionEnabled, debounce} from './utils';
import {doZoom} from './core';
import {zoom} from './core';
import {callback as call} from 'chart.js/helpers';
import {getState} from './state';

Expand Down Expand Up @@ -85,15 +85,15 @@ export function mouseUp(chart, event) {
}

const {top, left, width, height} = chart.chartArea;
const zoom = {
const amount = {
x: rect.zoomX,
y: rect.zoomY,
focalPoint: {
x: (rect.left - left) / (1 - dragDistanceX / width) + left,
y: (rect.top - top) / (1 - dragDistanceY / height) + top
}
};
doZoom(chart, zoom, true);
zoom(chart, amount, 'zoom');

call(zoomOptions.onZoomComplete, [chart]);
}
Expand All @@ -120,7 +120,7 @@ export function wheel(chart, event) {

const rect = event.target.getBoundingClientRect();
const speed = 1 + (event.deltaY >= 0 ? -zoomOptions.speed : zoomOptions.speed);
const zoom = {
const amount = {
x: speed,
y: speed,
focalPoint: {
Expand All @@ -129,7 +129,7 @@ export function wheel(chart, event) {
}
};

doZoom(chart, zoom);
zoom(chart, amount);

if (onZoomComplete) {
debounce(() => call(onZoomComplete, [{chart}]), 250);
Expand Down
2 changes: 1 addition & 1 deletion src/index.esm.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import plugin from './plugin';

export default plugin;
export {doPan, doZoom, resetZoom} from './core';
export {pan, zoom, zoomScale, resetZoom} from './core';
9 changes: 5 additions & 4 deletions src/plugin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Hammer from 'hammerjs';
import {addListeners, computeDragRect, removeListeners} from './handlers';
import {startHammer, stopHammer} from './hammer';
import {doPan, doZoom, resetZoom} from './core';
import {pan, zoom, resetZoom, zoomScale} from './core';
import {panFunctions, zoomFunctions} from './scale.types';
import {getState, removeState} from './state';
import {version} from '../package.json';
Expand All @@ -26,16 +26,17 @@ export default {
}
},

start: function(chart, args, options) {
start: function(chart, _args, options) {
const state = getState(chart);
state.options = options;

if (Hammer) {
startHammer(chart, options);
}

chart.pan = (pan, panScales) => doPan(chart, pan, panScales);
chart.zoom = (zoom, useTransition) => doZoom(chart, zoom, useTransition);
chart.pan = (delta, panScales, transition) => pan(chart, delta, panScales, transition);
chart.zoom = (args, transition) => zoom(chart, args, transition);
chart.zoomScale = (id, range, transition) => zoomScale(chart, id, range, transition);
chart.resetZoom = () => resetZoom(chart);
},

Expand Down
2 changes: 1 addition & 1 deletion src/scale.types.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function zoomDelta(scale, zoom, center) {
};
}

function updateRange(scale, {min, max}, limits, zoom = false) {
export function updateRange(scale, {min, max}, limits, zoom = false) {
const {axis, options: scaleOpts} = scale;
const {min: minLimit = -Infinity, max: maxLimit = Infinity, minRange = 0} = limits && limits[axis] || {};
const cmin = Math.max(min, minLimit);
Expand Down
23 changes: 16 additions & 7 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import { Plugin, ChartType, Chart, Scale } from 'chart.js';
import { Plugin, ChartType, Chart, Scale, UpdateMode } from 'chart.js';
import { DistributiveArray } from 'chart.js/types/utils';
import { ZoomPluginOptions } from './options';

type Point = { x: number, y: number };
type ZoomAmount = number | Partial<Point> & { focalPoint?: Point };
type PanAmount = number | Partial<Point>;
type ScaleRange = { min: number, max: number };

declare module 'chart.js' {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface PluginOptionsByType<TType extends ChartType> {
zoom: ZoomPluginOptions;
}

enum UpdateModeEnum {
zoom = 'zoom'
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Chart<TType extends keyof ChartTypeRegistry = keyof ChartTypeRegistry, TData = DistributiveArray<ChartTypeRegistry[TType]['defaultDataPoint']>, TLabel = unknown> {
pan(pan: PanAmount, scales?: Scale[]): void;
zoom(zoom: ZoomAmount, useTransition?: boolean): void;
resetZoom(): void;
pan(pan: PanAmount, scales?: Scale[], mode?: UpdateMode): void;
zoom(zoom: ZoomAmount, useTransition?: boolean, mode?: UpdateMode): void;
zoomScale(id: string, range: ScaleRange, mode?: UpdateMode): void;
resetZoom(mode?: UpdateMode): void;
}
}

declare const Zoom: Plugin;

export default Zoom;

export function doPan(chart: Chart, pan: PanAmount, scales?: Scale[]): void;
export function doZoom(chart: Chart, zoom: ZoomAmount, useTransition?: boolean): void;
export function resetZoom(chart: Chart): void;
export function pan(chart: Chart, amount: PanAmount, scales?: Scale[], mode?: UpdateMode): void;
export function zoom(chart: Chart, amount: ZoomAmount, mode?: UpdateMode): void;
export function zoomScale(chart: Chart, scaleId: string, range: ScaleRange, mode?: UpdateMode): void;
export function resetZoom(chart: Chart, mode?: UpdateMode): void;
8 changes: 4 additions & 4 deletions types/tests/exports.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Chart } from 'chart.js';
import Zoom, { doPan, doZoom, resetZoom } from '../index';
import Zoom, {pan, zoom, resetZoom } from '../index';

Chart.register(Zoom);
Chart.unregister(Zoom);
Expand Down Expand Up @@ -49,6 +49,6 @@ chart.zoom({ x: 1, y: 1.1, focalPoint: { x: 10, y: 10 } }, true);
chart.pan(10);
chart.pan({ x: 10, y: 20 }, [chart.scales.x]);

doPan(chart, -42);
doZoom(chart, { x: 1, y: 1.1, focalPoint: { x: 10, y: 10 } }, true);
resetZoom(chart);
pan(chart, -42, undefined, 'zoom');
zoom(chart, { x: 1, y: 1.1, focalPoint: { x: 10, y: 10 } }, 'zoom');
resetZoom(chart, 'none');