forked from ddrilling/asb_cloud_front
Merged dev into feature/DrillProcessFlow
This commit is contained in:
commit
b4ae4efa43
@ -139,7 +139,7 @@ const _D3HorizontalCursor = <DataType,>({
|
|||||||
if (!mouseState.visible || fixed) return
|
if (!mouseState.visible || fixed) return
|
||||||
|
|
||||||
let top = mouseState.y + offsetY
|
let top = mouseState.y + offsetY
|
||||||
if (top + height >= sizes.chartsHeight) {
|
if (mouseState.y >= sizes.chartsHeight / 2) {
|
||||||
setPosition('bottom')
|
setPosition('bottom')
|
||||||
top = mouseState.y - offsetY - height
|
top = mouseState.y - offsetY - height
|
||||||
} else {
|
} else {
|
||||||
@ -186,7 +186,9 @@ const _D3HorizontalCursor = <DataType,>({
|
|||||||
pointerEvents={fixed ? 'all' : 'none'}
|
pointerEvents={fixed ? 'all' : 'none'}
|
||||||
style={{ transition: 'opacity .1s ease-out', userSelect: fixed ? 'auto' : 'none' }}
|
style={{ transition: 'opacity .1s ease-out', userSelect: fixed ? 'auto' : 'none' }}
|
||||||
>
|
>
|
||||||
<div className={`tooltip ${position} ${className}`}>
|
<div className={`tooltip ${position} ${className}`}
|
||||||
|
style={{height: 'auto', bottom: `${position === 'bottom' ? '0' : ''}`}}
|
||||||
|
>
|
||||||
<div className={'tooltip-content'}>
|
<div className={'tooltip-content'}>
|
||||||
{tooltipBodies[i]}
|
{tooltipBodies[i]}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Form, FormItemProps, Input, InputNumber, Select, Tooltip } from 'antd'
|
import { Button, Checkbox, Form, FormItemProps, Input, InputNumber, Select, Tooltip } from 'antd'
|
||||||
import { memo, useCallback, useEffect, useMemo } from 'react'
|
import { memo, useCallback, useEffect, useMemo } from 'react'
|
||||||
|
|
||||||
import { MinMax } from '@components/d3/types'
|
import { MinMax } from '@components/d3/types'
|
||||||
@ -43,10 +43,12 @@ const _D3MonitoringChartEditor = <DataType,>({
|
|||||||
}, [value])
|
}, [value])
|
||||||
|
|
||||||
const onDomainChange = useCallback((mm: MinMax) => {
|
const onDomainChange = useCallback((mm: MinMax) => {
|
||||||
onSave({ xDomain: {
|
onSave({
|
||||||
|
xDomain: {
|
||||||
min: ('min' in mm) ? mm.min : value.xDomain?.min,
|
min: ('min' in mm) ? mm.min : value.xDomain?.min,
|
||||||
max: ('max' in mm) ? mm.max : value.xDomain?.max,
|
max: ('max' in mm) ? mm.max : value.xDomain?.max,
|
||||||
}})
|
}
|
||||||
|
})
|
||||||
}, [value])
|
}, [value])
|
||||||
|
|
||||||
const onColorChange = useCallback((color: Color) => {
|
const onColorChange = useCallback((color: Color) => {
|
||||||
@ -100,6 +102,14 @@ const _D3MonitoringChartEditor = <DataType,>({
|
|||||||
</Input.Group>
|
</Input.Group>
|
||||||
</Item>
|
</Item>
|
||||||
<Item label={'Цвет линий'}><ColorPicker onChange={onColorChange} value={value.color} /></Item>
|
<Item label={'Цвет линий'}><ColorPicker onChange={onColorChange} value={value.color} /></Item>
|
||||||
|
<Item>
|
||||||
|
<Checkbox
|
||||||
|
checked={value.showCurrentValue}
|
||||||
|
onChange={(e) => onSave({ showCurrentValue: e.target.checked })}
|
||||||
|
>
|
||||||
|
Показать текущее значение сверху
|
||||||
|
</Checkbox>
|
||||||
|
</Item>
|
||||||
</Form>
|
</Form>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import { getByAccessor, getChartClass, getGroupClass, getTicks } from '@componen
|
|||||||
import { renderArea, renderLine, renderNeedle, renderPoint, renderRectArea } from '@components/d3/renders'
|
import { renderArea, renderLine, renderNeedle, renderPoint, renderRectArea } from '@components/d3/renders'
|
||||||
|
|
||||||
import D3MonitoringEditor from './D3MonitoringEditor'
|
import D3MonitoringEditor from './D3MonitoringEditor'
|
||||||
|
import D3MonitoringCurrentValues from './D3MonitoringCurrentValues'
|
||||||
import { D3HorizontalCursor, D3HorizontalCursorSettings } from './D3HorizontalCursor'
|
import { D3HorizontalCursor, D3HorizontalCursorSettings } from './D3HorizontalCursor'
|
||||||
import D3MonitoringLimitChart, { TelemetryRegulators } from './D3MonitoringLimitChart'
|
import D3MonitoringLimitChart, { TelemetryRegulators } from './D3MonitoringLimitChart'
|
||||||
|
|
||||||
@ -55,6 +56,8 @@ export type ExtendedChartDataset<DataType> = ChartDataset<DataType> & {
|
|||||||
xDomain: MinMax
|
xDomain: MinMax
|
||||||
/** Скрыть отображение шкалы графика */
|
/** Скрыть отображение шкалы графика */
|
||||||
hideLabel?: boolean
|
hideLabel?: boolean
|
||||||
|
/** Показать последнее значение сверху графика */
|
||||||
|
showCurrentValue?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ExtendedChartRegistry<DataType> = ChartRegistry<DataType> & ExtendedChartDataset<DataType>
|
export type ExtendedChartRegistry<DataType> = ChartRegistry<DataType> & ExtendedChartDataset<DataType>
|
||||||
@ -291,9 +294,9 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
resetDatasets()
|
resetDatasets()
|
||||||
}, [resetDatasets, resetRegulators])
|
}, [resetDatasets, resetRegulators])
|
||||||
|
|
||||||
useEffect(() => methods?.({ setSettingsVisible }), [methods])
|
useEffect(() => methods?.({ setSettingsVisible }), [methods]) /// Возвращаем в делегат доступные методы
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => { /// Обновляем группы
|
||||||
if (isDev()) {
|
if (isDev()) {
|
||||||
datasets.forEach((sets, i) => {
|
datasets.forEach((sets, i) => {
|
||||||
sets.forEach((set, j) => {
|
sets.forEach((set, j) => {
|
||||||
@ -366,7 +369,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
})
|
})
|
||||||
}, [yAxisConfig, chartArea, datasets, animDurationMs, createAxesGroup])
|
}, [yAxisConfig, chartArea, datasets, animDurationMs, createAxesGroup])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => { /// Обновляем группы и горизонтальные оси
|
||||||
const axesGroups = axesArea()
|
const axesGroups = axesArea()
|
||||||
.selectAll('.charts-group')
|
.selectAll('.charts-group')
|
||||||
.data(groups)
|
.data(groups)
|
||||||
@ -542,7 +545,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
return <line key={`${i}`} x1={x} x2={x} y1={sizes.chartsTop} y2={offset.top + sizes.inlineHeight} />
|
return <line key={`${i}`} x1={x} x2={x} y1={sizes.chartsTop} y2={offset.top + sizes.inlineHeight} />
|
||||||
})}
|
})}
|
||||||
</g>
|
</g>
|
||||||
<D3MonitoringLimitChart
|
<D3MonitoringLimitChart<DataType>
|
||||||
regulators={regulators}
|
regulators={regulators}
|
||||||
data={data}
|
data={data}
|
||||||
yAxis={yAxis}
|
yAxis={yAxis}
|
||||||
@ -552,6 +555,12 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
top={sizes.chartsTop}
|
top={sizes.chartsTop}
|
||||||
zoneWidth={sizes.inlineWidth}
|
zoneWidth={sizes.inlineWidth}
|
||||||
/>
|
/>
|
||||||
|
<D3MonitoringCurrentValues<DataType>
|
||||||
|
groups={groups}
|
||||||
|
data={data}
|
||||||
|
left={offset.left}
|
||||||
|
sizes={sizes}
|
||||||
|
/>
|
||||||
<D3MouseZone width={width} height={height} offset={{ ...offset, top: sizes.chartsTop }}>
|
<D3MouseZone width={width} height={height} offset={{ ...offset, top: sizes.chartsTop }}>
|
||||||
<D3HorizontalCursor
|
<D3HorizontalCursor
|
||||||
{...plugins?.cursor}
|
{...plugins?.cursor}
|
||||||
@ -559,6 +568,7 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
groups={groups}
|
groups={groups}
|
||||||
sizes={sizes}
|
sizes={sizes}
|
||||||
data={data}
|
data={data}
|
||||||
|
height={height}
|
||||||
/>
|
/>
|
||||||
</D3MouseZone>
|
</D3MouseZone>
|
||||||
</svg>
|
</svg>
|
||||||
@ -581,6 +591,6 @@ const _D3MonitoringCharts = <DataType extends Record<string, unknown>>({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const D3MonitoringCharts = memo(_D3MonitoringCharts)
|
export const D3MonitoringCharts = memo(_D3MonitoringCharts) as typeof _D3MonitoringCharts
|
||||||
|
|
||||||
export default D3MonitoringCharts
|
export default D3MonitoringCharts
|
||||||
|
32
src/components/d3/monitoring/D3MonitoringCurrentValues.tsx
Normal file
32
src/components/d3/monitoring/D3MonitoringCurrentValues.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { memo } from 'react'
|
||||||
|
|
||||||
|
import { ChartGroup, ChartSizes } from '@components/d3/monitoring/D3MonitoringCharts'
|
||||||
|
import { makeDisplayValue } from '@utils'
|
||||||
|
|
||||||
|
export type D3MonitoringCurrentValuesProps<DataType> = {
|
||||||
|
groups: ChartGroup<DataType>[]
|
||||||
|
data: DataType[]
|
||||||
|
left: number
|
||||||
|
sizes: ChartSizes
|
||||||
|
}
|
||||||
|
|
||||||
|
const display = makeDisplayValue({ def: '---', fixed: 2 })
|
||||||
|
|
||||||
|
const _D3MonitoringCurrentValues = <DataType,>({ groups, data, left, sizes }: D3MonitoringCurrentValuesProps<DataType>) => (
|
||||||
|
<g transform={`translate(${left}, ${sizes.chartsTop})`} pointerEvents={'none'}>
|
||||||
|
{groups.map((group) => (
|
||||||
|
<g key={group.key} transform={`translate(${sizes.groupLeft(group.key)}, 0)`}>
|
||||||
|
{group.charts.filter((chart) => chart.showCurrentValue).map((chart, i) => (
|
||||||
|
<g key={chart.key} stroke={'white'} fill={chart.color} strokeWidth={3} paintOrder={'stroke'}>
|
||||||
|
<text x={sizes.groupWidth / 2 - 10} textAnchor={'end'} y={15 + i * 20}>{chart.shortLabel ?? chart.label}:</text>
|
||||||
|
<text x={sizes.groupWidth / 2 + 10} textAnchor={'start'} y={15 + i * 20}>{display(chart.x((data.at(-1) ?? {}) as any))}</text>
|
||||||
|
</g>
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
))}
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const D3MonitoringCurrentValues = memo(_D3MonitoringCurrentValues) as typeof _D3MonitoringCurrentValues
|
||||||
|
|
||||||
|
export default D3MonitoringCurrentValues
|
@ -255,7 +255,7 @@ const Archive = memo(() => {
|
|||||||
plugins={{
|
plugins={{
|
||||||
menu: { enabled: false },
|
menu: { enabled: false },
|
||||||
cursor: {
|
cursor: {
|
||||||
width: 200,
|
width: 220,
|
||||||
render: cursorRender,
|
render: cursorRender,
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -6,7 +6,7 @@ import { useWell } from '@asb/context'
|
|||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { DateRangeWrapper } from '@components/Table'
|
import { DateRangeWrapper } from '@components/Table'
|
||||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { getPermissions, arrayOrDefault, range, wrapPrivateComponent } from '@utils'
|
import { getPermissions, arrayOrDefault, range, wrapPrivateComponent, pretify } from '@utils'
|
||||||
import { DetectedOperationService, DrillerService, TelemetryDataSaubService } from '@api'
|
import { DetectedOperationService, DrillerService, TelemetryDataSaubService } from '@api'
|
||||||
|
|
||||||
import DrillerList from './DrillerList'
|
import DrillerList from './DrillerList'
|
||||||
@ -16,6 +16,7 @@ import OperationsChart from './OperationsChart'
|
|||||||
import OperationsTable from './OperationsTable'
|
import OperationsTable from './OperationsTable'
|
||||||
|
|
||||||
import '@styles/detected_operations.less'
|
import '@styles/detected_operations.less'
|
||||||
|
import { unique } from '@asb/utils/filters'
|
||||||
|
|
||||||
const Operations = memo(() => {
|
const Operations = memo(() => {
|
||||||
const [isLoading, setIsLoading] = useState(false)
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
@ -61,6 +62,14 @@ const Operations = memo(() => {
|
|||||||
{ actionName: 'Получение списка определённых операций', well }
|
{ actionName: 'Получение списка определённых операций', well }
|
||||||
), [well, dates, selectedCategory])
|
), [well, dates, selectedCategory])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!data?.operations) return
|
||||||
|
const maxTarget = Math.max(...data.operations?.map((op) => op.operationValue?.targetValue || 0))
|
||||||
|
const uniqueOps = data.operations?.map((op) => op.value || 0).filter(unique)
|
||||||
|
const value = uniqueOps.reduce((out, op) => out + op, 0) / uniqueOps.length * 3 / 2
|
||||||
|
setYDomain(pretify(Math.max(maxTarget, value)))
|
||||||
|
}, [data])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (permissions.driller.get)
|
if (permissions.driller.get)
|
||||||
updateDrillers()
|
updateDrillers()
|
||||||
|
@ -28,7 +28,7 @@ export const cursorRender = (group, data) => {
|
|||||||
<Fragment key={chart.key}>
|
<Fragment key={chart.key}>
|
||||||
<GridItem row={i+2} col={1} style={{ padding: '4px 0' }}>{getChartIcon(chart)}</GridItem>
|
<GridItem row={i+2} col={1} style={{ padding: '4px 0' }}>{getChartIcon(chart)}</GridItem>
|
||||||
<GridItem row={i+2} col={2}>{chart.shortLabel || chart.label}</GridItem>
|
<GridItem row={i+2} col={2}>{chart.shortLabel || chart.label}</GridItem>
|
||||||
<GridItem row={i+2} col={3} style={{ paddingRight: 0 }}>{xFormat(chart)}</GridItem>
|
<GridItem row={i+2} col={3} style={{ paddingRight: 0, textAlign: 'end' }}>{xFormat(chart)}</GridItem>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
@ -295,7 +295,7 @@ const TelemetryView = memo(() => {
|
|||||||
plugins={{
|
plugins={{
|
||||||
menu: { enabled: false },
|
menu: { enabled: false },
|
||||||
cursor: {
|
cursor: {
|
||||||
width: 200,
|
width: 220,
|
||||||
render: cursorRender,
|
render: cursorRender,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
@ -8,7 +8,7 @@ import { useWell } from '@asb/context'
|
|||||||
import { D3Chart } from '@components/d3'
|
import { D3Chart } from '@components/d3'
|
||||||
import LoaderPortal from '@components/LoaderPortal'
|
import LoaderPortal from '@components/LoaderPortal'
|
||||||
import { invokeWebApiWrapperAsync } from '@components/factory'
|
import { invokeWebApiWrapperAsync } from '@components/factory'
|
||||||
import { formatDate, fractionalSum, wrapPrivateComponent, getOperations } from '@utils'
|
import { formatDate, fractionalSum, wrapPrivateComponent, getOperations, pretify } from '@utils'
|
||||||
|
|
||||||
import TLPie from './TLPie'
|
import TLPie from './TLPie'
|
||||||
import TLChart from './TLChart'
|
import TLChart from './TLChart'
|
||||||
@ -21,10 +21,26 @@ import '@styles/index.css'
|
|||||||
import '@styles/tvd.less'
|
import '@styles/tvd.less'
|
||||||
|
|
||||||
const operationsColors = [
|
const operationsColors = [
|
||||||
'#1abc9c', '#16a085', '#2ecc71', '#27ae60', '#3498db',
|
'#1abc9c',
|
||||||
'#2980b9', '#9b59b6', '#8e44ad', '#34495e', '#2c3e50',
|
'#16a085',
|
||||||
'#f1c40f', '#f39c12', '#e67e22', '#d35400', '#e74c3c',
|
'#2ecc71',
|
||||||
'#c0392b', '#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d',
|
'#27ae60',
|
||||||
|
'#3498db',
|
||||||
|
'#2980b9',
|
||||||
|
'#9b59b6',
|
||||||
|
'#8e44ad',
|
||||||
|
'#34495e',
|
||||||
|
'#2c3e50',
|
||||||
|
'#f1c40f',
|
||||||
|
'#f39c12',
|
||||||
|
'#e67e22',
|
||||||
|
'#d35400',
|
||||||
|
'#e74c3c',
|
||||||
|
'#c0392b',
|
||||||
|
'#ecf0f1',
|
||||||
|
'#bdc3c7',
|
||||||
|
'#95a5a6',
|
||||||
|
'#7f8c8d',
|
||||||
]
|
]
|
||||||
|
|
||||||
export const makeGetColor = (types) => (type) => {
|
export const makeGetColor = (types) => (type) => {
|
||||||
@ -35,14 +51,17 @@ export const makeGetColor = (types) => (type) => {
|
|||||||
return i < 0 ? operationsColors[type] : operationsColors[i]
|
return i < 0 ? operationsColors[type] : operationsColors[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
const Item = ({ label, children, ...other }) => (<div className={'tvd-input-group'} {...other}><span>{label}: </span>{children}</div>)
|
const Item = ({ label, children, ...other }) => (
|
||||||
|
<div className={'tvd-input-group'} {...other}>
|
||||||
|
<span>{label}: </span>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
const numericRender = (d) => d && Number.isFinite(+d) ? (+d).toFixed(2) : '-'
|
const numericRender = (d) => (d && Number.isFinite(+d) ? (+d).toFixed(2) : '-')
|
||||||
|
|
||||||
const tooltipRender = (data) => {
|
const tooltipRender = (data) => {
|
||||||
if (!data || data.length <= 0) return (
|
if (!data || data.length <= 0) return <span>Данных нет</span>
|
||||||
<span>Данных нет</span>
|
|
||||||
)
|
|
||||||
|
|
||||||
return data.map(({ chart, data }) => {
|
return data.map(({ chart, data }) => {
|
||||||
const xFormat = (d) => chart.xAxis.format?.(d) ?? `${numericRender(d)} ${chart.xAxis.unit ?? ''}`
|
const xFormat = (d) => chart.xAxis.format?.(d) ?? `${numericRender(d)} ${chart.xAxis.unit ?? ''}`
|
||||||
@ -57,19 +76,23 @@ const tooltipRender = (data) => {
|
|||||||
{data.slice(0, 2).map((d, i) => {
|
{data.slice(0, 2).map((d, i) => {
|
||||||
const text = `${xFormat(chart.x(d))} :: ${yFormat(chart.y(d))}`
|
const text = `${xFormat(chart.x(d))} :: ${yFormat(chart.y(d))}`
|
||||||
|
|
||||||
const href = ['plan', 'fact'].includes(chart.key) && `/well/${d.idWell}/operations/${chart.key}/?selectedId=${d.id}`
|
const href =
|
||||||
|
['plan', 'fact'].includes(chart.key) &&
|
||||||
|
`/well/${d.idWell}/operations/${chart.key}/?selectedId=${d.id}`
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`${i}`}>
|
<div key={`${i}`}>
|
||||||
{href ? (
|
{href ? (
|
||||||
<Link style={{ color: 'inherit', textDecoration: 'underline' }} to={href} title={'Перейти к таблице операций'}>
|
<Link
|
||||||
|
style={{ color: 'inherit', textDecoration: 'underline' }}
|
||||||
|
to={href}
|
||||||
|
title={'Перейти к таблице операций'}
|
||||||
|
>
|
||||||
<span style={{ marginRight: '5px' }}>{text}</span>
|
<span style={{ marginRight: '5px' }}>{text}</span>
|
||||||
<LinkOutlined />
|
<LinkOutlined />
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span title={'Нельзя осуществить переход к этой операции'}>
|
<span title={'Нельзя осуществить переход к этой операции'}>{text}</span>
|
||||||
{text}
|
|
||||||
</span>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -89,7 +112,7 @@ const xAxis = {
|
|||||||
type: 'linear',
|
type: 'linear',
|
||||||
accessor: 'day',
|
accessor: 'day',
|
||||||
unit: 'день',
|
unit: 'день',
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ticks = {
|
const ticks = {
|
||||||
@ -105,27 +128,17 @@ const ticks = {
|
|||||||
x: {
|
x: {
|
||||||
visible: true,
|
visible: true,
|
||||||
count: d3.timeDay.every(1),
|
count: d3.timeDay.every(1),
|
||||||
format: (d, i) => i % 2 === 0 ? formatDate(d, undefined, 'YYYY-MM-DD') : '',
|
format: (d, i) => (i % 2 === 0 ? formatDate(d, undefined, 'YYYY-MM-DD') : ''),
|
||||||
},
|
},
|
||||||
y: { visible: true },
|
y: { visible: true },
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const domain = {
|
|
||||||
date: {
|
|
||||||
y: { min: 4500, max: 0 },
|
|
||||||
},
|
},
|
||||||
day: {
|
|
||||||
x: { min: 0 },
|
|
||||||
y: { min: 4500, max: 0 },
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins = {
|
const plugins = {
|
||||||
tooltip: { enabled: true, limit: 3, height: 200, render: tooltipRender },
|
tooltip: { enabled: true, limit: 3, height: 200, render: tooltipRender },
|
||||||
menu: { enabled: false },
|
menu: { enabled: false },
|
||||||
legend: { enabled: true, offset: { x: 400 }, type: 'horizontal' },
|
legend: { enabled: true, offset: { x: 400 }, type: 'horizontal' },
|
||||||
cursor: { enabled: false }
|
cursor: { enabled: false },
|
||||||
}
|
}
|
||||||
|
|
||||||
const makeDataset = (key, label, color, width, radius, dash) => ({
|
const makeDataset = (key, label, color, width, radius, dash) => ({
|
||||||
@ -146,7 +159,7 @@ const makeDataset = (key, label, color, width, radius, dash) => ({
|
|||||||
fillOpacity: 0.1,
|
fillOpacity: 0.1,
|
||||||
shape: 'vline',
|
shape: 'vline',
|
||||||
strokeWidth: 1.5,
|
strokeWidth: 1.5,
|
||||||
radius
|
radius,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -175,6 +188,25 @@ const Tvd = memo(({ well: givenWell, title, ...other }) => {
|
|||||||
return { ...operations, withoutNpt }
|
return { ...operations, withoutNpt }
|
||||||
}, [operations])
|
}, [operations])
|
||||||
|
|
||||||
|
const domain = useMemo(() => {
|
||||||
|
const maxValue = Math.max(
|
||||||
|
...Object.entries(chartData)
|
||||||
|
.map(([_, ops]) => Math.max(...ops.map((op) => op.depth).filter(Boolean)))
|
||||||
|
.filter(Boolean)
|
||||||
|
)
|
||||||
|
const minValue = pretify(maxValue)
|
||||||
|
|
||||||
|
return {
|
||||||
|
date: {
|
||||||
|
y: { min: minValue, max: 0 },
|
||||||
|
},
|
||||||
|
day: {
|
||||||
|
x: { min: 0 },
|
||||||
|
y: { min: minValue, max: 0 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, [chartData])
|
||||||
|
|
||||||
const datasets = useMemo(() => {
|
const datasets = useMemo(() => {
|
||||||
const radius = pointsEnabled ? 6 : 1
|
const radius = pointsEnabled ? 6 : 1
|
||||||
|
|
||||||
@ -202,7 +234,10 @@ const Tvd = memo(({ well: givenWell, title, ...other }) => {
|
|||||||
<h2>{title || 'График Глубина-день'}</h2>
|
<h2>{title || 'График Глубина-день'}</h2>
|
||||||
<Item label={'Ось времени'} style={{ marginLeft: 50 }}>
|
<Item label={'Ось времени'} style={{ marginLeft: 50 }}>
|
||||||
<Segmented
|
<Segmented
|
||||||
options={[{ label: 'Дата', value: 'date' }, { label: 'Дни со старта', value: 'day' }]}
|
options={[
|
||||||
|
{ label: 'Дата', value: 'date' },
|
||||||
|
{ label: 'Дни со старта', value: 'day' },
|
||||||
|
]}
|
||||||
onChange={setXLabel}
|
onChange={setXLabel}
|
||||||
value={xLabel}
|
value={xLabel}
|
||||||
title={'Нажмите для переключения горизонтальной оси'}
|
title={'Нажмите для переключения горизонтальной оси'}
|
||||||
@ -251,7 +286,7 @@ const Tvd = memo(({ well: givenWell, title, ...other }) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export default wrapPrivateComponent(Tvd, {
|
export default wrapPrivateComponent(Tvd, {
|
||||||
requirements: [ 'OperationStat.get', 'DetectedOperation.get' ],
|
requirements: ['OperationStat.get', 'DetectedOperation.get'],
|
||||||
title: 'TVD',
|
title: 'TVD',
|
||||||
route: 'tvd',
|
route: 'tvd',
|
||||||
})
|
})
|
||||||
|
@ -25,6 +25,15 @@ export const limitValue = <T,>(min: T, max: T) => (value: T) => {
|
|||||||
*/
|
*/
|
||||||
export const range = (end: number, start: number = 0) => Array.from({ length: end - start }, (_, i) => start + i)
|
export const range = (end: number, start: number = 0) => Array.from({ length: end - start }, (_, i) => start + i)
|
||||||
|
|
||||||
|
export const pretify = (n: number): number | null => {
|
||||||
|
if (!Number.isFinite(n)) return null
|
||||||
|
let i = 0
|
||||||
|
for (; Math.abs(n) >= 100; i++) n /= 10
|
||||||
|
const sign = Math.sign(n), nn = Math.floor(n / 10)
|
||||||
|
n = (Math.abs(n) % 10 < 5) ? nn * 10 + sign * 5 : (nn + sign) * 10
|
||||||
|
return n * Math.pow(10, i)
|
||||||
|
}
|
||||||
|
|
||||||
export type DisplayValueOptions = {
|
export type DisplayValueOptions = {
|
||||||
def?: ReactNode
|
def?: ReactNode
|
||||||
inf?: ReactNode | ((v: number) => ReactNode)
|
inf?: ReactNode | ((v: number) => ReactNode)
|
||||||
|
Loading…
Reference in New Issue
Block a user