Skip to content

[Feature] getRelativeCoordinate#6942

Merged
ckifer merged 10 commits into
mainfrom
getRelativeCoordinate
Feb 3, 2026
Merged

[Feature] getRelativeCoordinate#6942
ckifer merged 10 commits into
mainfrom
getRelativeCoordinate

Conversation

@PavelVanecek

@PavelVanecek PavelVanecek commented Jan 31, 2026

Copy link
Copy Markdown
Collaborator

Description

Exports new function: getRelativeCoordinate. This function computes relative element coordinates from mouse or touch event.

Changes:

Renamed getChartPointer to getRelativeCoordinate

I figured that this function does not actually return chart-relative coordinates, it returns coordinates relative to whatever was the currentTarget. Which internally we always pass the chart element, but once we export and make it public API that may not be the case. So I renamed the function and renamed properties in the return value as well.

Added support for SVG elements

Internally we always pass HTML elements but Recharts is a mix of HTML and SVG so let's make it easy so that as a dev I don't need to think which context I am in.

Added support for touch and multi-touch

It would be nice if we could support both mouse and touch wouldn't it. So now we do. Touch events return an array because the user can use multiple pointing devices (aka fingers) at the same time.

Fixed the currentTarget bug

There was a problem where browsers only keep reference to the event.currentTarget in the main event loop. This is usually no big deal unless you happen to process these events asynchronously which is exactly what we do. So I added a proxy so that we can cache the latest currentTarget and return it if needed. getRelativeCoordinate does need it indeed.

Fixed Legend re-render bug

Legend was re-rendering and resetting its own size which usually wasn't noticeable because of batched actions. But it did interrupt touch gestured so I added React.memo which fixed it.

Also added VR test and website example.

Related Issue

#6021

#1678

Screenshots (if appropriate):

https://recharts.github.io/recharts/pr-6942/www/en-US/api/getRelativeCoordinate/

Desktop:

Screen.Recording.2026-01-31.at.23.50.04.mov

Android multi-touch:

screen-20260131-231109-1769868659939.2.mp4

iOS multi-touch:

ScreenRecording_01-31-2026.23-15-56_1.mp4

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or VR test, or extended an existing story or VR test to show my changes

@coderabbitai

coderabbitai Bot commented Jan 31, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Introduces a new coordinate system (RelativePointer) replacing ChartPointer, adds event proxy and React component detection utilities, refactors pointer types for HTML/SVG distinction, makes chart callback types generic, memoizes Legend component, and migrates coordinate calculations throughout the codebase.

Changes

