forked from ddrilling/asb_cloud_front
Добавлен tooltip для графика операций время-день
This commit is contained in:
parent
5511c06410
commit
fc6646eb80
@ -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>
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
'Не удалось загрзуить категории операций'
|
'Не удалось загрзуить категории операций'
|
||||||
|
@ -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>
|
||||||
) : (
|
) : (
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user