asb_cloud_front/src/components/d3/plugins/D3Cursor.tsx

84 lines
2.4 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