Cohort / File(s) Summary
Event Handling Utilities
src/util/createEventProxy.ts
New utility that wraps React SyntheticEvents in a Proxy to preserve currentTarget across async operations and lazily bind function properties.
Coordinate System Migration
src/util/getRelativeCoordinate.ts, src/util/types.ts
Introduces RelativePointer type with relativeX/relativeY properties; adds getRelativeCoordinate function supporting HTML/SVG elements and touch events; refactors MousePointer/TouchPointer into HTML/SVG variants with proper currentTarget typing.
Pointer Type Deprecation
src/util/getChartPointer.ts
Removes deprecated getChartPointer utility and associated test suite.
React Component Detection
omnidoc/isReactComponent.ts, omnidoc/isReactComponent.spec.ts
New utility function to identify React components by uppercase naming convention with hardcoded exclusion list; includes comprehensive test coverage.
Generic Event Typing
src/chart/types.ts, src/state/externalEventsMiddleware.ts
Makes CategoricalChartFunc generic over event type; updates ExternalMouseEvents handlers with specific MouseEvent/TouchEvent types; parameterizes ExternalEventActionPayload for event typing.
Middleware Updates
src/state/mouseEventsMiddleware.ts, src/state/touchEventsMiddleware.ts, src/state/externalEventsMiddleware.ts
Replaces getChartPointer with getRelativeCoordinate; integrates createEventProxy for event handling; updates type references from ChartPointer to RelativePointer.
Selector Refactoring
src/state/selectors/axisSelectors.ts
Renames combineXAxisRange/combineYAxisRange to selectXAxisRange/selectYAxisRange for consistency.
Pointer Coordinate Updates
src/state/selectors/selectActivePropsFromChartPointer.ts, src/state/selectors/selectors.ts, src/util/ChartUtils.ts, src/util/PolarUtils.ts, src/util/getActiveCoordinate.ts
Propagates RelativePointer type replacing ChartPointer; updates destructuring and property access from chartX/chartY to relativeX/relativeY.
Component Memoization
src/component/Legend.tsx
Wraps Legend component with React.memo using propsAreEqual comparator for performance optimization.
Public API Exports
src/index.ts
Exposes RelativePointer type and getRelativeCoordinate function; re-exports pointer type variants (MousePointer, TouchPointer, SVG/HTML variants).
Omnidoc Improvements
omnidoc/readProject.ts, omnidoc/generateApiDoc.spec.ts
Refactors component/hook identification to use isReactComponent predicate; improves JSDoc extraction for variable declarations; exposes simplifyOneType utility.
Documentation & Examples
www/src/docs/apiExamples/getRelativeCoordinate/*, www/src/docs/exampleComponents/AreaChart/AreaChartWithCustomEvents.tsx, www/src/docs/apiCates.ts
Adds comprehensive examples demonstrating getRelativeCoordinate usage with crosshair overlay; adds event handler examples showing proper typing with custom event handlers.
Snapshot & Test Updates
scripts/snapshots/*, test/util/getRelativeCoordinate.spec.ts, test/state/externalEventsMiddleware.spec.ts
Updates file snapshots to reflect new utilities; adds comprehensive test suite for getRelativeCoordinate covering HTML/SVG and touch scenarios; extends external events middleware tests with event proxy verification.
API Documentation Tests
omnidoc/verifyExamples.spec.ts
Adds new pointer type exports to list of items requiring documentation examples.
Test Utilities
omnidoc/readProject.spec.ts
Expands function comment extraction test coverage with function argument scenario.

Sequence Diagram

sequenceDiagram
    participant React
    participant Handler as Event Handler
    participant Middleware
    participant EventProxy as Event Proxy
    participant Coordinate as getRelativeCoordinate
    
    React->>Handler: Fire Mouse/Touch Event
    Handler->>Middleware: Dispatch externalEventAction(payload)
    Note over Handler,Middleware: payload contains original SyntheticEvent
    
    Middleware->>EventProxy: createEventProxy(reactEvent)
    Note over EventProxy: Persist event, capture currentTarget
    
    EventProxy->>Middleware: Return proxied event
    Middleware->>Middleware: Store { handler, reactEvent: proxy }
    
    Note over Middleware: Async throttled processing
    Middleware->>Coordinate: getRelativeCoordinate(proxiedEvent)
    
    Coordinate->>Coordinate: Detect SVG vs HTML element
    Coordinate->>Coordinate: Calculate scale from getBBox() or offsetWidth
    Coordinate->>Coordinate: Compute relativeX/Y from clientX/Y
    
    Coordinate->>Middleware: Return RelativePointer
    Middleware->>Handler: Invoke handler with coordinates
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • #6634: Modifies externalEventsMiddleware.ts and Legend component memoization in parallel.
  • #6750: Updates same utility files (getActiveCoordinate.ts, ChartUtils.ts, axisSelectors.ts) for pointer coordinate migration.
  • #6582: Refactors omnidoc's readProject.ts component discovery logic similarly using new predicates.

Suggested labels

typescript, documentation, refactoring, event-handling

Suggested reviewers

  • ckifer
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title '[Feature] getRelativeCoordinate' directly and concisely describes the primary change—a new public function export.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering all key changes, motivation, related issues, testing approach, and checklist completion.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch getRelativeCoordinate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/state/externalEventsMiddleware.spec.ts (1)

11-19: ⚠️ Potential issue | 🟡 Minor

Initialize fake timers before timer assertions.

vi.getTimerCount() and vi.runOnlyPendingTimers() expect fake timers; add vi.useFakeTimers() (and restore) in setup.

🔧 Proposed change
-import { describe, it, expect, vi, beforeEach } from 'vitest';
+import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
@@
   beforeEach(() => {
+    vi.useFakeTimers();
     store = createRechartsStore();
     mockHandler = vi.fn();
@@
     vi.clearAllTimers();
   });
+
+  afterEach(() => {
+    vi.useRealTimers();
+  });

Based on learnings: Applies to test/**/*.{test,spec}.{ts,tsx} : Use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame.

