useChartHighlight.tsx103 lines · main
1import dayjs from 'dayjs'
2import { useState } from 'react'
3
4type ChartHighlightMouseEvent = {
5 activeLabel?: string
6 coordinates?: string
7}
8
9export interface ChartHighlight {
10 left: string | undefined
11 right: string | undefined
12 coordinates: { left?: string; right?: string }
13 isSelecting: boolean
14 popoverPosition: { x: number; y: number } | null
15 handleMouseDown: (e: ChartHighlightMouseEvent) => void
16 handleMouseMove: (e: ChartHighlightMouseEvent) => void
17 handleMouseUp: (e: { chartX?: number; chartY?: number }) => void
18 clearHighlight: () => void
19}
20
21export function useChartHighlight(): ChartHighlight {
22 const [left, setLeft] = useState<string | undefined>(undefined)
23 const [right, setRight] = useState<string | undefined>(undefined)
24 const [coordinates, setCoordinates] = useState<{ left?: string; right?: string }>({
25 left: undefined,
26 right: undefined,
27 })
28 const [isSelecting, setIsSelecting] = useState(false)
29 const [popoverPosition, setPopoverPosition] = useState<{ x: number; y: number } | null>(null)
30 const [initialPoint, setInitialPoint] = useState<string | undefined>(undefined)
31
32 const handleMouseDown = (e: ChartHighlightMouseEvent) => {
33 clearHighlight()
34 if (!e || !e.activeLabel) return
35 setIsSelecting(true)
36 setLeft(e.activeLabel)
37 setRight(e.activeLabel)
38 setInitialPoint(e.activeLabel)
39 setCoordinates({ left: e.coordinates, right: e.coordinates })
40 }
41
42 const handleMouseMove = (e: ChartHighlightMouseEvent) => {
43 if (!isSelecting || !e || !e.activeLabel) return
44
45 const currentTimestamp = dayjs(e.activeLabel)
46 const initialTimestamp = dayjs(initialPoint)
47
48 if (currentTimestamp.isBefore(initialTimestamp)) {
49 // If dragging left, update left and keep right as initial
50 setLeft(e.activeLabel)
51 setRight(initialPoint)
52 setCoordinates({
53 left: e.coordinates,
54 right: coordinates.right,
55 })
56 } else {
57 // If dragging right, update right and keep left as initial
58 setRight(e.activeLabel)
59 setLeft(initialPoint)
60 setCoordinates({
61 left: coordinates.left,
62 right: e.coordinates,
63 })
64 }
65 }
66
67 const handleMouseUp = (e: unknown) => {
68 if (!isSelecting) return
69 setIsSelecting(false)
70 setInitialPoint(undefined)
71
72 if (
73 typeof e === 'object' &&
74 e !== null &&
75 'chartX' in e &&
76 'chartY' in e &&
77 typeof e.chartX === 'number' &&
78 typeof e.chartY === 'number'
79 ) {
80 setPopoverPosition({ x: e.chartX, y: e.chartY })
81 }
82 }
83
84 const clearHighlight = () => {
85 setLeft(undefined)
86 setRight(undefined)
87 setCoordinates({ left: undefined, right: undefined })
88 setPopoverPosition(null)
89 setInitialPoint(undefined)
90 }
91
92 return {
93 left,
94 right,
95 coordinates,
96 isSelecting,
97 popoverPosition,
98 handleMouseDown,
99 handleMouseMove,
100 handleMouseUp,
101 clearHighlight,
102 }
103}