forked from ddrilling/asb_cloud_front
На странице Наработка добавлен сброс даты и выделение данных при наведении
This commit is contained in:
parent
6455be0891
commit
116de6e912
@ -1,4 +1,4 @@
|
|||||||
import { memo, useEffect, useMemo, useRef } from 'react'
|
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
|
||||||
import { useElementSize } from 'usehooks-ts'
|
import { useElementSize } from 'usehooks-ts'
|
||||||
import { Property } from 'csstype'
|
import { Property } from 'csstype'
|
||||||
import * as d3 from 'd3'
|
import * as d3 from 'd3'
|
||||||
@ -20,7 +20,7 @@ export type D3HorizontalChartProps = {
|
|||||||
height?: Property.Height
|
height?: Property.Height
|
||||||
data: PercentChartDataType[]
|
data: PercentChartDataType[]
|
||||||
offset?: Partial<ChartOffset>
|
offset?: Partial<ChartOffset>
|
||||||
afterDraw?: (d: d3.Selection<SVGGElement, unknown, null, undefined>) => void
|
afterDraw?: (d: d3.Selection<d3.BaseType, PercentChartDataType, d3.BaseType, unknown>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOffset = { top: 50, right: 100, bottom: 50, left: 100 }
|
const defaultOffset = { top: 50, right: 100, bottom: 50, left: 100 }
|
||||||
@ -37,7 +37,7 @@ export const D3HorizontalPercentChart = memo<D3HorizontalChartProps>(({
|
|||||||
const [divRef, { width, height }] = useElementSize()
|
const [divRef, { width, height }] = useElementSize()
|
||||||
const rootRef = useRef<SVGGElement | null>(null)
|
const rootRef = useRef<SVGGElement | null>(null)
|
||||||
|
|
||||||
const root = useMemo(() => rootRef.current ? d3.select(rootRef.current) : null, [rootRef.current])
|
const root = useCallback(() => d3.select(rootRef.current), [rootRef.current])
|
||||||
|
|
||||||
const inlineWidth = useMemo(() => width - offset.left - offset.right, [width])
|
const inlineWidth = useMemo(() => width - offset.left - offset.right, [width])
|
||||||
const inlineHeight = useMemo(() => height - offset.top - offset.bottom, [height])
|
const inlineHeight = useMemo(() => height - offset.top - offset.bottom, [height])
|
||||||
@ -50,15 +50,15 @@ export const D3HorizontalPercentChart = memo<D3HorizontalChartProps>(({
|
|||||||
const xAxisTop = d3.axisTop(xScale).tickFormat((d) => `${d}%`).ticks(4).tickSize(-inlineHeight)
|
const xAxisTop = d3.axisTop(xScale).tickFormat((d) => `${d}%`).ticks(4).tickSize(-inlineHeight)
|
||||||
const xAxisBottom = d3.axisBottom(xScale).tickFormat((d) => `${d}%`).ticks(4)
|
const xAxisBottom = d3.axisBottom(xScale).tickFormat((d) => `${d}%`).ticks(4)
|
||||||
|
|
||||||
root.selectChild<SVGGElement>('.axis.x.bottom').call(xAxisBottom)
|
root().selectChild<SVGGElement>('.axis.x.bottom').call(xAxisBottom)
|
||||||
root.selectChild<SVGGElement>('.axis.x.top').call(xAxisTop)
|
root().selectChild<SVGGElement>('.axis.x.top').call(xAxisTop)
|
||||||
.selectAll('.tick')
|
.selectAll('.tick')
|
||||||
.attr('class', 'tick grid-line')
|
.attr('class', 'tick grid-line')
|
||||||
}, [root, width, height, xScale, inlineHeight])
|
}, [root, width, height, xScale, inlineHeight])
|
||||||
|
|
||||||
useEffect(() => { /// Отрисовываем ось Y слева
|
useEffect(() => { /// Отрисовываем ось Y слева
|
||||||
if (width < 100 || height < 100 || !root) return
|
if (width < 100 || height < 100 || !root) return
|
||||||
root.selectChild<SVGGElement>('.axis.y.left').call(d3.axisLeft(yScale))
|
root().selectChild<SVGGElement>('.axis.y.left').call(d3.axisLeft(yScale))
|
||||||
}, [root, width, height, yScale])
|
}, [root, width, height, yScale])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -66,10 +66,10 @@ export const D3HorizontalPercentChart = memo<D3HorizontalChartProps>(({
|
|||||||
|
|
||||||
const delay = d3.transition().duration(500).ease(d3.easeLinear)
|
const delay = d3.transition().duration(500).ease(d3.easeLinear)
|
||||||
|
|
||||||
const rects = root.selectChild('.data').selectAll('rect').data(data)
|
const rects = root().selectChild('.data').selectAll('rect').data(data)
|
||||||
rects.enter().append('rect')
|
rects.enter().append('rect')
|
||||||
rects.exit().remove()
|
rects.exit().remove()
|
||||||
root.selectChild<SVGGElement>('.data')
|
root().selectChild<SVGGElement>('.data')
|
||||||
.selectAll<SVGRectElement, PercentChartDataType>('rect')
|
.selectAll<SVGRectElement, PercentChartDataType>('rect')
|
||||||
.attr('fill', (d) => d.color || 'black')
|
.attr('fill', (d) => d.color || 'black')
|
||||||
.attr('y', (d) => yScale(d.name) ?? null)
|
.attr('y', (d) => yScale(d.name) ?? null)
|
||||||
@ -77,14 +77,14 @@ export const D3HorizontalPercentChart = memo<D3HorizontalChartProps>(({
|
|||||||
.transition(delay)
|
.transition(delay)
|
||||||
.attr('width', (d) => d.percent > 0 ? xScale(d.percent) : 0)
|
.attr('width', (d) => d.percent > 0 ? xScale(d.percent) : 0)
|
||||||
|
|
||||||
afterDraw?.(root)
|
afterDraw?.(root().selectChild('.data').selectAll('rect'))
|
||||||
|
|
||||||
}, [data, width, height, root, yScale, xScale, afterDraw])
|
}, [data, width, height, root, yScale, xScale, afterDraw])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LoaderPortal show={false} style={{ width: givenWidth, height: givenHeight }}>
|
<LoaderPortal show={false} style={{ width: givenWidth, height: givenHeight }}>
|
||||||
<div ref={divRef} style={{ width: '100%', height: '100%' }}>
|
<div ref={divRef} style={{ width: '100%', height: '100%' }}>
|
||||||
<svg id={'d3-horizontal-chart'} width={'100%'} height={'100%'}>
|
<svg width={'100%'} height={'100%'}>
|
||||||
<g ref={rootRef} transform={`translate(${offset.left}, ${offset.top})`}>
|
<g ref={rootRef} transform={`translate(${offset.left}, ${offset.top})`}>
|
||||||
<g className={'axis x top'}></g>
|
<g className={'axis x top'}></g>
|
||||||
<g className={'axis x bottom'} transform={`translate(0, ${inlineHeight})`}></g>
|
<g className={'axis x bottom'} transform={`translate(0, ${inlineHeight})`}></g>
|
||||||
|
@ -21,6 +21,8 @@ const subsystemColors = [
|
|||||||
'#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d',
|
'#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const tableStyle = { background: '#FAFAFA', fontSize: '16px', fontWeight: '600', transition: 'all 0.2s ease-out' }
|
||||||
|
|
||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
makeColumn('Цвет', 'color', { width: 60, render: (backgroundColor) => (
|
makeColumn('Цвет', 'color', { width: 60, render: (backgroundColor) => (
|
||||||
<div className={'table_color'} style={{ backgroundColor }} />
|
<div className={'table_color'} style={{ backgroundColor }} />
|
||||||
@ -62,37 +64,25 @@ export const OperationTime = memo(() => {
|
|||||||
|
|
||||||
const onRow = useCallback((item) => {
|
const onRow = useCallback((item) => {
|
||||||
const out = {
|
const out = {
|
||||||
onMouseEnter: () => {
|
onMouseEnter: () => setSelectedSubsystem(item.subsystemName),
|
||||||
setSelectedSubsystem(item.subsystemName)
|
onMouseLeave: () => setSelectedSubsystem(null),
|
||||||
},
|
|
||||||
onMouseLeave: () => {
|
|
||||||
setSelectedSubsystem(null)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.subsystemName === selectedSubsystem) {
|
if (item.subsystemName === selectedSubsystem) {
|
||||||
out.style = { background: '#FAFAFA', fontSize: '16px', fontWeight: '600', transition: 'all 0.2s ease-out' }
|
out.style = tableStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}, [selectedSubsystem])
|
}, [selectedSubsystem])
|
||||||
|
|
||||||
const onMouseOver = useCallback((_, d) => {
|
const onMouseOver = useCallback((_, d) => setSelectedSubsystem(d.name), [])
|
||||||
setSelectedSubsystem(d.name)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const onMouseOut = useCallback(() => {
|
const onMouseOut = useCallback(() => setSelectedSubsystem(null), [])
|
||||||
setSelectedSubsystem(null)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const afterDraw = useCallback(function(selection) {
|
const afterDraw = useCallback(selection => {
|
||||||
selection.selectAll('rect')
|
selection.on('mouseover', onMouseOver)
|
||||||
.on('mouseover', onMouseOver)
|
|
||||||
.on('mouseout', onMouseOut)
|
.on('mouseout', onMouseOut)
|
||||||
.transition(200)
|
.classed('selected_graph_column', d => d.name === selectedSubsystem)
|
||||||
.style('stroke-width', d => d.name === selectedSubsystem ? '2' : '0')
|
|
||||||
.style('stroke', d => d.name === selectedSubsystem ? 'black' : '')
|
|
||||||
.style('stroke-opacity', '0.4')
|
|
||||||
}, [onMouseOver, onMouseOut, selectedSubsystem])
|
}, [onMouseOver, onMouseOut, selectedSubsystem])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
.table_color {
|
.table_color {
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selected_graph_column {
|
||||||
|
filter: drop-shadow(0px 2px 2px rgba(0, 0, 0, .6));
|
||||||
|
transition: all 0.2s ease-out
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user