🤖 Fix all issues with AI agents
In `@src/state/externalEventsMiddleware.ts`:
- Line 20: The action creator externalEventAction is using the forbidden any
type via ExternalEventActionPayload<any>; change the generic to a safe event
type (e.g., ExternalEventActionPayload<SyntheticEvent>) or rely on the payload's
default generic so it doesn't infer any, and update the createAction call
accordingly (target symbols: externalEventAction, ExternalEventActionPayload,
createAction) to remove any usage of `any`.

In `@src/util/createEventProxy.ts`:
- Around line 3-18: Add a JSDoc comment for the exported createEventProxy<T
extends SyntheticEvent>(reactEvent: T) function describing its purpose,
parameters, return type, and behavior (it persists the React event, caches
currentTarget, and returns a Proxy that binds function properties and returns
cached currentTarget); then add unit tests for createEventProxy in the util test
suite that (1) confirm currentTarget is cached and accessible after simulated
React event lifecycle, (2) verify function properties accessed via the proxy are
bound to the original event, and (3) ensure non-function/non-currentTarget
properties are delegated to the original event; update or import the test helper
to simulate event persistence behavior used by
src/state/externalEventsMiddleware.ts and src/state/touchEventsMiddleware.ts.

In `@test/util/getRelativeCoordinate.spec.ts`:
- Around line 1-13: This spec needs fake-timer setup/teardown: add
vi.useFakeTimers() in a beforeEach and vi.useRealTimers() in an afterEach (or
afterAll) so tests calling getRelativeCoordinate and helpers like getMockDomRect
run under fake timers (avoiding real requestAnimationFrame/timers from Redux
autoBatchEnhancer); locate the top of the describe block in
getRelativeCoordinate.spec.ts and add the setup/teardown hooks surrounding the
tests.

In `@www/src/docs/exampleComponents/AreaChart/AreaChartWithCustomEvents.tsx`:
- Around line 61-72: The touch handlers onTouchStart, onTouchMove and onTouchEnd
call getRelativeCoordinate which is declared to return Array<RelativePointer>,
but the code types the result as ReadonlyArray<RelativePointer>; update the type
annotation to Array<RelativePointer> to match getRelativeCoordinate’s signature
(or if you intentionally want an immutable view, add a comment explaining that
choice and keep a defensive readonly cast), ensuring the variable declaration in
each handler uses Array<RelativePointer> to resolve the mismatch with
getRelativeCoordinate.
🧹 Nitpick comments (3)
omnidoc/isReactComponent.ts (1)

15-18: Consider moving the constant outside the function.

NON_COMPONENT_EXPORTS is re-created on every function call. For a minor performance improvement, consider hoisting it to module scope.

♻️ Suggested refactor
+// Known non-component exports that happen to be Capitalized
+const NON_COMPONENT_EXPORTS = ['DefaultZIndexes', 'Global'];
+
 export function isReactComponent(name: string): boolean {
   // Must start with uppercase
   if (!/^[A-Z]/.test(name)) {
     return false;
   }

-  // Known non-component exports that happen to be Capitalized
-  const NON_COMPONENT_EXPORTS = ['DefaultZIndexes', 'Global'];
   if (NON_COMPONENT_EXPORTS.includes(name)) {
     return false;
   }

   return true;
 }
storybook/stories/Examples/Pie/DraggablePie.stories.tsx (1)

