Skip to content

[Bug] Candlestick series does not clip to grid in multi-grid layout even with clip: true #21627

@wplong11

Description

@wplong11

Version

5.5.0

Link to Minimal Reproduction

https://wplong11.github.io/echarts-candlestick-clip-bug/

Source

Image

Steps to Reproduce

  1. Open the reproduction link above — it shows two vertically stacked grids (Grid 0: line, Grid 1: candlestick), with a y-axis dataZoom (start: 30, end: 70) on Grid 1 and filterMode: 'none'.
  2. Observe that candlestick wicks from Grid 1 bleed upward into Grid 0's area, even though both series have clip: true.
  3. Click "Toggle filterMode" to switch to filterMode: 'empty' — the bleed disappears immediately.
  4. Click "Toggle y-axis zoom" to reset the y-axis zoom to full range — no bleed either.

Current Behavior

Candlestick wicks extend beyond Grid 1's boundary and render into Grid 0's area. Setting clip: true on the candlestick series has no effect in normal (non-large) rendering mode.

This happens because CandlestickView.render() unconditionally calls group.removeClipPath() (CandlestickView.ts:52), and then relies solely on a per-item isNormalBoxClipped() check (CandlestickView.ts:276-286). That check uses clipArea.contain() against each of the candlestick's ends points — if any point is inside the grid, the entire candlestick is rendered without pixel-level clipping. So a candle whose body is inside the grid but whose wick extends beyond passes the check and draws outside the grid boundary.

By contrast, LineView and BarView both prevent rendering outside the grid in normal mode, albeit via different mechanisms:

  • LineView.ts:744, 775 — applies group.setClipPath() (canvas-level pixel clipping)
  • BarView.ts:222-273 — modifies bar layout geometry via clip[coord.type]() to truncate shapes at the grid boundary (no canvas clip in normal mode, but the layout modification achieves the same visual result)

Candlestick does neither: it removes the canvas clip path and relies solely on the all-or-nothing per-item visibility check, making it the only standard series type where clip: true does not actually prevent rendering outside the grid.

Expected Behavior

Candlestick wicks and bodies should be clipped at the grid boundary when clip: true is set, consistent with how line and bar series behave. In the reproduction, Grid 1's candles should never render pixels outside Grid 1's area.

Environment

- OS: macOS Sequoia 15.5
- Browser: Chrome 137
- Framework: N/A (vanilla HTML, also reproduced in React Native WebView)

Any additional comments?

Root cause summary

What File (v5.5.0) Line
Normal mode removes clip path CandlestickView.ts 52
Per-item contain check (show-or-hide, not pixel clip) CandlestickView.ts 276-286
Large mode does apply setClipPath CandlestickView.ts 174-179
Grid clip rect helper createClipPathFromCoordSys.ts 32-105

Workaround

Setting dataZoom.filterMode: 'empty' instead of 'none' on the y-axis works around the issue. In 'empty' mode, AxisProxy converts out-of-range data to NaN (AxisProxy.ts:333-338), which causes the data.hasValue() check to skip those items entirely. However, this changes data semantics and may not always be acceptable.

Suggested fix

Apply group.setClipPath(createClipPathFromCoordSys(...)) in candlestick normal mode when clip: true, similar to how LineView applies canvas-level clipping. The per-item isNormalBoxClipped check could be kept as an optimization to avoid rendering items that are entirely outside the clip area, but the canvas-level clip path is needed to handle partial overflow (body inside, wick outside).

Related issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    enThis issue is in EnglishpendingWe are not sure about whether this is a bug/new feature.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions