feat(dataZoom): add per-axis wheel pan/zoom options for 'inside' dataZoom#21588
feat(dataZoom): add per-axis wheel pan/zoom options for 'inside' dataZoom#21588takaebato wants to merge 2 commits intoapache:masterfrom
Conversation
|
Thanks for your contribution! Please DO NOT commit the files in dist, i18n, and ssr/client/dist folders in a non-release pull request. These folders are for release use only. Document changes are required in this PR. Please also make a PR to apache/echarts-doc for document changes and update the issue id in the PR description. When the doc PR is merged, the maintainers will remove the |
Justin-ZS
left a comment
There was a problem hiding this comment.
Thanks, the API split between modifier gating and wheel-axis gating is clean, and the manual coverage is thoughtful. I found one blocking interaction issue, though: when the wheel direction does not match moveOnMouseWheelAxis / zoomOnMouseWheelAxis, the dataZoom becomes a no-op but the wheel event is still consumed in RoamController, so ordinary page/container scrolling is blocked. I think that axis filtering needs to happen before eventTool.stop() so non-matching wheel input can fall through.
| this._checkTriggerMoveZoom(this, 'zoom', 'zoomOnMouseWheel', e, { | ||
| scale: scale, originX: originX, originY: originY, isAvailableBehavior: null | ||
| scale: scale, | ||
| scaleX: axisZoomScale(nativeEvent, 'horizontal', 1), |
There was a problem hiding this comment.
With moveOnMouseWheelAxis: 'horizontal' / zoomOnMouseWheelAxis: 'horizontal', a plain vertical wheel becomes a no-op in InsideZoomView (effectiveDelta === 0 / effectiveScale === 1). But the event is still consumed later in _checkTriggerMoveZoom(), so the page/container can no longer scroll. That turns an axis mismatch from "ignored" into "blocked". Could we move the axis check earlier so non-matching wheel directions fall through like the existing modifier-gated cases do?
There was a problem hiding this comment.
Thanks! I hadn't considered that the event is consumed even when the axis doesn't match. Let me think through the right place to hoist the check and I'll follow up.
There was a problem hiding this comment.
Fixed in 80bda33.
The axis check is now hoisted into RoamController._mousewheelHandler, so non-matching wheel directions fall through to the browser.
I also tightened mergeControllerParams to forward each dataZoom's actual zoomOnMouseWheel / moveOnMouseWheel truthiness instead of fixing both to true.
As a side effect, this also resolves a long-standing case where wheel events were stop()ped even when every inside dataZoom had zoomOnMouseWheel: false and moveOnMouseWheel: false — i.e. the wheel was being captured even when no dataZoom would do anything with it.
Note: modifier-mismatched wheel events (e.g. zoomOnMouseWheel: 'shift' with shift not held) exhibit the same shape of issue and are out of scope here.
I'm planning a follow-up PR that extends the modifier API into a more flexible form (possibly an object form like { shift: true, ctrl: false }) to address the requests in #18365 — that change should naturally resolve the modifier-mismatch fall-through too.
Panel E in test/dataZoom-inside-wheel-axis.html is a quick visual check: a plain vertical wheel over the chart should now scroll the page.
There was a problem hiding this comment.
A separate API design question: would it make sense to let callers express the "no restriction" state while keeping the field present?
There seem to be a couple of independent dimensions to consider:
- Whether to add an explicit literal (e.g.
'all', or'both') - Whether to admit
null/undefinedin the type
Some existing precedents in echarts I found:
NullUndefinedonlyLine 1081 in c8adaf4
- both
echarts/src/coord/cartesian/GridModel.ts
Line 65 in c8adaf4
Line 770 in c8adaf4
So some candidate shapes might be:
// (a) literal only
moveOnMouseWheelAxis?: 'horizontal' | 'vertical' | 'all'
// (b) NullUndefined only
moveOnMouseWheelAxis?: 'horizontal' | 'vertical' | NullUndefined
// (c) both (matches outerBoundsMode / ModelFinderIndexQuery shape)
moveOnMouseWheelAxis?: 'horizontal' | 'vertical' | 'all' | NullUndefined
// (d) keep as-is
moveOnMouseWheelAxis?: 'horizontal' | 'vertical'(b) is the minimal way to let callers keep the field present in the no-restriction state.
That said, (c) might also be a good fit since it aligns with the established outerBoundsMode / ModelFinderIndexQuery shape.
Happy with whichever direction.
Brief Information
This pull request is in the type of:
What does this PR do?
Adds
moveOnMouseWheelAxisandzoomOnMouseWheelAxisoptions that restrict an inside dataZoom to a single wheel axis, so horizontal and vertical wheel components can drive different dataZooms independently.Fixed issues
Details
Before: What was the problem?
deltaXanddeltaYinto a singlewheelDeltascalar, so the horizontal and vertical components of a wheel event can't be directed to different dataZooms
separately.
After: How does it behave after the fixing?
RoamController's'zoom'and'scrollMove'events now carry per-axis fields (scaleX/scaleY,scrollDeltaX/scrollDeltaY) alongside the existingscale/scrollDeltascalars. Per-axis values arepolyfilled from the native
WheelEventwhendeltaX/deltaYare available; pre-2013 IE falls back tocaller-supplied defaults. Touch pinch mirrors the scalar into both per-axis fields since it has no distinct
direction.
dataZoom.inside:moveOnMouseWheelAxis?: 'horizontal' | 'vertical'— pin the pan to a single wheel axis.zoomOnMouseWheelAxis?: 'horizontal' | 'vertical'— pin the zoom to a single wheel axis.Document Info
One of the following should be checked.
Misc
Security Checking
ZRender Changes
The per-axis values are read directly from the native
WheelEvent(viae.event.deltaX/.deltaY, with a fallback tothe legacy WebKit
wheelDeltaX/wheelDeltaY), so zrender's scalarwheelDeltaAPI stays untouched and no companion zrender PR is needed.Related test cases or examples to use the new APIs
test/dataZoom-inside-wheel-axis.html(added in this PR) — 11 manual panels covering the default fallback,moveOnMouseWheelAxis/zoomOnMouseWheelAxiswith various axis configs, zoom / pan composition, shift-basedhorizontal scroll, and polar coordinate systems.
Merging options
Other information
Relation to #18365. Same underlying problem (zrender's
wheelDeltacollapses both wheel axes into a single scalar, so horizontal and vertical inputs can't be routed separately), different API. Rather than extendingmoveOnMouseWheel/zoomOnMouseWheelwith composite values like'x+shift'/'y+none', this PR splits the concern in two:moveOnMouseWheelAxis/zoomOnMouseWheelAxis— which wheel axis drives the dataZoom.moveOnMouseWheel/zoomOnMouseWheel— under which modifier state the action fires.Keeping the two orthogonal means axis restriction composes cleanly with any existing modifier mode, without a
combinatorial explosion of composite strings. The
'none'modifier value also mentioned in that issue is out ofscope here and can follow separately.
Touch pinch. Axis restriction applies only to wheel-driven pan / zoom. Touch pinch keeps zooming on every dataZoom
regardless of the axis restriction setting — a touch pinch is a 2D gesture with no distinct horizontal / vertical
component.
Future work. This is independent of the axis API introduced in this PR, but a follow-up is planned to tackle
the magnitude side. The
FIXMEinRoamControllersits on a 3-tier heuristic that ignoresdeltaMode, still carries the IE-era/ 120division, and feels a bit fast on some setups. The plan is to derive the magnitude from the nativeWheelEventdirectly, retire theFIXME, and add awheelSensitivityoption.