24-30: Type assertion needed for getRelativeCoordinate return value.

getRelativeCoordinate(e) returns RelativePointer | Array<RelativePointer>. Direct destructuring assumes a single object, which works for mouse events but TypeScript may flag this as a type error.

Consider adding explicit type handling:

♻️ Proposed type-safe destructuring
 function computeAngle(cx: number, cy: number, e: React.MouseEvent<SVGGraphicsElement>): number {
-  const { relativeX, relativeY }: RelativePointer = getRelativeCoordinate(e);
+  const result = getRelativeCoordinate(e);
+  const { relativeX, relativeY } = Array.isArray(result) ? result[0] : result;
   const deltaX = relativeX - cx;
   const deltaY = relativeY - cy;
test/state/selectors/selectors.spec.tsx (1)

1158-1166: Use expectLastCalledWith for the last-call assertion.

🔧 Proposed change
-    expect(tooltipActiveSpy).toHaveBeenLastCalledWith({
+    expectLastCalledWith(tooltipActiveSpy, {
       activeCoordinate: {
         x: 5,
         y: 10,
       },
       activeIndex: '0',
-    });
+    });

Based on learnings: Applies to test/**/*.{test,spec}.{ts,tsx} : Use the expectLastCalledWith helper function instead of expect(spy).toHaveBeenLastCalledWith(...) for better typing and autocompletion.

};

export const externalEventAction = createAction<ExternalEventActionPayload>('externalEvent');
export const externalEventAction = createAction<ExternalEventActionPayload<any>>('externalEvent');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Avoid using any type.

The action creator uses ExternalEventActionPayload<any> which violates the coding guideline. Since SyntheticEvent is the base type for all React events (including MouseEvent and TouchEvent), you can use the default type parameter or explicitly specify SyntheticEvent:

Proposed fix
-export const externalEventAction = createAction<ExternalEventActionPayload<any>>('externalEvent');
+export const externalEventAction = createAction<ExternalEventActionPayload>('externalEvent');

As per coding guidelines: "Never use any type, neither implicitly nor explicitly. Prefer unknown and refine the type."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const externalEventAction = createAction<ExternalEventActionPayload<any>>('externalEvent');
export const externalEventAction = createAction<ExternalEventActionPayload>('externalEvent');
🤖 Prompt for AI Agents
In `@src/state/externalEventsMiddleware.ts` at line 20, The action creator
externalEventAction is using the forbidden any type via
ExternalEventActionPayload<any>; change the generic to a safe event type (e.g.,
ExternalEventActionPayload<SyntheticEvent>) or rely on the payload's default
generic so it doesn't infer any, and update the createAction call accordingly
(target symbols: externalEventAction, ExternalEventActionPayload, createAction)
to remove any usage of `any`.

