Skip to content

feat: Zoom for cartesian charts - #216

Draft
georgylobko wants to merge 9 commits into
mainfrom
feat/zoom
Draft

feat: Zoom for cartesian charts#216
georgylobko wants to merge 9 commits into
mainfrom
feat/zoom

Conversation

@georgylobko

@georgylobko georgylobko commented May 5, 2026

Copy link
Copy Markdown
Member

Description

Zoom functionality for cartesian charts.

Screen.Recording.2026-07-01.at.9.30.32.PM.mov

Related links, issue #, if available: n/a

How has this been tested?

Review checklist

The following items are to be evaluated by the author(s) and the reviewer(s).

Correctness

  • Changes include appropriate documentation updates.
  • Changes are backward-compatible if not indicated, see CONTRIBUTING.md.
  • Changes do not include unsupported browser features, see CONTRIBUTING.md.
  • Changes were manually tested for accessibility, see accessibility guidelines.

Security

Testing

  • Changes are covered with new/existing unit tests?
  • Changes are covered with new/existing integration tests?

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@georgylobko
georgylobko requested a review from a team as a code owner May 5, 2026 09:14
@georgylobko
georgylobko requested review from avinashbot and removed request for a team and avinashbot May 5, 2026 09:14
@georgylobko
georgylobko marked this pull request as draft May 5, 2026 09:14
@georgylobko
georgylobko force-pushed the feat/zoom branch 2 times, most recently from 47cf11f to 1136df3 Compare July 1, 2026 21:34
@georgylobko georgylobko changed the title feat: Zoom and navigator feat: Zoom for cartesian charts Jul 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds end-user zoom interactions to the CartesianChart component, including drag-to-zoom and an accessible “zoom mode” with keyboard/pointer alternatives, plus the necessary API surface, styling, and tests to support it.

Changes:

  • Introduces zoom, zoomRange, and onZoomRangeChange props, plus ref methods (enterZoomMode, exitZoomMode, resetZoom) for programmatic control.
  • Implements zoom-mode UI/overlays (selection band, cursor/range dividers, portal-rendered cursor buttons) and controlled/uncontrolled zoom behaviors.
  • Adds comprehensive unit tests and a dev page demonstrating uncontrolled vs controlled zoom usage.

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/test-utils/dom/cartesian-chart/index.ts Extends CartesianChart test wrapper with zoom-control finders (including portal-rendered cursor buttons).
src/internal/components/zoom-cursor-buttons/test-classes/styles.scss Adds test-only selectors for zoom cursor direction buttons.
src/internal/components/zoom-cursor-buttons/styles.scss Adds styling for portal overlay and cursor direction buttons.
src/internal/components/zoom-cursor-buttons/portal-overlay.tsx New portal overlay component to align cursor controls with a tracked element.
src/internal/components/zoom-cursor-buttons/direction-button.tsx New direction button component used by zoom cursor controls.
src/core/styles.scss Adds cursor styling for Highcharts navigator mask while dragging.
src/core/interfaces.ts Extends cartesian i18n strings with zoom-related labels and announcements.
src/cartesian-chart/test-classes/styles.scss Adds test selectors for zoom-related buttons.
src/cartesian-chart/styles.scss Adds zoom controls positioning and selection-band/cursor-track styles.
src/cartesian-chart/interfaces.ts Adds public zoom props (zoom, zoomRange) and zoom ref methods/events.
src/cartesian-chart/chart-cartesian-internal.tsx Implements zoom mode state machine, overlays, keyboard/mouse interactions, and controlled/uncontrolled zoom handling.
src/cartesian-chart/tests/cartesian-chart-zoom.test.tsx Adds unit tests covering zoom UI states, keyboard interactions, drag dividers, controlled mode, and i18n.
src/tests/snapshots/documenter.test.ts.snap Updates API snapshot for new zoom props/events/ref methods and i18n strings.
pages/common/use-highcharts.ts Refactors parameter typing/formatting (no functional change).
pages/01-cartesian-chart/zoom.page.tsx Adds dev page demonstrating zoom behaviors and controlled/uncontrolled patterns.
pages/01-cartesian-chart/axes-and-thresholds.page.tsx Reorders imports after adding the new zoom page (formatting-only).
.gitignore Ignores common IDE directories (.idea, .vscode).
Suppressed comments (2)

src/cartesian-chart/chart-cartesian-internal.tsx:839

  • zoomed is derived using truthiness (!!(e.userMin || e.userMax)), which misclassifies a zoom when either extreme is 0 (valid value). This can cause zoom-reset logic to run incorrectly for ranges that start/end at 0.
                        const zoomed = !!(e.userMin || e.userMax);

src/cartesian-chart/chart-cartesian-internal.tsx:679

  • This effect attaches the keydown listener to the global document, which breaks when the chart is rendered in a different document (e.g. iframe) and can also make cleanup run against the wrong document. Use the chart container's ownerDocument instead.
      document.addEventListener("keydown", onKeyDown);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +359 to +363
if (props.zoomRange === undefined) {
xAxis?.setExtremes(min, max);
setZoomMode("zoomed");
setZoomedExtremes({ min, max });
}
Comment on lines +51 to +58
if (track.current && ref.current && document.body.contains(ref.current)) {
const isRtl = getIsRtl(ref.current);
const { insetInlineStart, insetBlockStart, inlineSize, blockSize } = getLogicalBoundingClientRect(
track.current,
);
const newX = (insetInlineStart + getScrollInlineStart(document.documentElement)) * (isRtl ? -1 : 1);
const newY = insetBlockStart + document.documentElement.scrollTop;
if (lastX !== newX || lastY !== newY) {
Comment on lines +798 to +802
// Move the cursor-tracking element into the chart container, so the direction buttons can be
// positioned relative to the plot through the portal overlay.
if (cursorTrackRef.current && !api.chart.container.contains(cursorTrackRef.current)) {
api.chart.container.style.position = "relative";
api.chart.container.appendChild(cursorTrackRef.current);
Comment on lines +581 to +585
document.addEventListener("mouseup", onMouseUp);

return () => {
disposed = true;
document.removeEventListener("mouseup", onMouseUp);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants