2022-06-25 16:03:08 +05:00
|
|
|
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 = {
|
2022-07-25 14:30:24 +05:00
|
|
|
/** Параметры стиля линии */
|
2022-06-25 16:03:08 +05:00
|
|
|
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
|