forked from ddrilling/asb_cloud_front
Merge branch 'dev' of bitbucket.org:autodrilling/asb_cloud_front into dev
This commit is contained in:
commit
af031d94d7
@ -11,6 +11,7 @@ const { RangePicker } = DatePicker
|
||||
export type DateRangeWrapperProps = RangePickerSharedProps<Moment> & {
|
||||
value?: RangeValue<Moment>,
|
||||
isUTC?: boolean
|
||||
allowClear?: boolean
|
||||
}
|
||||
|
||||
const normalizeDates = (value?: RangeValue<Moment>, isUTC?: boolean): RangeValue<Moment> => {
|
||||
@ -21,10 +22,10 @@ const normalizeDates = (value?: RangeValue<Moment>, isUTC?: boolean): RangeValue
|
||||
]
|
||||
}
|
||||
|
||||
export const DateRangeWrapper = memo<DateRangeWrapperProps>(({ value, isUTC, ...other }) => (
|
||||
export const DateRangeWrapper = memo<DateRangeWrapperProps>(({ value, isUTC, allowClear = false, ...other }) => (
|
||||
<RangePicker
|
||||
showTime
|
||||
allowClear={false}
|
||||
allowClear={allowClear}
|
||||
format={defaultFormat}
|
||||
defaultValue={[
|
||||
moment().subtract(1, 'days').startOf('day'),
|
||||
|
@ -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 { Property } from 'csstype'
|
||||
import * as d3 from 'd3'
|
||||
@ -20,6 +20,7 @@ export type D3HorizontalChartProps = {
|
||||
height?: Property.Height
|
||||
data: PercentChartDataType[]
|
||||
offset?: Partial<ChartOffset>
|
||||
afterDraw?: (d: d3.Selection<SVGRectElement, PercentChartDataType, SVGGElement, unknown>) => void
|
||||
}
|
||||
|
||||
const defaultOffset = { top: 50, right: 100, bottom: 50, left: 100 }
|
||||
@ -29,13 +30,14 @@ export const D3HorizontalPercentChart = memo<D3HorizontalChartProps>(({
|
||||
height: givenHeight = '100%',
|
||||
offset: givenOffset,
|
||||
data,
|
||||
afterDraw,
|
||||
}) => {
|
||||
const offset = usePartialProps<ChartOffset>(givenOffset, defaultOffset)
|
||||
|
||||
const [divRef, { width, height }] = useElementSize()
|
||||
const rootRef = useRef<SVGGElement | null>(null)
|
||||
|
||||
const root = useMemo(() => rootRef.current ? d3.select(rootRef.current) : null, [rootRef.current])
|
||||
const root = useCallback(() => rootRef.current ? d3.select(rootRef.current) : null, [rootRef.current])
|
||||
|
||||
const inlineWidth = useMemo(() => width - offset.left - offset.right, [width])
|
||||
const inlineHeight = useMemo(() => height - offset.top - offset.bottom, [height])
|
||||
@ -44,42 +46,50 @@ export const D3HorizontalPercentChart = memo<D3HorizontalChartProps>(({
|
||||
const yScale = useMemo(() => d3.scaleBand().domain(data.map((d) => d.name)).range([0, inlineHeight]).padding(0.25), [data, inlineHeight])
|
||||
|
||||
useEffect(() => { /// Отрисовываем оси X сверху и снизу
|
||||
if (width < 100 || height < 100 || !root) return
|
||||
const r = root()
|
||||
if (width < 100 || height < 100 || !r) return
|
||||
const xAxisTop = d3.axisTop(xScale).tickFormat((d) => `${d}%`).ticks(4).tickSize(-inlineHeight)
|
||||
const xAxisBottom = d3.axisBottom(xScale).tickFormat((d) => `${d}%`).ticks(4)
|
||||
|
||||
root.selectChild<SVGGElement>('.axis.x.bottom').call(xAxisBottom)
|
||||
root.selectChild<SVGGElement>('.axis.x.top').call(xAxisTop)
|
||||
r.selectChild<SVGGElement>('.axis.x.bottom').call(xAxisBottom)
|
||||
r.selectChild<SVGGElement>('.axis.x.top').call(xAxisTop)
|
||||
.selectAll('.tick')
|
||||
.attr('class', 'tick grid-line')
|
||||
}, [root, width, height, xScale, inlineHeight])
|
||||
|
||||
useEffect(() => { /// Отрисовываем ось Y слева
|
||||
if (width < 100 || height < 100 || !root) return
|
||||
root.selectChild<SVGGElement>('.axis.y.left').call(d3.axisLeft(yScale))
|
||||
const r = root()
|
||||
if (width < 100 || height < 100 || !r) return
|
||||
r.selectChild<SVGGElement>('.axis.y.left').call(d3.axisLeft(yScale))
|
||||
}, [root, width, height, yScale])
|
||||
|
||||
useEffect(() => {
|
||||
if (width < 100 || height < 100 || !root) return
|
||||
const r = root()
|
||||
if (width < 100 || height < 100 || !r) return
|
||||
|
||||
const delay = d3.transition().duration(500).ease(d3.easeLinear)
|
||||
|
||||
const rects = root.selectChild('.data').selectAll('rect').data(data)
|
||||
const rects = r.selectChild('.data').selectAll('rect').data(data)
|
||||
rects.enter().append('rect')
|
||||
rects.exit().remove()
|
||||
root.selectChild<SVGGElement>('.data')
|
||||
.selectAll<SVGRectElement, PercentChartDataType>('rect')
|
||||
.attr('fill', (d) => d.color || 'black')
|
||||
.attr('y', (d) => yScale(d.name) ?? null)
|
||||
.attr('height', yScale.bandwidth())
|
||||
.transition(delay)
|
||||
.attr('width', (d) => xScale(d.percent))
|
||||
}, [data, width, height, root, yScale, xScale])
|
||||
|
||||
const selectedRects = r.selectChild<SVGGElement>('.data')
|
||||
.selectAll<SVGRectElement, PercentChartDataType>('rect')
|
||||
|
||||
selectedRects.attr('fill', (d) => d.color || 'black')
|
||||
.attr('y', (d) => yScale(d.name) ?? null)
|
||||
.attr('height', yScale.bandwidth())
|
||||
.transition(delay)
|
||||
.attr('width', (d) => d.percent > 0 ? xScale(d.percent) : 0)
|
||||
|
||||
afterDraw?.(selectedRects)
|
||||
|
||||
}, [data, width, height, root, yScale, xScale, afterDraw])
|
||||
|
||||
return (
|
||||
<LoaderPortal show={false} style={{ width: givenWidth, height: givenHeight }}>
|
||||
<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 className={'axis x top'}></g>
|
||||
<g className={'axis x bottom'} transform={`translate(0, ${inlineHeight})`}></g>
|
||||
|
@ -22,14 +22,14 @@ const subsystemColors = [
|
||||
]
|
||||
|
||||
const tableColumns = [
|
||||
makeColumn('Цвет', 'color', { width: 50, render: (backgroundColor) => (
|
||||
makeColumn('Цвет', 'color', { width: 60, render: (backgroundColor) => (
|
||||
<div className={'table_color'} style={{ backgroundColor }} />
|
||||
)}),
|
||||
makeTextColumn('Подсистема', 'subsystemName'),
|
||||
makeNumericColumn('Использование, %', 'kUsage', undefined, undefined, val => (+val * 100).toFixed(2)),
|
||||
makeNumericColumn('Проходка, м', 'sumDepthInterval'),
|
||||
makeNumericColumn('Время работы, ч', 'usedTimeHours'),
|
||||
makeNumericColumn('Кол-во запусков', 'operationCount', undefined, undefined, makeNumericRender(0)),
|
||||
makeNumericColumn('Использование, %', 'kUsage', undefined, undefined, val => (+val * 100).toFixed(2), 200),
|
||||
makeNumericColumn('Проходка, м', 'sumDepthInterval', undefined, undefined, undefined, 200),
|
||||
makeNumericColumn('Время работы, ч', 'usedTimeHours', undefined, undefined, undefined, 200),
|
||||
makeNumericColumn('Кол-во запусков', 'operationCount', undefined, undefined, makeNumericRender(0), 200),
|
||||
]
|
||||
|
||||
// Выбор доступен только до текущей даты
|
||||
@ -65,15 +65,15 @@ export const OperationTime = memo(() => {
|
||||
if (!well.id) return
|
||||
|
||||
// Ограничение задаётся только если выбраны обе даты
|
||||
const startDate = dateRange[1] ? dateRange[0]?.toISOString() : undefined
|
||||
const endDate = dateRange[1]?.toISOString()
|
||||
const startDate = dateRange?.[1] ? dateRange[0]?.toISOString() : undefined
|
||||
const endDate = dateRange?.[1] ? dateRange[1]?.toISOString() : undefined
|
||||
|
||||
const data = await SubsystemOperationTimeService.getStat(well.id, undefined, startDate, endDate)
|
||||
// Выбираем цвета для подсистем (если цветов не хватает начинаем сначала)
|
||||
const coloredData = arrayOrDefault(data).map((d, i) => ({ ...d, color: subsystemColors[i % subsystemColors.length] }))
|
||||
|
||||
setData(coloredData)
|
||||
setSelected(data.map((d) => d.idSubsystem)) // По-умолчанию выбираем все подсистемы
|
||||
setSelected(data?.map((d) => d.idSubsystem)) // По-умолчанию выбираем все подсистемы
|
||||
},
|
||||
setShowLoader,
|
||||
`Не удалось загрузить данные`,
|
||||
@ -95,6 +95,7 @@ export const OperationTime = memo(() => {
|
||||
value={selected}
|
||||
/>
|
||||
<DateRangeWrapper
|
||||
allowClear
|
||||
onCalendarChange={setDateRange}
|
||||
disabledDate={disabledDates}
|
||||
disabledTime={disabledTimes}
|
||||
|
@ -1,3 +1,3 @@
|
||||
.table_color {
|
||||
padding: 5px 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user