forked from ddrilling/asb_cloud_front
83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
|
import { SVGProps, useEffect, useMemo, useRef } from 'react'
|
||
|
import * as d3 from 'd3'
|
||
|
|
||
|
import { useD3MouseZone } from '@components/d3/D3MouseZone'
|
||
|
import { usePartialProps } from '@utils'
|
||
|
|
||
|
import { wrapPlugin } from './base'
|
||
|
|
||
|
import '@styles/d3.less'
|
||
|
|
||
|
export type D3CursorSettings = {
|
||
|
lineStyle?: SVGProps<SVGGElement>
|
||
|
}
|
||
|
|
||
|
const defaultLineStyle: SVGProps<SVGGElement> = {
|
||
|
stroke: 'gray',
|
||
|
strokeWidth: 1,
|
||
|
strokeOpacity: 1,
|
||
|
className: '',
|
||
|
}
|
||
|
|
||
|
const defaultSettings: D3CursorSettings = {
|
||
|
lineStyle: defaultLineStyle,
|
||
|
}
|
||
|
|
||
|
export type D3CursorProps = D3CursorSettings
|
||
|
|
||
|
export const D3Cursor = wrapPlugin<D3CursorSettings>(((props) => {
|
||
|
const settings = usePartialProps(props, defaultSettings)
|
||
|
const lineStyle = usePartialProps(settings.lineStyle, defaultLineStyle)
|
||
|
|
||
|
const { mouseState, zoneRect } = useD3MouseZone()
|
||
|
const zoneRef = useRef(null)
|
||
|
|
||
|
const zone = useMemo(() => zoneRef.current ? (() => d3.select(zoneRef.current)) : null, [zoneRef.current])
|
||
|
|
||
|
const getXLine = useMemo(() => zone ? (() => zone().select('.tooltip-x-line')) : null, [zone])
|
||
|
const getYLine = useMemo(() => zone ? (() => zone().select('.tooltip-y-line')) : null, [zone])
|
||
|
|
||
|
useEffect(() => {
|
||
|
if (!zone || !getXLine || !getYLine) return
|
||
|
const z = zone()
|
||
|
|
||
|
if (z.selectAll('line').empty()) {
|
||
|
z.append('line').attr('class', 'tooltip-x-line').style('pointer-events', 'none')
|
||
|
z.append('line').attr('class', 'tooltip-y-line').style('pointer-events', 'none')
|
||
|
}
|
||
|
|
||
|
getXLine()
|
||
|
.attr('y1', 0)
|
||
|
.attr('y2', zoneRect?.height ?? 0)
|
||
|
|
||
|
getYLine()
|
||
|
.attr('x1', 0)
|
||
|
.attr('x2', zoneRect?.width ?? 0)
|
||
|
}, [zone, getXLine, getYLine, zoneRect])
|
||
|
|
||
|
useEffect(() => {
|
||
|
if (!getXLine || !getYLine || !mouseState) return
|
||
|
|
||
|
getXLine()
|
||
|
.attr('x1', mouseState.x)
|
||
|
.attr('x2', mouseState.x)
|
||
|
.attr('opacity', mouseState.visible ? '1' : '0')
|
||
|
|
||
|
getYLine()
|
||
|
.attr('y1', mouseState.y)
|
||
|
.attr('y2', mouseState.y)
|
||
|
.attr('opacity', mouseState.visible ? '1' : '0')
|
||
|
}, [mouseState, getXLine, getYLine])
|
||
|
|
||
|
|
||
|
return (
|
||
|
<g
|
||
|
{...lineStyle}
|
||
|
ref={zoneRef}
|
||
|
className={`cursor-zone ${lineStyle.className}`}
|
||
|
/>
|
||
|
)
|
||
|
}), true)
|
||
|
|
||
|
export default D3Cursor
|