Skip to content

Commit 7ec113a

Browse files
authored
Replace overScaleMode with more flexible scaleMode (#658)
* Spelling * Implement new scaleMode property * Add tests and a deprecation warning * Fix wording
1 parent 18e87a1 commit 7ec113a

10 files changed

Lines changed: 149 additions & 31 deletions

File tree

docs/guide/options.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ const chart = new Chart('id', {
3535
| `enabled` | `boolean` | `false` | Enable panning
3636
| `mode` | `'x'`\|`'y'`\|`'xy'` | `'xy'` | Allowed panning directions
3737
| `modifierKey` | `'ctrl'`\|`'alt'`\|`'shift'`\|`'meta'` | `null` | Modifier key required for panning with mouse
38-
| `overScaleMode` | `'x'`\|`'y'`\|`'xy'` | `undefined` | Which of the enabled panning directions should only be available when the mouse cursor is over a scale for that axis
38+
| `scaleMode` | `'x'`\|`'y'`\|`'xy'` | `undefined` | Enable panning over a scale for that axis (regardless of mode)
39+
| `overScaleMode` | `'x'`\|`'y'`\|`'xy'` | `undefined` | Enable panning over a scale for that axis (but only if mode is also enabled), and disables panning along that axis otherwise. Deprecated.
3940
| `threshold` | `number` | `10` | Minimal pan distance required before actually applying pan
4041

4142
### Pan Events
@@ -57,7 +58,8 @@ const chart = new Chart('id', {
5758
| `drag` | [`DragOptions`](#drag-options) | | Options of the drag-to-zoom behavior
5859
| `pinch` | [`PinchOptions`](#pinch-options) | | Options of the pinch behavior
5960
| `mode` | `'x'`\|`'y'`\|`'xy'` | `'xy'` | Allowed zoom directions
60-
| `overScaleMode` | `'x'`\|`'y'`\|`'xy'` | `undefined` | Which of the enabled zooming directions should only be available when the mouse cursor is over a scale for that axis
61+
| `scaleMode` | `'x'`\|`'y'`\|`'xy'` | `undefined` | Which of the enabled zooming directions should only be available when the mouse cursor is over a scale for that axis
62+
| `overScaleMode` | `'x'`\|`'y'`\|`'xy'` | `undefined` | Allowed zoom directions when the mouse cursor is over a scale for that axis (but only if mode is also enabled), and disables zooming along that axis otherwise. Deprecated; use `scaleMode` instead.
6163

6264
#### Wheel options
6365

docs/samples/wheel/over-scale-mode.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ const zoomOptions = {
6262
enabled: true,
6363
},
6464
mode: 'xy',
65-
overScaleMode: 'xy',
65+
scaleMode: 'xy',
6666
},
6767
pan: {
6868
enabled: true,
6969
mode: 'xy',
70-
overScaleMode: 'xy',
70+
scaleMode: 'xy',
7171
}
7272
};
7373
// </block>

samples/zoom-separately.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@
100100
zoom: {
101101
pan: {
102102
enabled: true,
103-
mode: 'xy',
104-
overScaleMode: 'y'
103+
mode: 'x',
104+
scaleMode: 'y'
105105
},
106106
zoom: {
107107
wheel: {
@@ -110,8 +110,8 @@
110110
pinch: {
111111
enabled: true,
112112
},
113-
mode: 'xy',
114-
overScaleMode: 'y'
113+
mode: 'x',
114+
scaleMode: 'y'
115115
}
116116
}
117117
}

src/core.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,12 @@ export function zoom(chart, amount, transition = 'none') {
6060
const {x = 1, y = 1, focalPoint = getCenter(chart)} = typeof amount === 'number' ? {x: amount, y: amount} : amount;
6161
const state = getState(chart);
6262
const {options: {limits, zoom: zoomOptions}} = state;
63-
const {mode = 'xy', overScaleMode} = zoomOptions || {};
6463

6564
storeOriginalScaleLimits(chart, state);
6665

67-
const xEnabled = x !== 1 && directionEnabled(mode, 'x', chart);
68-
const yEnabled = y !== 1 && directionEnabled(mode, 'y', chart);
69-
const enabledScales = overScaleMode && getEnabledScalesByPoint(overScaleMode, focalPoint, chart);
66+
const xEnabled = x !== 1;
67+
const yEnabled = y !== 1;
68+
const enabledScales = getEnabledScalesByPoint(zoomOptions, focalPoint, chart);
7069

7170
each(enabledScales || chart.scales, function(scale) {
7271
if (scale.isHorizontal() && xEnabled) {
@@ -182,12 +181,12 @@ export function pan(chart, delta, enabledScales, transition = 'none') {
182181
const {x = 0, y = 0} = typeof delta === 'number' ? {x: delta, y: delta} : delta;
183182
const state = getState(chart);
184183
const {options: {pan: panOptions, limits}} = state;
185-
const {mode = 'xy', onPan} = panOptions || {};
184+
const {onPan} = panOptions || {};
186185

187186
storeOriginalScaleLimits(chart, state);
188187

189-
const xEnabled = x !== 0 && directionEnabled(mode, 'x', chart);
190-
const yEnabled = y !== 0 && directionEnabled(mode, 'y', chart);
188+
const xEnabled = x !== 0;
189+
const yEnabled = y !== 0;
191190

192191
each(enabledScales || chart.scales, function(scale) {
193192
if (scale.isHorizontal() && xEnabled) {

src/hammer.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ function handlePan(chart, state, e) {
9090
}
9191

9292
function startPan(chart, state, event) {
93-
const {enabled, overScaleMode, onPanStart, onPanRejected} = state.options.pan;
93+
const {enabled, onPanStart, onPanRejected} = state.options.pan;
9494
if (!enabled) {
9595
return;
9696
}
@@ -104,7 +104,7 @@ function startPan(chart, state, event) {
104104
return call(onPanRejected, [{chart, event}]);
105105
}
106106

107-
state.panScales = overScaleMode && getEnabledScalesByPoint(overScaleMode, point, chart);
107+
state.panScales = getEnabledScalesByPoint(state.options.pan, point, chart);
108108
state.delta = {x: 0, y: 0};
109109
clearTimeout(state.panEndTimeout);
110110
handlePan(chart, state, event);

src/handlers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ function wheelPreconditions(chart, event, zoomOptions) {
133133
return;
134134
}
135135

136-
// Prevent the event from triggering the default behavior (eg. Content scrolling).
136+
// Prevent the event from triggering the default behavior (e.g. content scrolling).
137137
if (event.cancelable) {
138138
event.preventDefault();
139139
}

src/plugin.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export default {
4242
if (Object.prototype.hasOwnProperty.call(options.zoom, 'enabled')) {
4343
console.warn('The option `zoom.enabled` is no longer supported. Please use `zoom.wheel.enabled`, `zoom.drag.enabled`, or `zoom.pinch.enabled`.');
4444
}
45+
if (Object.prototype.hasOwnProperty.call(options.zoom, 'overScaleMode')
46+
|| Object.prototype.hasOwnProperty.call(options.pan, 'overScaleMode')) {
47+
console.warn('The option `overScaleMode` is deprecated. Please use `scaleMode` instead (and update `mode` as desired).');
48+
}
4549

4650
if (Hammer) {
4751
startHammer(chart, options);

src/utils.js

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,17 @@ export function directionEnabled(mode, dir, chart) {
2222
return false;
2323
}
2424

25+
function directionsEnabled(mode, chart) {
26+
if (typeof mode === 'function') {
27+
mode = mode({chart});
28+
}
29+
if (typeof mode === 'string') {
30+
return {x: mode.indexOf('x') !== -1, y: mode.indexOf('y') !== -1};
31+
}
32+
33+
return {x: false, y: false};
34+
}
35+
2536
/**
2637
* Debounces calling `fn` for `delay` ms
2738
* @param {function} fn - Function to call. No arguments are passed.
@@ -37,7 +48,8 @@ export function debounce(fn, delay) {
3748
};
3849
}
3950

40-
/** This function use for check what axis now under mouse cursor.
51+
/**
52+
* Checks which axis is under the mouse cursor.
4153
* @param {{x: number, y: number}} point - the mouse location
4254
* @param {import('chart.js').Chart} [chart] instance of the chart in question
4355
* @return {import('chart.js').Scale}
@@ -54,27 +66,40 @@ function getScaleUnderPoint({x, y}, chart) {
5466
return null;
5567
}
5668

57-
/** This function return only one scale whose position is under mouse cursor and which direction is enabled.
58-
* If under mouse hasn't scale, then return all other scales which 'mode' is diffrent with overScaleMode.
59-
* So 'overScaleMode' works as a limiter to scale the user-selected scale (in 'mode') only when the cursor is under the scale,
60-
* and other directions in 'mode' works as before.
61-
* Example: mode = 'xy', overScaleMode = 'y' -> it's means 'x' - works as before, and 'y' only works for one scale when cursor is under it.
69+
/**
70+
* Evaluate the chart's mode, scaleMode, and overScaleMode properties to
71+
* determine which axes are eligible for scaling.
6272
* options.overScaleMode can be a function if user want zoom only one scale of many for example.
63-
* @param {string} mode - 'xy', 'x' or 'y'
73+
* @param options - Zoom or pan options
6474
* @param {{x: number, y: number}} point - the mouse location
6575
* @param {import('chart.js').Chart} [chart] instance of the chart in question
6676
* @return {import('chart.js').Scale[]}
6777
*/
68-
export function getEnabledScalesByPoint(mode, point, chart) {
78+
export function getEnabledScalesByPoint(options, point, chart) {
79+
const {mode = 'xy', scaleMode, overScaleMode} = options || {};
6980
const scale = getScaleUnderPoint(point, chart);
7081

71-
if (scale && directionEnabled(mode, scale.axis, chart)) {
82+
const enabled = directionsEnabled(mode, chart);
83+
const scaleEnabled = directionsEnabled(scaleMode, chart);
84+
85+
// Convert deprecated overScaleEnabled to new scaleEnabled.
86+
if (overScaleMode) {
87+
const overScaleEnabled = directionsEnabled(overScaleMode, chart);
88+
for (const axis of ['x', 'y']) {
89+
if (overScaleEnabled[axis]) {
90+
scaleEnabled[axis] = enabled[axis];
91+
enabled[axis] = false;
92+
}
93+
}
94+
}
95+
96+
if (scale && scaleEnabled[scale.axis]) {
7297
return [scale];
7398
}
7499

75100
const enabledScales = [];
76101
each(chart.scales, function(scaleItem) {
77-
if (!directionEnabled(mode, scaleItem.axis, chart)) {
102+
if (enabled[scaleItem.axis]) {
78103
enabledScales.push(scaleItem);
79104
}
80105
});

test/specs/zoom.spec.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,90 @@ describe('zoom', function() {
550550
});
551551
});
552552

553+
describe('with scaleMode = y and mode = xy', function() {
554+
const config = {
555+
type: 'line',
556+
data,
557+
options: {
558+
scales: {
559+
x: {
560+
type: 'linear',
561+
min: 1,
562+
max: 10
563+
},
564+
y: {
565+
type: 'linear'
566+
}
567+
},
568+
plugins: {
569+
zoom: {
570+
zoom: {
571+
wheel: {
572+
enabled: true,
573+
},
574+
mode: 'xy',
575+
scaleMode: 'y'
576+
}
577+
}
578+
}
579+
}
580+
};
581+
582+
describe('Wheel under Y scale', function() {
583+
it('should be applied on Y, but not on X scales.', async function() {
584+
const chart = window.acquireChart(config);
585+
586+
const scaleX = chart.scales.x;
587+
const scaleY = chart.scales.y;
588+
589+
const oldMinX = scaleX.options.min;
590+
const oldMaxX = scaleX.options.max;
591+
const oldMinY = scaleY.options.min;
592+
const oldMaxY = scaleY.options.max;
593+
594+
const wheelEv = {
595+
x: scaleY.left + (scaleY.right - scaleY.left) / 2,
596+
y: scaleY.top + (scaleY.bottom - scaleY.top) / 2,
597+
deltaY: 1
598+
};
599+
600+
await jasmine.triggerWheelEvent(chart, wheelEv);
601+
602+
expect(scaleX.options.min).toEqual(oldMinX);
603+
expect(scaleX.options.max).toEqual(oldMaxX);
604+
expect(scaleY.options.min).not.toEqual(oldMinY);
605+
expect(scaleY.options.max).not.toEqual(oldMaxY);
606+
});
607+
});
608+
609+
describe('Wheel not under Y scale', function() {
610+
it('should be applied on X and Y scales.', async function() {
611+
const chart = window.acquireChart(config);
612+
613+
const scaleX = chart.scales.x;
614+
const scaleY = chart.scales.y;
615+
616+
const oldMinX = scaleX.options.min;
617+
const oldMaxX = scaleX.options.max;
618+
const oldMinY = scaleY.options.min;
619+
const oldMaxY = scaleY.options.max;
620+
621+
const wheelEv = {
622+
x: scaleX.getPixelForValue(1.5),
623+
y: scaleY.getPixelForValue(1.1),
624+
deltaY: 1
625+
};
626+
627+
await jasmine.triggerWheelEvent(chart, wheelEv);
628+
629+
expect(scaleX.options.min).not.toEqual(oldMinX);
630+
expect(scaleX.options.max).not.toEqual(oldMaxX);
631+
expect(scaleY.options.min).not.toEqual(oldMinY);
632+
expect(scaleY.options.max).not.toEqual(oldMaxY);
633+
});
634+
});
635+
});
636+
553637
describe('events', function() {
554638
describe('wheel', function() {
555639
it('should call onZoomStart', function() {

types/options.d.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export interface PinchOptions {
6767
export interface ZoomOptions {
6868
/**
6969
* Zooming directions. Remove the appropriate direction to disable
70-
* Eg. 'y' would only allow zooming in the y direction
70+
* E.g. 'y' would only allow zooming in the y direction
7171
* A function that is called as the user is zooming and returns the
7272
* available directions can also be used:
7373
* mode: function({ chart }) {
@@ -91,6 +91,8 @@ export interface ZoomOptions {
9191
*/
9292
pinch?: PinchOptions;
9393

94+
scaleMode?: Mode | { (chart: Chart): Mode };
95+
/** @deprecated Use scaleMode instead */
9496
overScaleMode?: Mode | { (chart: Chart): Mode };
9597

9698
/**
@@ -122,7 +124,7 @@ export interface PanOptions {
122124

123125
/**
124126
* Panning directions. Remove the appropriate direction to disable
125-
* Eg. 'y' would only allow panning in the y direction
127+
* E.g. 'y' would only allow panning in the y direction
126128
* A function that is called as the user is panning and returns the
127129
* available directions can also be used:
128130
* mode: function({ chart }) {
@@ -136,7 +138,9 @@ export interface PanOptions {
136138
*/
137139
modifierKey?: Key;
138140

139-
overScaleMode?: Mode | { (char: Chart): Mode };
141+
scaleMode?: Mode | { (chart: Chart): Mode };
142+
/** @deprecated Use scaleMode instead */
143+
overScaleMode?: Mode | { (chart: Chart): Mode };
140144

141145
/**
142146
* Minimal pan distance required before actually applying pan

0 commit comments

Comments
 (0)