forked from ddrilling/asb_cloud_front
Добавлено автоматическое масштабирование для TVD и Операций
This commit is contained in:
parent
00f7d6e9da
commit
1dd19399e5
@ -6,7 +6,7 @@ import { useWell } from '@asb/context'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
import { DateRangeWrapper } from '@components/Table'
|
||||
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 DrillerList from './DrillerList'
|
||||
@ -16,6 +16,7 @@ import OperationsChart from './OperationsChart'
|
||||
import OperationsTable from './OperationsTable'
|
||||
|
||||
import '@styles/detected_operations.less'
|
||||
import { unique } from '@asb/utils/filters'
|
||||
|
||||
const Operations = memo(() => {
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
@ -61,6 +62,14 @@ const Operations = memo(() => {
|
||||
{ actionName: 'Получение списка определённых операций', well }
|
||||
), [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(() => {
|
||||
if (permissions.driller.get)
|
||||
updateDrillers()
|
||||
|
@ -8,7 +8,7 @@ import { useWell } from '@asb/context'
|
||||
import { D3Chart } from '@components/d3'
|
||||
import LoaderPortal from '@components/LoaderPortal'
|
||||
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 TLChart from './TLChart'
|
||||
@ -21,10 +21,26 @@ import '@styles/index.css'
|
||||
import '@styles/tvd.less'
|
||||
|
||||
const operationsColors = [
|
||||
'#1abc9c', '#16a085', '#2ecc71', '#27ae60', '#3498db',
|
||||
'#2980b9', '#9b59b6', '#8e44ad', '#34495e', '#2c3e50',
|
||||
'#f1c40f', '#f39c12', '#e67e22', '#d35400', '#e74c3c',
|
||||
'#c0392b', '#ecf0f1', '#bdc3c7', '#95a5a6', '#7f8c8d',
|
||||
'#1abc9c',
|
||||
'#16a085',
|
||||
'#2ecc71',
|
||||
'#27ae60',
|
||||
'#3498db',
|
||||
'#2980b9',
|
||||
'#9b59b6',
|
||||
'#8e44ad',
|
||||
'#34495e',
|
||||
'#2c3e50',
|
||||
'#f1c40f',
|
||||
'#f39c12',
|
||||
'#e67e22',
|
||||
'#d35400',
|
||||
'#e74c3c',
|
||||
'#c0392b',
|
||||
'#ecf0f1',
|
||||
'#bdc3c7',
|
||||
'#95a5a6',
|
||||
'#7f8c8d',
|
||||
]
|
||||
|
||||
export const makeGetColor = (types) => (type) => {
|
||||
@ -35,14 +51,17 @@ export const makeGetColor = (types) => (type) => {
|
||||
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) => {
|
||||
if (!data || data.length <= 0) return (
|
||||
<span>Данных нет</span>
|
||||
)
|
||||
if (!data || data.length <= 0) return <span>Данных нет</span>
|
||||
|
||||
return data.map(({ chart, data }) => {
|
||||
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) => {
|
||||
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 (
|
||||
<div key={`${i}`}>
|
||||
{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>
|
||||
<LinkOutlined />
|
||||
</Link>
|
||||
) : (
|
||||
<span title={'Нельзя осуществить переход к этой операции'}>
|
||||
{text}
|
||||
</span>
|
||||
<span title={'Нельзя осуществить переход к этой операции'}>{text}</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@ -89,7 +112,7 @@ const xAxis = {
|
||||
type: 'linear',
|
||||
accessor: 'day',
|
||||
unit: 'день',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const ticks = {
|
||||
@ -105,27 +128,17 @@ const ticks = {
|
||||
x: {
|
||||
visible: true,
|
||||
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 },
|
||||
}
|
||||
}
|
||||
|
||||
const domain = {
|
||||
date: {
|
||||
y: { min: 4500, max: 0 },
|
||||
},
|
||||
day: {
|
||||
x: { min: 0 },
|
||||
y: { min: 4500, max: 0 },
|
||||
}
|
||||
}
|
||||
|
||||
const plugins = {
|
||||
tooltip: { enabled: true, limit: 3, height: 200, render: tooltipRender },
|
||||
menu: { enabled: false },
|
||||
legend: { enabled: true, offset: { x: 400 }, type: 'horizontal' },
|
||||
cursor: { enabled: false }
|
||||
cursor: { enabled: false },
|
||||
}
|
||||
|
||||
const makeDataset = (key, label, color, width, radius, dash) => ({
|
||||
@ -146,7 +159,7 @@ const makeDataset = (key, label, color, width, radius, dash) => ({
|
||||
fillOpacity: 0.1,
|
||||
shape: 'vline',
|
||||
strokeWidth: 1.5,
|
||||
radius
|
||||
radius,
|
||||
},
|
||||
})
|
||||
|
||||
@ -175,6 +188,25 @@ const Tvd = memo(({ well: givenWell, title, ...other }) => {
|
||||
return { ...operations, withoutNpt }
|
||||
}, [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 radius = pointsEnabled ? 6 : 1
|
||||
|
||||
@ -202,7 +234,10 @@ const Tvd = memo(({ well: givenWell, title, ...other }) => {
|
||||
<h2>{title || 'График Глубина-день'}</h2>
|
||||
<Item label={'Ось времени'} style={{ marginLeft: 50 }}>
|
||||
<Segmented
|
||||
options={[{ label: 'Дата', value: 'date' }, { label: 'Дни со старта', value: 'day' }]}
|
||||
options={[
|
||||
{ label: 'Дата', value: 'date' },
|
||||
{ label: 'Дни со старта', value: 'day' },
|
||||
]}
|
||||
onChange={setXLabel}
|
||||
value={xLabel}
|
||||
title={'Нажмите для переключения горизонтальной оси'}
|
||||
|
@ -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 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 = {
|
||||
def?: ReactNode
|
||||
inf?: ReactNode | ((v: number) => ReactNode)
|
||||
|
Loading…
Reference in New Issue
Block a user