[Feature] getRelativeCoordinate#6942
Conversation
WalkthroughIntroduces a new coordinate system ( Changes
Sequence DiagramsequenceDiagram
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 | 🟡 MinorInitialize fake timers before timer assertions.
vi.getTimerCount()andvi.runOnlyPendingTimers()expect fake timers; addvi.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 andrequestAnimationFrame.
🤖 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_EXPORTSis 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 forgetRelativeCoordinatereturn value.
getRelativeCoordinate(e)returnsRelativePointer | 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: UseexpectLastCalledWithfor 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
expectLastCalledWithhelper function instead ofexpect(spy).toHaveBeenLastCalledWith(...)for better typing and autocompletion.
| }; | ||
|
|
||
| export const externalEventAction = createAction<ExternalEventActionPayload>('externalEvent'); | ||
| export const externalEventAction = createAction<ExternalEventActionPayload<any>>('externalEvent'); |
There was a problem hiding this comment.
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.
| 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`.
| 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; | ||
| }, | ||
| }); | ||
| } |
There was a problem hiding this comment.
🧩 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 tsxRepository: 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:
currentTargetis 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.
| 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.
| 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', () => { |
There was a problem hiding this comment.
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.
| 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.
| 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); | ||
| }} |
There was a problem hiding this comment.
🧩 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 fRepository: recharts/recharts
Length of output: 133
🏁 Script executed:
# Also search for getRelativeCoordinate definition
rg "getRelativeCoordinate" -A 3 -B 1Repository: 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.tsxRepository: 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 -50Repository: 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 Report❌ Patch coverage is
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. 🚀 New features to boost your workflow:
|
Bundle ReportChanges will increase total bundle size by 8.96kB (0.32%) ⬆️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: recharts/bundle-cjsAssets Changed:
view changes for bundle: recharts/bundle-umdAssets Changed:
view changes for bundle: recharts/bundle-es6Assets Changed:
|
|
Staging Deployment Details
These deployments will remain available for 30 days. To update snapshots: Comment |
| * 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 { |
There was a problem hiding this comment.
Are people using this? We don't know
There was a problem hiding this comment.
It was never exported from index.
There was a problem hiding this comment.
It was never exported from index.
There was a problem hiding this comment.
Ah ok I was looking at the file name wrong lol
## 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 -->
Description
Exports new function:
getRelativeCoordinate. This function computes relative element coordinates from mouse or touch event.Changes:
Renamed
getChartPointertogetRelativeCoordinateI 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.currentTargetin 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 latestcurrentTargetand return it if needed.getRelativeCoordinatedoes 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
Checklist: