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 } const defaultLineStyle: SVGProps = { stroke: 'gray', strokeWidth: 1, strokeOpacity: 1, className: '', } const defaultSettings: D3CursorSettings = { lineStyle: defaultLineStyle, } export type D3CursorProps = D3CursorSettings export const D3Cursor = wrapPlugin(((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 ( ) }), true) export default D3Cursor