Skip to content

Commit a9d8494

Browse files
authored
Add zoomScale, rename doPan to pan, doZoom to zoom (#478)
* Add zoomScale, rename doPan to pan, doZoom to zoom * Reduce zoomScale parameters
1 parent a1609d5 commit a9d8494

File tree

11 files changed

+93
-46
lines changed

11 files changed

+93
-46
lines changed

docs/samples/api.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,21 @@ const actions = [
8484
chart.zoom({x: 0.9});
8585
},
8686
}, {
87-
name: 'Pan x 100px',
87+
name: 'Pan x 100px (anim)',
8888
handler(chart) {
89-
chart.pan({x: 100});
89+
chart.pan({x: 100}, undefined, 'default');
9090
}
9191
}, {
92-
name: 'Pan x -100px',
92+
name: 'Pan x -100px (anim)',
9393
handler(chart) {
94-
chart.pan({x: -100});
94+
chart.pan({x: -100}, undefined, 'default');
9595
},
96+
}, {
97+
name: 'Zoom x: 0..-100, y: 0..100',
98+
handler(chart) {
99+
chart.zoomScale('x', {min: -100, max: 0}, 'default');
100+
chart.zoomScale('y', {min: 0, max: 100}, 'default');
101+
}
96102
}, {
97103
name: 'Reset zoom',
98104
handler(chart) {

docs/samples/time.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,20 @@ const actions = [
106106
handler(chart) {
107107
chart.resetZoom();
108108
}
109+
}, {
110+
name: 'Zoom to next week',
111+
handler(chart) {
112+
chart.zoomScale('x', Utils.nextWeek(), 'default');
113+
chart.update();
114+
}
115+
}, {
116+
name: 'Zoom to 400-600',
117+
handler(chart) {
118+
chart.zoomScale('y', {min: 400, max: 600}, 'default');
119+
chart.update();
120+
}
109121
}
122+
110123
];
111124

112125
module.exports = {

docs/scripts/utils.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {valueOrDefault} from 'chart.js/helpers';
2-
import {addHours} from 'date-fns';
2+
import {addHours, startOfWeek, endOfWeek} from 'date-fns';
33

44
// Adapted from http://indiegamr.com/generate-repeatable-random-numbers-in-js/
55
let _seed = Date.now();
@@ -86,3 +86,12 @@ export function hourlyPoints(config) {
8686
const start = new Date().valueOf();
8787
return ys.map((y, i) => ({x: addHours(start, i), y}));
8888
}
89+
90+
export function nextWeek() {
91+
const now = new Date().valueOf();
92+
const min = startOfWeek(addHours(endOfWeek(now), 24));
93+
return {
94+
min: +min,
95+
max: +endOfWeek(min)
96+
};
97+
}

src/core.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {each, callback as call} from 'chart.js/helpers';
2-
import {panFunctions, zoomFunctions} from './scale.types';
2+
import {panFunctions, updateRange, zoomFunctions} from './scale.types';
33
import {getState} from './state';
44
import {directionEnabled, getEnabledScalesByPoint} from './utils';
55

@@ -18,9 +18,9 @@ function storeOriginalScaleLimits(chart) {
1818
return originalScaleLimits;
1919
}
2020

21-
function zoomScale(scale, zoom, center, limits) {
21+
function doZoom(scale, amount, center, limits) {
2222
const fn = zoomFunctions[scale.type] || zoomFunctions.default;
23-
call(fn, [scale, zoom, center, limits]);
23+
call(fn, [scale, amount, center, limits]);
2424
}
2525

2626
function getCenter(chart) {
@@ -33,11 +33,11 @@ function getCenter(chart) {
3333

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

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

5050
each(enabledScales || chart.scales, function(scale) {
5151
if (scale.isHorizontal() && xEnabled) {
52-
zoomScale(scale, x, focalPoint, limits);
52+
doZoom(scale, x, focalPoint, limits);
5353
} else if (!scale.isHorizontal() && yEnabled) {
54-
zoomScale(scale, y, focalPoint, limits);
54+
doZoom(scale, y, focalPoint, limits);
5555
}
5656
});
5757

58-
chart.update(useTransition ? 'zoom' : 'none');
58+
chart.update(transition);
5959

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

63-
export function resetZoom(chart) {
63+
64+
export function zoomScale(chart, scaleId, range, transition = 'none') {
65+
storeOriginalScaleLimits(chart);
66+
const scale = chart.scales[scaleId];
67+
updateRange(scale, range, undefined, true);
68+
chart.update(transition);
69+
}
70+
71+
72+
export function resetZoom(chart, transition = 'default') {
6473
const originalScaleLimits = storeOriginalScaleLimits(chart);
6574

6675
each(chart.scales, function(scale) {
@@ -73,7 +82,7 @@ export function resetZoom(chart) {
7382
delete scaleOptions.max;
7483
}
7584
});
76-
chart.update();
85+
chart.update(transition);
7786
}
7887

7988
function panScale(scale, delta, limits) {
@@ -90,8 +99,8 @@ function panScale(scale, delta, limits) {
9099
}
91100
}
92101

93-
export function doPan(chart, pan, enabledScales) {
94-
const {x = 0, y = 0} = typeof pan === 'number' ? {x: pan, y: pan} : pan;
102+
export function pan(chart, delta, enabledScales, transition = 'none') {
103+
const {x = 0, y = 0} = typeof delta === 'number' ? {x: delta, y: delta} : delta;
95104
const {options: {pan: panOptions, limits}} = getState(chart);
96105
const {mode = 'xy', onPan} = panOptions || {};
97106

@@ -108,7 +117,7 @@ export function doPan(chart, pan, enabledScales) {
108117
}
109118
});
110119

111-
chart.update('none');
120+
chart.update(transition);
112121

113122
call(onPan, [{chart}]);
114123
}

src/hammer.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {callback as call} from 'chart.js/helpers';
22
import Hammer from 'hammerjs';
3-
import {doPan, doZoom} from './core';
3+
import {pan, zoom} from './core';
44
import {getState} from './state';
55
import {directionEnabled, getEnabledScalesByPoint} from './utils';
66

@@ -50,7 +50,7 @@ function handlePinch(chart, state, e) {
5050
const rect = e.target.getBoundingClientRect();
5151
const pinch = pinchAxes(pointers[0], pointers[1]);
5252
const mode = state.options.zoom.mode;
53-
const zoom = {
53+
const amount = {
5454
x: pinch.x && directionEnabled(mode, 'x', chart) ? zoomPercent : 1,
5555
y: pinch.y && directionEnabled(mode, 'y', chart) ? zoomPercent : 1,
5656
focalPoint: {
@@ -59,7 +59,7 @@ function handlePinch(chart, state, e) {
5959
}
6060
};
6161

62-
doZoom(chart, zoom);
62+
zoom(chart, amount);
6363

6464
// Keep track of overall scale
6565
state.scale = e.scale;
@@ -84,7 +84,7 @@ function handlePan(chart, state, e) {
8484
const delta = state.delta;
8585
if (delta !== null) {
8686
state.panning = true;
87-
doPan(chart, {x: e.deltaX - delta.x, y: e.deltaY - delta.y}, state.panScales);
87+
pan(chart, {x: e.deltaX - delta.x, y: e.deltaY - delta.y}, state.panScales);
8888
state.delta = {x: e.deltaX, y: e.deltaY};
8989
}
9090
}

src/handlers.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {directionEnabled, debounce} from './utils';
2-
import {doZoom} from './core';
2+
import {zoom} from './core';
33
import {callback as call} from 'chart.js/helpers';
44
import {getState} from './state';
55

@@ -85,15 +85,15 @@ export function mouseUp(chart, event) {
8585
}
8686

8787
const {top, left, width, height} = chart.chartArea;
88-
const zoom = {
88+
const amount = {
8989
x: rect.zoomX,
9090
y: rect.zoomY,
9191
focalPoint: {
9292
x: (rect.left - left) / (1 - dragDistanceX / width) + left,
9393
y: (rect.top - top) / (1 - dragDistanceY / height) + top
9494
}
9595
};
96-
doZoom(chart, zoom, true);
96+
zoom(chart, amount, 'zoom');
9797

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

121121
const rect = event.target.getBoundingClientRect();
122122
const speed = 1 + (event.deltaY >= 0 ? -zoomOptions.speed : zoomOptions.speed);
123-
const zoom = {
123+
const amount = {
124124
x: speed,
125125
y: speed,
126126
focalPoint: {
@@ -129,7 +129,7 @@ export function wheel(chart, event) {
129129
}
130130
};
131131

132-
doZoom(chart, zoom);
132+
zoom(chart, amount);
133133

134134
if (onZoomComplete) {
135135
debounce(() => call(onZoomComplete, [{chart}]), 250);

src/index.esm.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import plugin from './plugin';
22

33
export default plugin;
4-
export {doPan, doZoom, resetZoom} from './core';
4+
export {pan, zoom, zoomScale, resetZoom} from './core';

src/plugin.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Hammer from 'hammerjs';
22
import {addListeners, computeDragRect, removeListeners} from './handlers';
33
import {startHammer, stopHammer} from './hammer';
4-
import {doPan, doZoom, resetZoom} from './core';
4+
import {pan, zoom, resetZoom, zoomScale} from './core';
55
import {panFunctions, zoomFunctions} from './scale.types';
66
import {getState, removeState} from './state';
77
import {version} from '../package.json';
@@ -26,16 +26,17 @@ export default {
2626
}
2727
},
2828

29-
start: function(chart, args, options) {
29+
start: function(chart, _args, options) {
3030
const state = getState(chart);
3131
state.options = options;
3232

3333
if (Hammer) {
3434
startHammer(chart, options);
3535
}
3636

37-
chart.pan = (pan, panScales) => doPan(chart, pan, panScales);
38-
chart.zoom = (zoom, useTransition) => doZoom(chart, zoom, useTransition);
37+
chart.pan = (delta, panScales, transition) => pan(chart, delta, panScales, transition);
38+
chart.zoom = (args, transition) => zoom(chart, args, transition);
39+
chart.zoomScale = (id, range, transition) => zoomScale(chart, id, range, transition);
3940
chart.resetZoom = () => resetZoom(chart);
4041
},
4142

src/scale.types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function zoomDelta(scale, zoom, center) {
1212
};
1313
}
1414

15-
function updateRange(scale, {min, max}, limits, zoom = false) {
15+
export function updateRange(scale, {min, max}, limits, zoom = false) {
1616
const {axis, options: scaleOpts} = scale;
1717
const {min: minLimit = -Infinity, max: maxLimit = Infinity, minRange = 0} = limits && limits[axis] || {};
1818
const cmin = Math.max(min, minLimit);

types/index.d.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,36 @@
1-
import { Plugin, ChartType, Chart, Scale } from 'chart.js';
1+
import { Plugin, ChartType, Chart, Scale, UpdateMode } from 'chart.js';
22
import { DistributiveArray } from 'chart.js/types/utils';
33
import { ZoomPluginOptions } from './options';
44

55
type Point = { x: number, y: number };
66
type ZoomAmount = number | Partial<Point> & { focalPoint?: Point };
77
type PanAmount = number | Partial<Point>;
8+
type ScaleRange = { min: number, max: number };
9+
810
declare module 'chart.js' {
911
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1012
interface PluginOptionsByType<TType extends ChartType> {
1113
zoom: ZoomPluginOptions;
1214
}
15+
16+
enum UpdateModeEnum {
17+
zoom = 'zoom'
18+
}
19+
1320
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1421
interface Chart<TType extends keyof ChartTypeRegistry = keyof ChartTypeRegistry, TData = DistributiveArray<ChartTypeRegistry[TType]['defaultDataPoint']>, TLabel = unknown> {
15-
pan(pan: PanAmount, scales?: Scale[]): void;
16-
zoom(zoom: ZoomAmount, useTransition?: boolean): void;
17-
resetZoom(): void;
22+
pan(pan: PanAmount, scales?: Scale[], mode?: UpdateMode): void;
23+
zoom(zoom: ZoomAmount, useTransition?: boolean, mode?: UpdateMode): void;
24+
zoomScale(id: string, range: ScaleRange, mode?: UpdateMode): void;
25+
resetZoom(mode?: UpdateMode): void;
1826
}
1927
}
2028

2129
declare const Zoom: Plugin;
2230

2331
export default Zoom;
2432

25-
export function doPan(chart: Chart, pan: PanAmount, scales?: Scale[]): void;
26-
export function doZoom(chart: Chart, zoom: ZoomAmount, useTransition?: boolean): void;
27-
export function resetZoom(chart: Chart): void;
33+
export function pan(chart: Chart, amount: PanAmount, scales?: Scale[], mode?: UpdateMode): void;
34+
export function zoom(chart: Chart, amount: ZoomAmount, mode?: UpdateMode): void;
35+
export function zoomScale(chart: Chart, scaleId: string, range: ScaleRange, mode?: UpdateMode): void;
36+
export function resetZoom(chart: Chart, mode?: UpdateMode): void;

0 commit comments

Comments
 (0)