Comment on lines +3 to +18
export function createEventProxy<T extends SyntheticEvent>(reactEvent: T): T {
reactEvent.persist();
const { currentTarget } = reactEvent;
return new Proxy(reactEvent, {
get: (target, prop) => {
if (prop === 'currentTarget') {
return currentTarget;
}
const value = Reflect.get(target, prop);
if (typeof value === 'function') {
return value.bind(target);
}
return value;
},
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, check if the file exists and read its content
echo "=== Reading src/util/createEventProxy.ts ==="
cat -n src/util/createEventProxy.ts

echo -e "\n=== Searching for test files covering createEventProxy ==="
find . -type f \( -name "*test*" -o -name "*spec*" \) \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" \) -exec rg -l 'createEventProxy' {} \;

echo -e "\n=== Searching for createEventProxy references in entire codebase ==="
rg -l 'createEventProxy' --type ts --type tsx

Repository: recharts/recharts

Length of output: 894


🏁 Script executed:

#!/bin/bash
# Check test directory structure
echo "=== Looking for test files in repo ==="
fd -type f -name "*.test.ts" -o -name "*.test.tsx" -o -name "*.spec.ts" -o -name "*.spec.tsx" | head -20

echo -e "\n=== Checking for createEventProxy in src files ==="
rg 'createEventProxy' --type-list | head -5

echo -e "\n=== Direct search for createEventProxy ==="
grep -r 'createEventProxy' . 2>/dev/null || echo "No matches found"

echo -e "\n=== Check file git status ==="
git log --oneline -- src/util/createEventProxy.ts 2>/dev/null || echo "File may be new/untracked"
</parameter>

Repository: recharts/recharts

Length of output: 1677


🏁 Script executed:

#!/bin/bash
# Check for test structure in repo
echo "=== Looking for test files ==="
find . -path ./node_modules -prune -o -type f \( -name "*.test.ts" -o -name "*.test.tsx" -o -name "*.spec.ts" -o -name "*.spec.tsx" \) -print | head -10

echo -e "\n=== Check test directory existence ==="
ls -la test/ 2>/dev/null || echo "No test/ directory"
ls -la tests/ 2>/dev/null || echo "No tests/ directory"
ls -la __tests__/ 2>/dev/null || echo "No __tests__/ directory"

echo -e "\n=== Look in src for __tests__ or similar ==="
find src -type d -name "*test*" 2>/dev/null | head -5

echo -e "\n=== Check package.json for test script ==="
grep -A 5 '"test"' package.json 2>/dev/null | head -10
</parameter>

Repository: recharts/recharts

Length of output: 2449


🏁 Script executed:

#!/bin/bash
# Check test/util directory for tests
echo "=== Contents of test/util/ ==="
ls -la test/util/

echo -e "\n=== Check for createEventProxy test files ==="
find test/util -type f -name "*createEventProxy*"

echo -e "\n=== Look for any tests in state that might test createEventProxy ==="
ls -la test/state/

echo -e "\n=== Search for any test mentioning createEventProxy ==="
rg 'createEventProxy' test/ 2>/dev/null || echo "No tests found referencing createEventProxy"

Repository: recharts/recharts

Length of output: 3918


🏁 Script executed:

#!/bin/bash
# Check the externalEventsMiddleware test to see if it tests createEventProxy indirectly
echo "=== Check externalEventsMiddleware.spec.ts ==="
head -100 test/state/externalEventsMiddleware.spec.ts

echo -e "\n=== Look for imports and usage patterns ==="
grep -A 10 'createEventProxy' src/state/externalEventsMiddleware.ts

echo -e "\n=== Check if the function has any documentation ==="
head -20 src/util/createEventProxy.ts
</parameter>

Repository: recharts/recharts

Length of output: 4300


Add JSDoc documentation and create unit tests for this utility.

Per coding guidelines, JSDoc comments are required for all src/**/*.{ts,tsx} files as they are used to autogenerate API documentation. Additionally, unit tests are mandatory for utility functions in src/**/util/**/*.{ts,tsx}. This function currently lacks both.

The utility is used in src/state/externalEventsMiddleware.ts and src/state/touchEventsMiddleware.ts to preserve the currentTarget property across async event handling in React 17+. Tests should verify:

  • currentTarget is correctly cached and accessible after the React event lifecycle
  • Function properties are properly bound when accessed through the proxy
  • The proxy correctly delegates to the original event for all other properties
📝 Proposed JSDoc documentation
+/**
+ * Creates a proxy around a React SyntheticEvent that preserves `currentTarget`
+ * for asynchronous access. React nullifies `currentTarget` after the event
+ * callback completes, so this proxy caches it at creation time.
+ *
+ * `@param` reactEvent - The React SyntheticEvent to wrap
+ * `@returns` A proxied event with stable `currentTarget` access
+ */
 export function createEventProxy<T extends SyntheticEvent>(reactEvent: T): T {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function createEventProxy<T extends SyntheticEvent>(reactEvent: T): T {
reactEvent.persist();
const { currentTarget } = reactEvent;
return new Proxy(reactEvent, {
get: (target, prop) => {
if (prop === 'currentTarget') {
return currentTarget;
}
const value = Reflect.get(target, prop);
if (typeof value === 'function') {
return value.bind(target);
}
return value;
},
});
}
/**
* Creates a proxy around a React SyntheticEvent that preserves `currentTarget`
* for asynchronous access. React nullifies `currentTarget` after the event
* callback completes, so this proxy caches it at creation time.
*
* `@param` reactEvent - The React SyntheticEvent to wrap
* `@returns` A proxied event with stable `currentTarget` access
*/
export function createEventProxy<T extends SyntheticEvent>(reactEvent: T): T {
reactEvent.persist();
const { currentTarget } = reactEvent;
return new Proxy(reactEvent, {
get: (target, prop) => {
if (prop === 'currentTarget') {
return currentTarget;
}
const value = Reflect.get(target, prop);
if (typeof value === 'function') {
return value.bind(target);
}
return value;
},
});
}
🤖 Prompt for AI Agents
In `@src/util/createEventProxy.ts` around lines 3 - 18, Add a JSDoc comment for
the exported createEventProxy<T extends SyntheticEvent>(reactEvent: T) function
describing its purpose, parameters, return type, and behavior (it persists the
React event, caches currentTarget, and returns a Proxy that binds function
properties and returns cached currentTarget); then add unit tests for
createEventProxy in the util test suite that (1) confirm currentTarget is cached
and accessible after simulated React event lifecycle, (2) verify function
properties accessed via the proxy are bound to the original event, and (3)
ensure non-function/non-currentTarget properties are delegated to the original
event; update or import the test helper to simulate event persistence behavior
used by src/state/externalEventsMiddleware.ts and
src/state/touchEventsMiddleware.ts.

Comment on lines +1 to +13
import { describe, it, expect } from 'vitest';
import { getRelativeCoordinate } from '../../src';
import { getMockDomRect } from '../helper/mockGetBoundingClientRect';
import {
RelativePointer,
HTMLMousePointer,
SVGMousePointer,
HTMLTouchPointer,
SVGTouchPointer,
} from '../../src/util/types';

describe('getRelativeCoordinate', () => {
describe('with HTML elements', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add fake timers setup for this spec.

This test file should run under fake timers per test guidelines; add setup/teardown to avoid relying on real timers.

🔧 Proposed change
-import { describe, it, expect } from 'vitest';
+import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
 import { getRelativeCoordinate } from '../../src';
 import { getMockDomRect } from '../helper/mockGetBoundingClientRect';
@@
 describe('getRelativeCoordinate', () => {
+  beforeEach(() => {
+    vi.useFakeTimers();
+  });
+
+  afterEach(() => {
+    vi.useRealTimers();
+  });
+
   describe('with HTML elements', () => {

Based on learnings: Applies to test/**/*.{test,spec}.{ts,tsx} : Use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { describe, it, expect } from 'vitest';
import { getRelativeCoordinate } from '../../src';
import { getMockDomRect } from '../helper/mockGetBoundingClientRect';
import {
RelativePointer,
HTMLMousePointer,
SVGMousePointer,
HTMLTouchPointer,
SVGTouchPointer,
} from '../../src/util/types';
describe('getRelativeCoordinate', () => {
describe('with HTML elements', () => {
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { getRelativeCoordinate } from '../../src';
import { getMockDomRect } from '../helper/mockGetBoundingClientRect';
import {
RelativePointer,
HTMLMousePointer,
SVGMousePointer,
HTMLTouchPointer,
SVGTouchPointer,
} from '../../src/util/types';
describe('getRelativeCoordinate', () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
});
describe('with HTML elements', () => {
🤖 Prompt for AI Agents
In `@test/util/getRelativeCoordinate.spec.ts` around lines 1 - 13, This spec needs
fake-timer setup/teardown: add vi.useFakeTimers() in a beforeEach and
vi.useRealTimers() in an afterEach (or afterAll) so tests calling
getRelativeCoordinate and helpers like getMockDomRect run under fake timers
(avoiding real requestAnimationFrame/timers from Redux autoBatchEnhancer);
locate the top of the describe block in getRelativeCoordinate.spec.ts and add
the setup/teardown hooks surrounding the tests.

Comment on lines +61 to +72
onTouchStart={(mouseEventData: MouseHandlerDataParam, event: TouchEvent<SVGGraphicsElement>) => {
const chartPointer: ReadonlyArray<RelativePointer> = getRelativeCoordinate(event);
console.log('AreaChart touch start:', mouseEventData, event, chartPointer);
}}
onTouchMove={(mouseEventData: MouseHandlerDataParam, event: TouchEvent<SVGGraphicsElement>) => {
const chartPointer: ReadonlyArray<RelativePointer> = getRelativeCoordinate(event);
console.log('AreaChart touch move:', mouseEventData, event, chartPointer);
}}
onTouchEnd={(mouseEventData: MouseHandlerDataParam, event: TouchEvent<SVGGraphicsElement>) => {
const chartPointer: ReadonlyArray<RelativePointer> = getRelativeCoordinate(event);
console.log('AreaChart touch end:', mouseEventData, event, chartPointer);
}}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's find and read the target file to see its imports and the code in question
find . -name "AreaChartWithCustomEvents.tsx" -type f

Repository: recharts/recharts

Length of output: 133


🏁 Script executed:

# Also search for getRelativeCoordinate definition
rg "getRelativeCoordinate" -A 3 -B 1

Repository: recharts/recharts

Length of output: 22410


🏁 Script executed:

# Let me view the exact lines 61-72 to confirm the code
sed -n '1,10p' www/src/docs/exampleComponents/AreaChart/AreaChartWithCustomEvents.tsx

Repository: recharts/recharts

Length of output: 233


🏁 Script executed:

# Get the complete imports section and exact lines
head -80 www/src/docs/exampleComponents/AreaChart/AreaChartWithCustomEvents.tsx | tail -50

Repository: recharts/recharts

Length of output: 3157


Align type annotation with actual return type for touch events.

The touch event handlers annotate the return as ReadonlyArray<RelativePointer>, but getRelativeCoordinate returns Array<RelativePointer> according to its overload signature. Change the annotation to Array<RelativePointer> to match the declared return type, or keep ReadonlyArray<RelativePointer> if intentional to discourage mutation (document the reasoning in that case).

🤖 Prompt for AI Agents
In `@www/src/docs/exampleComponents/AreaChart/AreaChartWithCustomEvents.tsx`
around lines 61 - 72, The touch handlers onTouchStart, onTouchMove and
onTouchEnd call getRelativeCoordinate which is declared to return
Array<RelativePointer>, but the code types the result as
ReadonlyArray<RelativePointer>; update the type annotation to
Array<RelativePointer> to match getRelativeCoordinate’s signature (or if you
intentionally want an immutable view, add a comment explaining that choice and
keep a defensive readonly cast), ensuring the variable declaration in each
handler uses Array<RelativePointer> to resolve the mismatch with
getRelativeCoordinate.

@codecov

codecov Bot commented Jan 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 58.23755% with 109 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.13%. Comparing base (e43875c) to head (372f394).
⚠️ Report is 7 commits behind head on main.

Files with missing lines Patch % Lines
...xamples/getRelativeCoordinate/CrosshairExample.tsx 7.31% 76 Missing ⚠️
...Components/AreaChart/AreaChartWithCustomEvents.tsx 50.74% 33 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6942      +/-   ##
==========================================
- Coverage   91.37%   91.13%   -0.24%     
==========================================
  Files         505      509       +4     
  Lines       37754    37967     +213     
  Branches     5271     5287      +16     
==========================================
+ Hits        34497    34601     +104     
- Misses       3248     3357     +109     
  Partials        9        9              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codecov

codecov Bot commented Jan 31, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 8.96kB (0.32%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.23MB 4.33kB (0.35%) ⬆️
recharts/bundle-es6 1.07MB 3.98kB (0.38%) ⬆️
recharts/bundle-umd 536.16kB 650 bytes (0.12%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
state/selectors/axisSelectors.js -8 bytes 62.56kB -0.01%
util/ChartUtils.js 6 bytes 19.89kB 0.03%
index.js 237 bytes 12.42kB 1.95%
component/Legend.js 148 bytes 9.39kB 1.6%
util/types.js 348 bytes 8.5kB 4.27%
util/getActiveCoordinate.js 12 bytes 7.89kB 0.15%
state/mouseEventsMiddleware.js 42 bytes 5.13kB 0.83%
state/externalEventsMiddleware.js 146 bytes 5.08kB 2.96%
state/touchEventsMiddleware.js 386 bytes 5.03kB 8.31% ⚠️
util/PolarUtils.js 6 bytes 4.83kB 0.12%
util/getRelativeCoordinate.js (New) 4.41kB 4.41kB 100.0% 🚀
util/createEventProxy.js (New) 533 bytes 533 bytes 100.0% 🚀
util/getChartPointer.js (Deleted) -1.93kB 0 bytes -100.0% 🗑️
view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 650 bytes 536.16kB 0.12%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
state/selectors/axisSelectors.js -4 bytes 53.26kB -0.01%
util/ChartUtils.js 6 bytes 17.87kB 0.03%
component/Legend.js 124 bytes 8.26kB 1.52%
util/types.js 348 bytes 8.09kB 4.5%
util/getActiveCoordinate.js 12 bytes 7.38kB 0.16%
state/externalEventsMiddleware.js 123 bytes 4.83kB 2.61%
state/touchEventsMiddleware.js 357 bytes 4.75kB 8.14% ⚠️
state/mouseEventsMiddleware.js 30 bytes 4.65kB 0.65%
util/PolarUtils.js 6 bytes 4.43kB 0.14%
util/getRelativeCoordinate.js (New) 4.28kB 4.28kB 100.0% 🚀
index.js 70 bytes 3.45kB 2.07%
util/createEventProxy.js (New) 415 bytes 415 bytes 100.0% 🚀
util/getChartPointer.js (Deleted) -1.78kB 0 bytes -100.0% 🗑️

@github-actions

Copy link
Copy Markdown
Contributor

Staging Deployment Details

These deployments will remain available for 30 days.

To update snapshots: Comment /update-snapshots on this PR to automatically update the baseline screenshots.

@PavelVanecek

Copy link
Copy Markdown
Collaborator Author

Comment thread src/util/types.ts
* Coordinates relative to the top-left corner of the active element.
* Also include scale which means that element that's scaled will return the same coordinates as element that's not scaled.
*/
export interface ChartPointer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are people using this? We don't know

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It was never exported from index.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It was never exported from index.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ah ok I was looking at the file name wrong lol

@ckifer
ckifer merged commit 196fe3e into main Feb 3, 2026
46 of 48 checks passed
@PavelVanecek
PavelVanecek deleted the getRelativeCoordinate branch February 3, 2026 22:47
ckifer pushed a commit that referenced this pull request Feb 10, 2026
## Description

Added tests to make sure that the new function we added in
#6942 is internally compatible
with our type handlers.

## Related Issue

#6645

Fixes #3362

Fixes #4872

Closes #5495

## Motivation and Context

I suspect that the new functionality and hooks will draw more attention
to the event handlers so I would like this to be easy to use.

## Types of changes

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)

## Checklist:

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [x] I have added tests to cover my changes.
- [ ] I have added a storybook story or VR test, or extended an existing
story or VR test to show my changes


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

## Release Notes

* **New Features**
* Exported new public types: `SankeyElementType`, `RadarPoint`,
`InternalRadarProps`, and `ScatterPointItem` for improved TypeScript
support and better type inference in event handlers.

* **Bug Fixes**
* Made `TreemapNode.root` optional to prevent structure validation
errors.

* **Refactor**
* Refined event handler type signatures across charts for more specific
SVG element typing and better IDE support.
  * Removed `onClick` handler from Dot component.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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