@@ -2,9 +2,9 @@ import type {SkTypefaceFontProvider} from '@shopify/react-native-skia';
22import type { SharedValue } from 'react-native-reanimated' ;
33import { useSharedValue } from 'react-native-reanimated' ;
44import type { Scale } from 'victory-native' ;
5- import { DIAGONAL_ANGLE_RADIAN_THRESHOLD } from '@components/Charts/constants' ;
5+ import { AXIS_LABEL_GAP , DIAGONAL_ANGLE_RADIAN_THRESHOLD } from '@components/Charts/constants' ;
66import type { LabelRotation } from '@components/Charts/types' ;
7- import { getFontLineMetrics , isCursorOverChartLabel } from '@components/Charts/utils' ;
7+ import { getAdditionalOffset , getFontLineMetrics , isCursorOverChartLabel , rotatedLabelYOffset } from '@components/Charts/utils' ;
88import variables from '@styles/variables' ;
99import type { HitTestArgs } from './useChartInteractions' ;
1010
@@ -34,28 +34,6 @@ type LabelHitGeometry = {
3434 yMax90Offsets : number [ ] ;
3535} ;
3636
37- type ComputeGeometryInput = {
38- /** The ascent of the font */
39- ascent : number ;
40-
41- /** The descent of the font */
42- descent : number ;
43-
44- /** The sine of the angle */
45- sinA : number ;
46-
47- /** The angle in radians */
48- angleRad : number ;
49-
50- /** The widths of the labels */
51- labelWidths : number [ ] ;
52-
53- /** The padding of the labels */
54- padding : number ;
55- } ;
56-
57- type ComputeGeometryFn = ( input : ComputeGeometryInput ) => LabelHitGeometry ;
58-
5937type UseLabelHitTestingParams = {
6038 fontMgr : SkTypefaceFontProvider | null | undefined ;
6139 fontSize : number ;
@@ -64,45 +42,45 @@ type UseLabelHitTestingParams = {
6442 labelRotation : LabelRotation ;
6543 labelSkipInterval : number ;
6644 chartBottom : SharedValue < number > ;
67-
68- /**
69- * Chart-specific geometry factory.
70- * Receives font metrics, trig values, and per-label widths; returns the
71- * normalized geometry shape. Typically a module-level constant.
72- */
73- computeGeometry : ComputeGeometryFn ;
7445} ;
7546
7647/**
7748 * Shared hook for x-axis label hit-testing in cartesian charts.
7849 *
7950 * Encapsulates angle conversion, pre-computed hit geometry, and the
8051 * isCursorOverLabel / findLabelCursorX worklets — all of which are identical
81- * between bar and line chart except for how the hit geometry is computed .
52+ * between bar and line charts .
8253 *
8354 * Label widths are accepted as a pre-computed array (from useChartLabelLayout)
8455 * so no Skia measurement happens here.
8556 *
86- * Chart-specific geometry (45° corner anchor offsets, 90° vertical bounds) is supplied
87- * via the `computeGeometry` callback, typically a module-level constant .
57+ * Labels are right-aligned at the tick: the 45° parallelogram's upper-right corner is
58+ * offset by (iconSize/3 * sinA) left and down, placing the box just below the axis line .
8859 */
89- function useLabelHitTesting ( { fontMgr, fontSize, truncatedLabelWidths, labelRotation, labelSkipInterval, chartBottom, computeGeometry } : UseLabelHitTestingParams ) {
60+ function useLabelHitTesting ( { fontMgr, fontSize, truncatedLabelWidths, labelRotation, labelSkipInterval, chartBottom} : UseLabelHitTestingParams ) {
9061 const tickXPositions = useSharedValue < number [ ] > ( [ ] ) ;
9162
9263 const angleRad = ( Math . abs ( labelRotation ) * Math . PI ) / 180 ;
9364
9465 const fontMetrics = fontMgr ? getFontLineMetrics ( fontMgr , fontSize ) : null ;
9566
96- /**
97- * Geometry for label hit-testing. The `computeGeometry` callback supplies the
98- * chart-specific differences (bar vs. line anchor offsets).
99- */
10067 let labelHitGeometry : LabelHitGeometry | null = null ;
10168 if ( fontMetrics ) {
10269 const { ascent, descent} = fontMetrics ;
10370 const sinA = Math . sin ( angleRad ) ;
10471 const padding = variables . iconSizeExtraSmall / 2 ;
105- labelHitGeometry = computeGeometry ( { ascent, descent, sinA, angleRad, labelWidths : truncatedLabelWidths , padding} ) ;
72+ const iconThirdSin = ( variables . iconSizeExtraSmall / 3 ) * sinA ;
73+ const additionalOffset = getAdditionalOffset ( angleRad ) ;
74+ labelHitGeometry = {
75+ labelYOffset : AXIS_LABEL_GAP + rotatedLabelYOffset ( ascent , descent , angleRad ) - additionalOffset ,
76+ iconSin : variables . iconSizeExtraSmall * sinA ,
77+ labelSins : truncatedLabelWidths . map ( ( w ) => w * sinA ) ,
78+ halfWidths : truncatedLabelWidths . map ( ( w ) => w / 2 ) ,
79+ cornerAnchorDX : truncatedLabelWidths . map ( ( ) => - iconThirdSin ) ,
80+ cornerAnchorDY : truncatedLabelWidths . map ( ( ) => iconThirdSin ) ,
81+ yMin90Offsets : truncatedLabelWidths . map ( ( ) => padding ) ,
82+ yMax90Offsets : truncatedLabelWidths . map ( ( w ) => w + padding ) ,
83+ } ;
10684 }
10785
10886 /**
@@ -183,4 +161,3 @@ function useLabelHitTesting({fontMgr, fontSize, truncatedLabelWidths, labelRotat
183161}
184162
185163export default useLabelHitTesting ;
186- export type { ComputeGeometryFn , ComputeGeometryInput , LabelHitGeometry } ;
0 commit comments