На странице Наработка добавлен сброс даты и выделение данных при наведении

This commit is contained in:
ts_salikhov 2022-10-05 14:20:39 +04:00
parent 74b309ee87
commit be7e76acf7
3 changed files with 68 additions and 27 deletions

View File

@ -11,6 +11,7 @@ const { RangePicker } = DatePicker
export type DateRangeWrapperProps = RangePickerSharedProps<Moment> & { export type DateRangeWrapperProps = RangePickerSharedProps<Moment> & {
value?: RangeValue<Moment>, value?: RangeValue<Moment>,
isUTC?: boolean isUTC?: boolean
allowClear?: boolean
} }
const normalizeDates = (value?: RangeValue<Moment>, isUTC?: boolean): RangeValue<Moment> => { 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 <RangePicker
showTime showTime
allowClear={false} allowClear={allowClear}
format={defaultFormat} format={defaultFormat}
defaultValue={[ defaultValue={[
moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').startOf('day'),

View File

@ -7,7 +7,7 @@ import { useElementSize } from 'usehooks-ts'
import '@styles/d3.less' import '@styles/d3.less'
type DataType = { export type HorizontalChartDataType = {
name: string name: string
percent: number percent: number
} }
@ -15,16 +15,22 @@ type DataType = {
type D3HorizontalChartProps = { type D3HorizontalChartProps = {
width?: string width?: string
height?: string height?: string
data: DataType[] data: HorizontalChartDataType[]
colors?: string[] colors?: string[]
selected?: string | null
onMouseOver?: (e: MouseEvent, d: HorizontalChartDataType) => void
onMouseOut?: (e: MouseEvent, d: HorizontalChartDataType) => void
} }
const D3HorizontalChart = memo(( export const D3HorizontalChart = memo((
{ {
width: givenWidth = '100%', width: givenWidth = '100%',
height: givenHeight = '100%', height: givenHeight = '100%',
selected,
data, data,
colors colors,
onMouseOver,
onMouseOut,
}: D3HorizontalChartProps) => { }: D3HorizontalChartProps) => {
const [rootRef, { width, height }] = useElementSize() const [rootRef, { width, height }] = useElementSize()
@ -54,6 +60,7 @@ const D3HorizontalChart = memo((
const y = d3.scaleBand() const y = d3.scaleBand()
.domain(names) .domain(names)
.range([0, chartHeight]) .range([0, chartHeight])
.padding(0.25)
// axes // axes
@ -113,16 +120,17 @@ const D3HorizontalChart = memo((
.attr('fill', (d, i) => colors ? colors[i] : 'black') .attr('fill', (d, i) => colors ? colors[i] : 'black')
.attr('y', d => String(y(d.name))) .attr('y', d => String(y(d.name)))
.attr('height', y.bandwidth()) .attr('height', y.bandwidth())
.transition()
.duration(1000)
.ease(d3.easeLinear)
.attr('width', d => d.percent >= 0 ? x(d.percent) : 0) .attr('width', d => d.percent >= 0 ? x(d.percent) : 0)
.attr('stroke', d => selected && d.name === selected ? 'black' : '')
.attr('stroke-width', d => selected && d.name === selected ? '2' : '0')
.on('mouseover', onMouseOver ? onMouseOver : () => {})
.on('mouseout', onMouseOut ? onMouseOut : () => {})
}) })
return () => { return () => {
svg.remove() svg.remove()
} }
}, [width, height, data]) }, [width, height, data, colors, selected, onMouseOver, onMouseOut])
return ( return (
<LoaderPortal show={false} style={{width: givenWidth, height: givenHeight}}> <LoaderPortal show={false} style={{width: givenWidth, height: givenHeight}}>

View File

@ -5,7 +5,7 @@ import { Moment } from 'moment'
import { DateRangeWrapper, makeColumn, makeNumericRender, Table } from '@components/Table' import { DateRangeWrapper, makeColumn, makeNumericRender, Table } from '@components/Table'
import LoaderPortal from '@components/LoaderPortal' import LoaderPortal from '@components/LoaderPortal'
import { arrayOrDefault, wrapPrivateComponent } from '@utils' import { arrayOrDefault, wrapPrivateComponent } from '@utils'
import D3HorizontalChart from '@components/d3/D3HorizontalChart' import { D3HorizontalChart, HorizontalChartDataType } from '@components/d3/D3HorizontalChart'
import { useWell } from '@asb/context' import { useWell } from '@asb/context'
import { invokeWebApiWrapperAsync } from '@components/factory' import { invokeWebApiWrapperAsync } from '@components/factory'
import { SubsystemOperationTimeService } from '@api' import { SubsystemOperationTimeService } from '@api'
@ -49,22 +49,50 @@ const tableColumns = [
<div style={{ backgroundColor: color, padding: '5px 0' }} /> <div style={{ backgroundColor: color, padding: '5px 0' }} />
) }), ) }),
makeColumn('Подсистема', 'subsystemName'), makeColumn('Подсистема', 'subsystemName'),
makeColumn('% использования', 'kUsage', { render: val => (+val * 100).toFixed(2) }), makeColumn('% использования', 'kUsage', { width: 200, render: val => makeNumericRender(2)(+val * 100) }),
makeColumn('Проходка, м', 'sumDepthInterval', {render: makeNumericRender(2)}), makeColumn('Проходка, м', 'sumDepthInterval', { width: 200, render: makeNumericRender(2) }),
makeColumn('Время работы, ч', 'usedTimeHours', {render: makeNumericRender(2)}), makeColumn('Время работы, ч', 'usedTimeHours', { width: 200, render: makeNumericRender(2) }),
makeColumn('Кол-во запусков', 'operationCount'), makeColumn('Кол-во запусков', 'operationCount', { width: 200, render: makeNumericRender(0) }),
] ]
const OperationTime = memo(() => { const OperationTime = memo(() => {
const [showLoader, setShowLoader] = useState(false) const [showLoader, setShowLoader] = useState(false)
const [data, setData] = useState<DataType[]>([]) const [data, setData] = useState<DataType[]>([])
const [selectedData, setSelectedData] = useState<DataType[]>([]) const [selectedData, setSelectedData] = useState<DataType[]>([])
const [dateRange, setDateRange] = useState<Moment[]>([]) const [dateRange, setDateRange] = useState<Moment[] | null>([])
const [selected, setSelected] = useState<string | null>(null)
const [childrenData, setChildrenData] = useState<ReactNode[]>([]) const [childrenData, setChildrenData] = useState<ReactNode[]>([])
const [well] = useWell() const [well] = useWell()
const errorNotifyText = `Не удалось загрузить данные` const errorNotifyText = `Не удалось загрузить данные`
const onRow = useCallback((item: DataType) => {
const out = {
onMouseEnter: () => {
setSelected(item.subsystemName)
},
onMouseLeave: () => {
setSelected(null)
},
style: {}
}
if (item.subsystemName === selected) {
out.style = { background: '#FAFAFA', fontSize: '16px', fontWeight: '600' }
}
return out
}, [selected])
const onMouseOver = useCallback(function (e: MouseEvent, d: HorizontalChartDataType) {
setSelected(d.name)
}, [])
const onMouseOut = useCallback(function (e: MouseEvent, d: HorizontalChartDataType) {
setSelected(null)
}, [])
useEffect(() => { useEffect(() => {
invokeWebApiWrapperAsync( invokeWebApiWrapperAsync(
async () => { async () => {
@ -73,8 +101,8 @@ const OperationTime = memo(() => {
const responseData:DataType[] = arrayOrDefault(await SubsystemOperationTimeService.getStat( const responseData:DataType[] = arrayOrDefault(await SubsystemOperationTimeService.getStat(
well.id, well.id,
undefined, undefined,
dateRange[1] ? dateRange[0]?.toISOString() : undefined, dateRange && dateRange[1] ? dateRange[0]?.toISOString() : undefined,
dateRange[1]?.toISOString(), dateRange && dateRange[1] ? dateRange[1].toISOString() : undefined,
)) ))
setData(responseData) setData(responseData)
setSelectedData(responseData) setSelectedData(responseData)
@ -124,25 +152,29 @@ const OperationTime = memo(() => {
</Col> </Col>
<Col span={6}> <Col span={6}>
<DateRangeWrapper <DateRangeWrapper
allowClear
allowEmpty={[true, true]}
onCalendarChange={(dateRange: any) => setDateRange(dateRange)} onCalendarChange={(dateRange: any) => setDateRange(dateRange)}
value={[dateRange[0], dateRange[1]]} value={[dateRange && dateRange[0], dateRange && dateRange[1]]}
/> />
</Col> </Col>
</Row> </Row>
<div style={{width: '100%', height: '50vh'}}> <D3HorizontalChart
<D3HorizontalChart data={selectedData.map(item => ({name: item.subsystemName, percent: item.kUsage * 100}))}
data={selectedData.map(item => ({name: item.subsystemName, percent: item.kUsage * 100}))} colors={subsystemColors}
colors={subsystemColors} selected={selected}
width={'100%'} width={'100%'}
height={'50vh'} height={'50vh'}
/> onMouseOver={onMouseOver}
</div> onMouseOut={onMouseOut}
/>
<Table <Table
size={'small'} size={'small'}
columns={tableColumns} columns={tableColumns}
dataSource={selectedData.map((d, i) => ({...d, color: subsystemColors[i]}))} dataSource={selectedData.map((d, i) => ({...d, color: subsystemColors[i]}))}
scroll={{ y: '25vh', x: true }} scroll={{ y: '25vh', x: true }}
pagination={false} pagination={false}
onRow={onRow}
/> />
</LoaderPortal> </LoaderPortal>
) )