Добавлен тултип для колонки

This commit is contained in:
goodmice 2022-08-15 11:58:32 +05:00
parent cc37bccacf
commit 48ee08acab
3 changed files with 63 additions and 16 deletions

View File

@ -78,12 +78,11 @@ const defaultOffsets: ChartOffset = {
} }
const defaultRegulators: TelemetryRegulators = { const defaultRegulators: TelemetryRegulators = {
1: { color: '#007070', label: 'Расход' }, 1: { color: '#59B359', label: 'Скорость блока' },
2: { color: '#59B359', label: 'Скорость блока' }, 2: { color: '#FF0000', label: 'Давление' },
3: { color: '#FF0000', label: 'Давление' }, 3: { color: '#0000CC', label: 'Осевая нагрузка' },
4: { color: '#0000CC', label: 'Осевая нагрузка' }, 4: { color: '#990099', label: 'Момент на роторе' },
5: { color: '#00B3B3', label: 'Вес на крюке' }, 5: { color: '#007070', label: 'Расход' },
6: { color: '#990099', label: 'Момент на роторе' },
} }
const getDefaultYAxisConfig = <DataType,>(): ChartAxis<DataType> => ({ const getDefaultYAxisConfig = <DataType,>(): ChartAxis<DataType> => ({
@ -321,11 +320,12 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
let sets = chartName ? await UserSettingsService.get(chartName) : null let sets = chartName ? await UserSettingsService.get(chartName) : null
if (typeof sets === 'string') if (typeof sets === 'string')
sets = JSON.parse(sets) sets = JSON.parse(sets)
const { settings, regulators } = sets if (sets && Array.isArray(sets.settings)) {
if (regulators) if (sets.regulators)
setRegulators(regulators) setRegulators(sets.regulators)
if (Array.isArray(settings)) { if (Array.isArray(sets.settings)) {
setDatasets(settings) setDatasets(sets.settings)
}
} else if (Array.isArray(datasetGroups)) { } else if (Array.isArray(datasetGroups)) {
setDatasets(datasetGroups) setDatasets(datasetGroups)
if (chartName) { if (chartName) {

View File

@ -1,18 +1,24 @@
import { memo, useEffect, useMemo, useState } from 'react' import { memo, useEffect, useMemo, useState } from 'react'
import * as d3 from 'd3' import * as d3 from 'd3'
import { Grid, GridItem } from '@components/Grid'
import { TelemetryDataSaubDto } from '@api' import { TelemetryDataSaubDto } from '@api'
import { formatDate } from '@utils'
type LimitChartData = { type LimitChartData = {
id: number id: number
dateStart: Date dateStart: Date
dateEnd: Date dateEnd: Date
depthStart: number | null
depthEnd: number | null
} }
type LimitChartDataRaw = { type LimitChartDataRaw = {
id?: number id?: number
dateStart?: string dateStart?: string
dateEnd?: string dateEnd?: string
depthStart?: number | null
depthEnd?: number | null
} }
export type TelemetryRegulators = Record<number, { export type TelemetryRegulators = Record<number, {
@ -31,12 +37,17 @@ const calcualteData = <DataType extends TelemetryDataSaubDto>(data: DataType[])
if (last.id === row.idFeedRegulator) { if (last.id === row.idFeedRegulator) {
if (!row.idFeedRegulator) return out if (!row.idFeedRegulator) return out
last.dateEnd = row.dateTime last.dateEnd = row.dateTime
last.depthEnd = row.wellDepth
} else { } else {
const n: LimitChartDataRaw = {} let n: LimitChartDataRaw = {}
if (row.idFeedRegulator) { if (row.idFeedRegulator) {
n.id = row.idFeedRegulator n = {
n.dateStart = row.dateTime id: row.idFeedRegulator,
n.dateEnd = row.dateTime dateStart: row.dateTime,
dateEnd: row.dateTime,
depthStart: row.wellDepth,
depthEnd: row.wellDepth,
}
} }
out.push(n) out.push(n)
} }
@ -47,6 +58,8 @@ const calcualteData = <DataType extends TelemetryDataSaubDto>(data: DataType[])
id: row.id, id: row.id,
dateStart: new Date(row.dateStart), dateStart: new Date(row.dateStart),
dateEnd: new Date(row.dateEnd), dateEnd: new Date(row.dateEnd),
depthStart: row.depthStart,
depthEnd: row.depthEnd,
})) }))
} }
@ -60,6 +73,9 @@ export type D3MonitoringLimitChartProps<DataType> = {
top: number top: number
} }
const tooltipWidth = 300
const tooltipHeight = 130
const _D3MonitoringLimitChart = <DataType extends TelemetryDataSaubDto>({ const _D3MonitoringLimitChart = <DataType extends TelemetryDataSaubDto>({
yAxis, yAxis,
data: chartData, data: chartData,
@ -70,6 +86,8 @@ const _D3MonitoringLimitChart = <DataType extends TelemetryDataSaubDto>({
regulators regulators
}: D3MonitoringLimitChartProps<DataType>) => { }: D3MonitoringLimitChartProps<DataType>) => {
const [ref, setRef] = useState<SVGGElement | null>(null) const [ref, setRef] = useState<SVGGElement | null>(null)
const [tooltipRef, setTooltipRef] = useState<SVGForeignObjectElement | null>(null)
const [selected, setSelected] = useState<Partial<LimitChartData & { x: number, y: number, visible: boolean }>>({})
const data = useMemo(() => calcualteData(chartData), [chartData]) const data = useMemo(() => calcualteData(chartData), [chartData])
@ -85,12 +103,33 @@ const _D3MonitoringLimitChart = <DataType extends TelemetryDataSaubDto>({
.attr('height', (d) => Math.max(yAxis(d.dateEnd) - yAxis(d.dateStart), 1)) .attr('height', (d) => Math.max(yAxis(d.dateEnd) - yAxis(d.dateStart), 1))
.attr('y', (d) => yAxis(d.dateStart)) .attr('y', (d) => yAxis(d.dateStart))
.attr('fill', (d) => regulators[d.id].color) .attr('fill', (d) => regulators[d.id].color)
.on('mouseover', (_, d) => {
const y = (yAxis(d.dateStart) + yAxis(d.dateEnd) - tooltipHeight) / 2
setSelected({ ...d, y, x: -tooltipWidth, visible: true })
})
.on('mouseout', (_, d) => setSelected((pre) => ({ ...pre, visible: false })))
}, [yAxis, data, ref, width]) }, [yAxis, data, ref, width])
return ( return (
<g transform={`translate(${left}, ${top})`} stroke={'#333'} strokeWidth={1} fill={'none'}> <g transform={`translate(${left}, ${top})`} stroke={'#333'} strokeWidth={1} fill={'none'}>
<g ref={setRef} strokeWidth={0} /> <g ref={setRef} strokeWidth={0} />
<rect x={0} y={0} width={width} height={height} /> <rect x={0} y={0} width={width} height={height} />
<foreignObject ref={setTooltipRef} width={tooltipWidth} height={tooltipHeight} x={selected.x ?? 0} y={selected.y ?? 0} pointerEvents={'none'}>
<div className={'tooltip right'} style={{ transition: 'opacity .1s ease-in-out', opacity: selected.visible ? 1 : 0 }}>
<Grid>
<GridItem row={1} col={1}>Регулятор:</GridItem>
<GridItem row={1} col={2}>{selected?.id ? regulators[selected.id].label : '---'}</GridItem>
<GridItem row={2} col={1}>Начало:</GridItem>
<GridItem row={2} col={2}>{formatDate(selected?.dateStart) ?? '---'}</GridItem>
<GridItem row={2} col={3}>{selected?.depthStart?.toFixed(2) ?? '---'}</GridItem>
<GridItem row={2} col={4}>м.</GridItem>
<GridItem row={3} col={1}>Конец:</GridItem>
<GridItem row={3} col={2}>{formatDate(selected?.dateEnd) ?? '---'}</GridItem>
<GridItem row={3} col={3}>{selected?.depthEnd?.toFixed(2) ?? '---'}</GridItem>
<GridItem row={3} col={4}>м.</GridItem>
</Grid>
</div>
</foreignObject>
</g> </g>
) )
} }

View File

@ -8,7 +8,7 @@
@arrow-size: 8px; @arrow-size: 8px;
width: 100%; width: 100%;
height: 100% - @arrow-size; height: 100%;
font-size: 13px; font-size: 13px;
color: @color; color: @color;
@ -30,6 +30,7 @@
&.top { &.top {
margin-top: @arrow-size; margin-top: @arrow-size;
height: 100% - @arrow-size;
&::after { &::after {
border-bottom-color: @bg-color; border-bottom-color: @bg-color;
@ -42,6 +43,7 @@
&.bottom { &.bottom {
margin-bottom: @arrow-size; margin-bottom: @arrow-size;
height: 100% - @arrow-size;
&::after { &::after {
border-top-color: @bg-color; border-top-color: @bg-color;
@ -53,8 +55,11 @@
&.left { &.left {
margin-left: @arrow-size; margin-left: @arrow-size;
width: 100% - @arrow-size;
&::after { &::after {
border-right-color: @bg-color; border-right-color: @bg-color;
margin-top: -@arrow-size;
top: 50%; top: 50%;
right: 100%; right: 100%;
} }
@ -62,8 +67,11 @@
&.right { &.right {
margin-right: @arrow-size; margin-right: @arrow-size;
width: 100% - @arrow-size;
&::after { &::after {
border-left-color: @bg-color; border-left-color: @bg-color;
margin-top: -@arrow-size;
top: 50%; top: 50%;
left: 100%; left: 100%;
} }