Skip to content

Commit 80bda33

Browse files
committed
fix(dataZoom): preserve page scroll on wheel-axis mismatch
1 parent dfec4f4 commit 80bda33

2 files changed

Lines changed: 74 additions & 10 deletions

File tree

src/component/dataZoom/roams.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ function mergeControllerParams(
198198
'type_undefined': -1
199199
};
200200
let preventDefaultMouseMove = true;
201+
let zoomOnMouseWheelEverActive = false;
202+
let moveOnMouseWheelEverActive = false;
203+
// `dataZoomInfoMap` is guaranteed non-empty by the caller.
204+
const firstDz = dataZoomInfoMap.get(dataZoomInfoMap.keys()[0]).model;
205+
let zoomOnMouseWheelAxis = firstDz.get('zoomOnMouseWheelAxis', true);
206+
let moveOnMouseWheelAxis = firstDz.get('moveOnMouseWheelAxis', true);
201207

202208
dataZoomInfoMap.each(function (dataZoomInfo) {
203209
const dataZoomModel = dataZoomInfo.model;
@@ -214,17 +220,34 @@ function mergeControllerParams(
214220
// users may be confused why it does not work when multiple insideZooms exist.
215221
preventDefaultMouseMove = preventDefaultMouseMove
216222
&& dataZoomModel.get('preventDefaultMouseMove', true);
223+
224+
if (dataZoomModel.get('zoomOnMouseWheel', true) !== false) {
225+
zoomOnMouseWheelEverActive = true;
226+
}
227+
if (dataZoomModel.get('moveOnMouseWheel', true) !== false) {
228+
moveOnMouseWheelEverActive = true;
229+
}
230+
231+
if (zoomOnMouseWheelAxis !== dataZoomModel.get('zoomOnMouseWheelAxis', true)) {
232+
zoomOnMouseWheelAxis = undefined;
233+
}
234+
if (moveOnMouseWheelAxis !== dataZoomModel.get('moveOnMouseWheelAxis', true)) {
235+
moveOnMouseWheelAxis = undefined;
236+
}
217237
});
218238

219239
return {
220240
controlType: controlType,
221241
opt: {
222-
// RoamController will enable all of these functionalities,
223-
// and the final behavior is determined by its event listener
224-
// provided by each inside zoom.
225-
zoomOnMouseWheel: true,
242+
// RoamController enables these functionalities if any inside
243+
// zoom opts in, and the final behavior (including modifier
244+
// specifics) is determined by its event listener provided by
245+
// each inside zoom.
246+
zoomOnMouseWheel: zoomOnMouseWheelEverActive,
226247
moveOnMouseMove: true,
227-
moveOnMouseWheel: true,
248+
moveOnMouseWheel: moveOnMouseWheelEverActive,
249+
zoomOnMouseWheelAxis: zoomOnMouseWheelAxis,
250+
moveOnMouseWheelAxis: moveOnMouseWheelAxis,
228251
preventDefaultMouseMove: !!preventDefaultMouseMove,
229252
api,
230253
zInfo: {

src/component/helper/RoamController.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,14 @@ export interface RoamOption {
4949
zoomOnMouseWheel?: boolean | 'ctrl' | 'shift' | 'alt'
5050
moveOnMouseMove?: boolean | 'ctrl' | 'shift' | 'alt'
5151
moveOnMouseWheel?: boolean | 'ctrl' | 'shift' | 'alt'
52+
/**
53+
* Restrict wheel-driven zoom to a single wheel axis. Unset = no restriction.
54+
*/
55+
zoomOnMouseWheelAxis?: WheelAxisType | undefined
56+
/**
57+
* Restrict wheel-driven pan to a single wheel axis. Unset = no restriction.
58+
*/
59+
moveOnMouseWheelAxis?: WheelAxisType | undefined
5260
/**
5361
* If fixed the page when pan
5462
*/
@@ -201,6 +209,9 @@ class RoamController extends Eventful<RoamEventDefinition> {
201209
moveOnMouseMove: true,
202210
// By default, wheel do not trigger move.
203211
moveOnMouseWheel: false,
212+
// `undefined` = no axis restriction.
213+
zoomOnMouseWheelAxis: undefined,
214+
moveOnMouseWheelAxis: undefined,
204215
preventDefaultMouseMove: true,
205216
zInfoParsed,
206217
triggerInfo,
@@ -389,11 +400,11 @@ class RoamController extends Eventful<RoamEventDefinition> {
389400
return;
390401
}
391402

392-
const shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);
393-
const shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);
403+
const zoomAvailable = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);
404+
const moveAvailable = isAvailableBehavior('moveOnMouseWheel', e, this._opt);
394405
const wheelDelta = e.wheelDelta;
395406
// wheelDelta maybe -0 in chrome mac.
396-
if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {
407+
if (wheelDelta === 0 || (!zoomAvailable && !moveAvailable)) {
397408
return;
398409
}
399410

@@ -402,6 +413,19 @@ class RoamController extends Eventful<RoamEventDefinition> {
402413
// Pre-2013 IE has no `deltaY`; the axis helpers fall back to the
403414
// passed default in that case.
404415
const nativeEvent = (e.event as unknown as WheelEvent) || null;
416+
417+
// When axis restriction is set, the wheel must carry delta
418+
// on that axis or the event falls through to the browser.
419+
const zoomAxis = this._opt.zoomOnMouseWheelAxis;
420+
const moveAxis = this._opt.moveOnMouseWheelAxis;
421+
const shouldZoom = zoomAvailable
422+
&& (zoomAxis == null || axisHasDelta(nativeEvent, zoomAxis));
423+
const shouldMove = moveAvailable
424+
&& (moveAxis == null || axisHasDelta(nativeEvent, moveAxis));
425+
if (!shouldZoom && !shouldMove) {
426+
return;
427+
}
428+
405429
const originX = e.offsetX;
406430
const originY = e.offsetY;
407431

@@ -492,6 +516,23 @@ interface WheelEventWithLegacyPerAxis extends WheelEvent {
492516
wheelDeltaY?: number
493517
}
494518

519+
/** Whether the wheel event exposes per-axis deltas (false on pre-2013 IE). */
520+
function hasPerAxisInfo(nativeEvent: WheelEvent | null): nativeEvent is WheelEvent {
521+
return !!nativeEvent && nativeEvent.deltaY != null;
522+
}
523+
524+
/**
525+
* Whether the requested axis carries any wheel delta.
526+
*/
527+
function axisHasDelta(
528+
nativeEvent: WheelEvent | null, axis: WheelAxisType
529+
): boolean {
530+
if (!hasPerAxisInfo(nativeEvent)) {
531+
return true;
532+
}
533+
return axisWheelDelta(nativeEvent, axis) !== 0;
534+
}
535+
495536
/**
496537
* Per-axis equivalent of zrender's `getWheelDeltaMayPolyfill` + `/120`
497538
* normalization. Returns a value on the same scale as `wheelDelta`
@@ -551,7 +592,7 @@ function axisScrollDelta(
551592
axis: WheelAxisType,
552593
fallback: number
553594
): number {
554-
if (!nativeEvent || nativeEvent.deltaY == null) {
595+
if (!hasPerAxisInfo(nativeEvent)) {
555596
return fallback;
556597
}
557598
return ladderScrollDelta(axisWheelDelta(nativeEvent, axis));
@@ -566,7 +607,7 @@ function axisZoomScale(
566607
axis: WheelAxisType,
567608
fallback: number
568609
): number {
569-
if (!nativeEvent || nativeEvent.deltaY == null) {
610+
if (!hasPerAxisInfo(nativeEvent)) {
570611
return fallback;
571612
}
572613
return ladderZoomScale(axisWheelDelta(nativeEvent, axis));

0 commit comments

Comments
 (0)