Skip to content

fix(dataZoom): keep boundary neighbors for line series so partial segments and null gaps survive#21636

Open
JamesGoslings wants to merge 1 commit into
apache:masterfrom
JamesGoslings:fix/21564-21565-line-partial-segment
Open

fix(dataZoom): keep boundary neighbors for line series so partial segments and null gaps survive#21636
JamesGoslings wants to merge 1 commit into
apache:masterfrom
JamesGoslings:fix/21564-21565-line-partial-segment

Conversation

@JamesGoslings
Copy link
Copy Markdown

Brief Information

This pull request is in the type of:

  • bug fixing
  • new feature
  • others

What does this PR do?

When dataZoom filters a line series with the default filterMode: 'filter', keep one neighboring data row on each side of the in-window range so partial line segments at the boundary can still be drawn and null gap markers outside the window still interrupt the line.

Fixed issues

Details

Before: What was the problem?

Both bugs share one root cause. AxisProxy.filterData() calls seriesData.selectRange(), which physically drops every row whose value falls outside the data zoom window. For line / area series this corrupts the rendering in two ways:

#21564 — partial line segments vanish at the boundary.
When a segment connects an in-window point with an out-of-window point, the out-of-window endpoint is removed and the line view loses the entire segment instead of clipping it. The result is that any line crossing the visible edge disappears completely.

#21565 — null gap markers stop interrupting the line.
When a null row's value sits outside the window, the row is dropped from the filtered store and the line view never sees the gap marker. With non-monotonic data, the line view then connects two rows that should remain interrupted, drawing a "ghost line".

After: How does it behave after the fixing?

For line / area series only (subType === 'line') and only when filterMode === 'filter', swap selectRange() for a boundary-aware filter:

Keep row i if row i, row i-1 or row i+1 is in the window.

A single Uint8Array pre-scan computes inWindow status; filterSelf then applies the keep predicate in one pass. Other series types (bar, scatter, ...) and other filter modes (none, empty, weakFilter) are completely untouched, so the fast selectRange path remains the default for everything that does not need this.

With the fix:

  • The boundary points just outside the window are retained, so segments crossing the edge still draw their visible portion (clip path takes care of the cropping).
  • A null row whose raw-order neighbor is in the window is retained, so it still breaks the line and prevents ghost connections.

The visible-y extent on auto-fit Y axes may extend slightly to include the boundary points' Y values; this is necessary because the partial segment's clipping line can reach those Y values, and without the wider extent the segment would be clipped along the Y dimension as well.

Tests

test/ut/spec/component/dataZoom/lineBoundary.test.ts adds five unit tests covering:

  • #21564: window [3, 13] against [(0,5), (2,6), (8,5), (12,5), (16,6)] → kept raw indices [1, 2, 3, 4] (the two boundary neighbors are now retained).
  • #21565: window [3, 10] against [(4,5), (7,5), (11,5), (11,null), (6,6), (9,6)] → all six rows retained, so the null still breaks the line.
  • bar series: behavior unchanged (no boundary keeping).
  • filterMode: 'none': behavior unchanged.
  • All-in-window: short-circuited, no extra work.

test/line-dataZoom-boundary.html is a visual reproducer for both issues so reviewers can pan the chart and verify the rendering directly.

Full unit suite: 26 suites, 197 tests, all green.

Document Info

  • This PR doesn't relate to document changes
  • The document should be updated later
  • The document changes have been made in apache/echarts-doc#xxx

Misc

Security Checking

  • This PR uses security-sensitive Web APIs.

ZRender Changes

  • This PR depends on ZRender changes (ecomfe/zrender#xxx).

Related test cases or examples to use the new APIs

  • test/ut/spec/component/dataZoom/lineBoundary.test.ts — unit tests
  • test/line-dataZoom-boundary.html — visual reproducer

Merging options

  • Please squash the commits into a single one when merging.

Other information

A few related rendering features were not exhaustively visually verified and are worth a reviewer's eye:

  • endLabel on a line series with dataZoom: with the fix, the last filtered row may be a boundary point sitting just outside the window. The label would either be clipped or rendered just past the chart edge depending on how endLabel is positioned. If this turns out to need adjusting, it can be a follow-up.
  • markPoint with type: 'max' / 'min': same caveat — these may now match a boundary point.

For the bugs as reported, both reproductions render correctly with the fix applied.

@echarts-bot
Copy link
Copy Markdown

echarts-bot Bot commented May 29, 2026

Thanks for your contribution!
The community will review it ASAP. In the meanwhile, please checkout the coding standard and Wiki about How to make a pull request.

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.

…al segments and null gaps survive. close apache#21564, close apache#21565

When dataZoom uses the default filterMode 'filter', AxisProxy calls
selectRange() on the series store, which physically drops every row
whose value falls outside the window. For line / area series this
corrupts the rendering in two ways:

  - A line segment that crosses the window boundary loses one of its
    endpoints, so the visible portion of the segment vanishes
    entirely (apache#21564).
  - A null data point that interrupts the line gets dropped if its
    own value sits outside the window, so the line view no longer
    sees the gap and connects across it as a ghost line (apache#21565).
    This is most visible when data is non-monotonic in the filter
    dimension and the null is the only signal that two adjacent rows
    belong to different segments.

Replace selectRange with a boundary-aware filter for line subType
only: keep row i when row i, row i-1 or row i+1 is in the window.
A single Uint8Array pre-scan computes inWindow status; filterSelf
then applies the keep predicate. Other series types and other filter
modes are untouched.

Adds unit coverage for the partial-segment case, the null-gap case,
the bar-series no-op, the filterMode: 'none' no-op, and the
all-in-window short-circuit. Adds a visual reproducer at
test/line-dataZoom-boundary.html.
@JamesGoslings JamesGoslings force-pushed the fix/21564-21565-line-partial-segment branch from 4cc086f to 5d8e7cd Compare May 29, 2026 18:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Interrupted lines can draw ghost lines [Bug] Line chart drops partially visible lines entirely

1 participant