Добавлен tooltip для графика операций время-день

This commit is contained in:
goodmice 2022-08-09 11:54:06 +05:00
parent 5511c06410
commit fc6646eb80
5 changed files with 82 additions and 9 deletions

View File

@ -8,7 +8,7 @@ import '@styles/detected_operations.less'
const displayNumber = makeDisplayValue({ fixed: 2 }) const displayNumber = makeDisplayValue({ fixed: 2 })
const makeTooltipRender = (category) => ([{ data: [data] }]) => ( export const makeTooltipRender = (category) => ([{ data: [data] }]) => (
<div className={'detected-operations-tooltip'}> <div className={'detected-operations-tooltip'}>
<span className={'tooltip-label'}>{data.operationCategory?.name}</span> <span className={'tooltip-label'}>{data.operationCategory?.name}</span>
<span className={'tooltip-label'}>{formatDate(data.dateStart, undefined, 'DD.MM.YYYY')}</span> <span className={'tooltip-label'}>{formatDate(data.dateStart, undefined, 'DD.MM.YYYY')}</span>
@ -21,12 +21,12 @@ const makeTooltipRender = (category) => ([{ data: [data] }]) => (
<GridItem row={2} col={3}>{displayNumber(data.depthEnd)} м</GridItem> <GridItem row={2} col={3}>{displayNumber(data.depthEnd)} м</GridItem>
</Grid> </Grid>
<Grid style={{ marginTop: 0 }}> <Grid style={{ marginTop: 0 }}>
<GridItem row={1} col={1}>{category?.name ?? 'Ключ'}:</GridItem> <GridItem row={1} col={1}>{category?.keyValueName ?? 'Ключ'}:</GridItem>
<GridItem row={1} col={2}>{displayNumber(data.value)}</GridItem> <GridItem row={1} col={2}>{displayNumber(data.value)}</GridItem>
<GridItem row={1} col={3}>{category?.unit ?? '----'}</GridItem> <GridItem row={1} col={3}>{category?.keyValueUnits ?? '----'}</GridItem>
<GridItem row={2} col={1}>Цель:</GridItem> <GridItem row={2} col={1}>Цель:</GridItem>
<GridItem row={2} col={2}>{displayNumber(data.operationValue?.targetValue)}</GridItem> <GridItem row={2} col={2}>{displayNumber(data.operationValue?.targetValue)}</GridItem>
<GridItem row={2} col={3}>{category?.unit ?? '----'}</GridItem> <GridItem row={2} col={3}>{category?.keyValueUnits ?? '----'}</GridItem>
</Grid> </Grid>
</div> </div>
) )

View File

@ -70,7 +70,11 @@ const Operations = memo(() => {
invokeWebApiWrapperAsync( invokeWebApiWrapperAsync(
async () => { async () => {
const categories = arrayOrDefault(await DetectedOperationService.getCategories()) const categories = arrayOrDefault(await DetectedOperationService.getCategories())
setCategories(categories.map(({ id, name }) => ({ value: id, label: name }))) setCategories(categories.map((category) => ({
...category,
value: category.id,
label: category.name,
})))
}, },
setIsLoading, setIsLoading,
'Не удалось загрзуить категории операций' 'Не удалось загрзуить категории операций'

View File

@ -11,8 +11,13 @@ import { DetectedOperationService } from '@api'
import { unique } from '@utils/filters' import { unique } from '@utils/filters'
import { formatDate } from '@utils' import { formatDate } from '@utils'
import { makeTooltipRender } from '@pages/Telemetry/Operations/OperationsChart'
import { makeGetColor } from '.' import { makeGetColor } from '.'
import '@styles/d3.less'
import '@styles/tvd.less'
import '@styles/detected_operations.less'
const defaultOffset = { left: 40, right: 20, top: 20, bottom: 20 } const defaultOffset = { left: 40, right: 20, top: 20, bottom: 20 }
const zeroDate = moment('2000-01-01 00:00:00') const zeroDate = moment('2000-01-01 00:00:00')
@ -42,10 +47,13 @@ export const TLChart = memo(({
backgroundColor = '#0000', backgroundColor = '#0000',
barHeight = 15, barHeight = 15,
offset = defaultOffset, offset = defaultOffset,
tooltipSize = { width: 200, height: 220 },
}) => { }) => {
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [svgRef, setSvgRef] = useState() const [svgRef, setSvgRef] = useState()
const [data, setData] = useState() const [data, setData] = useState()
const [selected, setSelected] = useState()
const [tooltipPos, setTooltipPos] = useState({ x: 0, y: 0 })
const getColor = useMemo(() => makeGetColor(data?.map((row) => row.idCategory).filter(unique)), [data]) const getColor = useMemo(() => makeGetColor(data?.map((row) => row.idCategory).filter(unique)), [data])
@ -124,22 +132,54 @@ export const TLChart = memo(({
.attr('width', (d) => xAxis(d.endTime) - xAxis(d.startTime)) .attr('width', (d) => xAxis(d.endTime) - xAxis(d.startTime))
.attr('height', barHeight) .attr('height', barHeight)
.attr('fill', (d) => getColor(d.idCategory)) .attr('fill', (d) => getColor(d.idCategory))
.on('mouseover', (e, data) => {
d3.select(svgRef).select('.chart-area')
.selectAll('rect')
.filter((d) => d.idCategory === data.idCategory)
.attr('stroke-width', '2px')
const rect = e.target.getBoundingClientRect()
setTooltipPos({ x: rect.x, y: rect.y })
setSelected(data)
})
.on('mouseout', (e, data) => {
d3.select(svgRef).select('.chart-area')
.selectAll('rect')
.filter((d) => d.idCategory === data.idCategory)
.attr('stroke-width', '0')
setSelected(null)
})
}, [svgRef, xAxis, yAxis, data, getColor]) }, [svgRef, xAxis, yAxis, data, getColor])
const tooltipStyle = useMemo(() => {
return {
...tooltipSize,
left: tooltipPos.x - tooltipSize.width - 8,
top: tooltipPos.y - tooltipSize.height / 2 + barHeight / 2,
}
}, [tooltipPos, tooltipSize, barHeight])
return ( return (
<div className={'tvd-right'} ref={rootRef}> <div className={'tvd-right'} ref={rootRef}>
<LoaderPortal show={isLoading} style={{ width: '100%', flexGrow: 1 }}> <LoaderPortal show={isLoading} className={'asb-d3-chart'}>
{selected && (
<div className={'tl-op-tooltip'} style={tooltipStyle}>
<div className={'tooltip right'}>
{makeTooltipRender(selected.operationCategory)([{ data: [selected] }])}
</div>
</div>
)}
{data ? ( {data ? (
<svg ref={setSvgRef} width={'100%'} height={'100%'}> <svg className={'tl-op-chart'} ref={setSvgRef} width={'100%'} height={'100%'}>
<g className={'axis x'} transform={`translate(${offset.left}, ${offset.top})`} /> <g className={'axis x'} transform={`translate(${offset.left}, ${offset.top})`} />
<g className={'axis y'} transform={`translate(${offset.left}, ${offset.top + barHeight})`} /> <g className={'axis y'} transform={`translate(${offset.left}, ${offset.top + barHeight})`} />
<g className={'chart-area'} transform={`translate(${offset.left}, ${offset.top + barHeight})`} stroke={'none'} /> <g className={'chart-area'} transform={`translate(${offset.left}, ${offset.top + barHeight})`} stroke={'red'} strokeWidth={'0'} />
<rect <rect
x={offset.left} x={offset.left}
y={offset.top} y={offset.top}
width={Math.max(width - offset.left - offset.right, 0)} width={Math.max(width - offset.left - offset.right, 0)}
height={Math.max(height - offset.top - offset.bottom, 0)} height={Math.max(height - offset.top - offset.bottom, 0)}
fill={backgroundColor} fill={backgroundColor}
pointerEvents={'none'}
/> />
</svg> </svg>
) : ( ) : (

View File

@ -41,7 +41,7 @@
&.bottom { &.bottom {
margin-top: 0; margin-bottom: @arrow-size;
&::after { &::after {
border-top-color: @bg-color; border-top-color: @bg-color;
@ -50,6 +50,24 @@
margin-left: -@arrow-size; margin-left: -@arrow-size;
} }
} }
&.left {
margin-left: @arrow-size;
&::after {
border-right-color: @bg-color;
top: 50%;
right: 100%;
}
}
&.right {
margin-right: @arrow-size;
&::after {
border-left-color: @bg-color;
top: 50%;
left: 100%;
}
}
& .tooltip-content { & .tooltip-content {
overflow: hidden; overflow: hidden;

View File

@ -86,6 +86,17 @@
justify-content: center; justify-content: center;
} }
.tl-op-tooltip {
position: absolute;
pointer-events: none;
}
.tl-op-chart {
& .chart-area > rect {
transition: stroke-width .25s ease-in-out;
}
}
.tl-pie { .tl-pie {
display: flex; display: flex;
flex-direction: column; flex-direction: column;