forked from ddrilling/asb_cloud_front
Отображение ROP добавлено
This commit is contained in:
parent
cae068e7b3
commit
46c8b1fe73
@ -8,8 +8,10 @@ import {
|
||||
PointElement,
|
||||
LineElement,
|
||||
ChartData,
|
||||
ChartTypeRegistry,
|
||||
ChartOptions} from 'chart.js'
|
||||
ChartOptions,
|
||||
ChartType,
|
||||
ChartDataset
|
||||
} from 'chart.js'
|
||||
import 'chartjs-adapter-moment'
|
||||
import ChartDataLabels from 'chartjs-plugin-datalabels'
|
||||
import zoomPlugin from 'chartjs-plugin-zoom'
|
||||
@ -25,16 +27,10 @@ Chart.register(
|
||||
zoomPlugin
|
||||
)
|
||||
|
||||
const defaultOptions = {
|
||||
const defaultOptions: ChartOptions = {
|
||||
responsive: true,
|
||||
aspectRatio: 0.45,
|
||||
animation: false,
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
callbacks: {
|
||||
label: (tooltipItem:any) => tooltipItem.yLabel
|
||||
}
|
||||
},
|
||||
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
||||
scales: {
|
||||
y: {
|
||||
@ -97,99 +93,88 @@ const defaultOptions = {
|
||||
mode: 'x',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
callbacks: {
|
||||
label: (tooltipItem: any) => tooltipItem.yLabel
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export type ChartTimeData = ChartData<keyof ChartTypeRegistry, {
|
||||
x: number;
|
||||
label: number;
|
||||
y: Date;
|
||||
}[], unknown>
|
||||
export type ChartTimeDataPoint = {
|
||||
x: number
|
||||
label: number
|
||||
y: Date
|
||||
}
|
||||
|
||||
export type ChartTimeDataset = ChartDataset<ChartType, ChartTimeDataPoint[]>
|
||||
export type ChartTimeData = ChartData<ChartType, ChartTimeDataPoint[], unknown>
|
||||
|
||||
export type ChartTimeDataParams = {
|
||||
data: ChartTimeData,
|
||||
yStart?: Date,
|
||||
yInterval?: number,
|
||||
displayLabels?: Boolean,
|
||||
data: ChartTimeData
|
||||
yStart?: Date
|
||||
yInterval?: number
|
||||
displayLabels?: boolean
|
||||
}
|
||||
|
||||
export type ChartTimeBaseProps = {
|
||||
dataParams: ChartTimeDataParams,
|
||||
// TODO: Create good type for options
|
||||
options?: ChartOptions<keyof ChartTypeRegistry> | any,
|
||||
dataParams: ChartTimeDataParams
|
||||
options?: ChartOptions
|
||||
}
|
||||
|
||||
export type TimeParams = {
|
||||
unit: String
|
||||
unit: string
|
||||
stepSize: number
|
||||
}
|
||||
|
||||
const linesPerInterval = 32
|
||||
|
||||
export const timeUnitByInterval = (intervalSec: number): String => {
|
||||
if(intervalSec <= 60)
|
||||
const intervals = {
|
||||
millisecond: 0.001,
|
||||
second: 1,
|
||||
minute: 60,
|
||||
hour: 60 * 60,
|
||||
day: 60 * 60 * 24,
|
||||
week: 60 * 60 * 24 * 7,
|
||||
month: 60 * 60 * 24 * 30,
|
||||
quarter: 60 * 60 * 24 * 91,
|
||||
year: 60 * 60 * 24 * 365.25
|
||||
}
|
||||
|
||||
type IntervalType = keyof typeof intervals
|
||||
|
||||
export const timeUnitByInterval = (intervalSec: number): IntervalType => {
|
||||
if(intervalSec <= intervals.minute)
|
||||
return 'millisecond'
|
||||
|
||||
if(intervalSec <= 32*60)
|
||||
if(intervalSec <= 32 * intervals.minute)
|
||||
return 'second'
|
||||
|
||||
if(intervalSec <= 32*60*60)
|
||||
if(intervalSec <= 32 * intervals.hour)
|
||||
return 'minute'
|
||||
|
||||
if(intervalSec <= 32*12*60*60)
|
||||
if(intervalSec <= 32 * intervals.day / 2)
|
||||
return 'hour'
|
||||
|
||||
if(intervalSec <= 32*24*60*60)
|
||||
if(intervalSec <= 32 * intervals.day)
|
||||
return 'day'
|
||||
|
||||
if(intervalSec <= 32*7*24*60*60)
|
||||
if(intervalSec <= 32 * intervals.week)
|
||||
return 'week'
|
||||
|
||||
if(intervalSec <= 32*30.4375*24*60*60)
|
||||
if(intervalSec <= 32 * intervals.year / 12)
|
||||
return 'month'
|
||||
|
||||
if(intervalSec <= 32*121.75*24*60*60)
|
||||
if(intervalSec <= 32 * intervals.year / 3)
|
||||
return 'quarter'
|
||||
else
|
||||
|
||||
return 'year'
|
||||
}
|
||||
|
||||
export const timeParamsByInterval = (intervalSec: number): TimeParams => {
|
||||
let stepSize = intervalSec
|
||||
let unit = timeUnitByInterval(intervalSec)
|
||||
|
||||
switch(unit){
|
||||
case 'millisecond':
|
||||
stepSize *= 1000
|
||||
break;
|
||||
case 'second':
|
||||
//stepSize *= 1
|
||||
break;
|
||||
case 'minute':
|
||||
stepSize /= 60
|
||||
break;
|
||||
case 'hour':
|
||||
stepSize /= 60*60
|
||||
break;
|
||||
case 'day':
|
||||
stepSize /= 24*60*60
|
||||
break;
|
||||
case 'week':
|
||||
stepSize /= 7*24*60*60
|
||||
break;
|
||||
case 'month':
|
||||
stepSize /= 30*24*60*60
|
||||
break;
|
||||
case 'quarter':
|
||||
stepSize /= 91*24*60*60
|
||||
break;
|
||||
case 'year':
|
||||
stepSize /= 365.25*24*60*60
|
||||
break;
|
||||
}
|
||||
|
||||
stepSize = Math.round(stepSize/linesPerInterval)
|
||||
stepSize = stepSize > 0 ? stepSize : 1
|
||||
const unit = timeUnitByInterval(intervalSec)
|
||||
const stepSize = Math.max(1, Math.round(intervalSec / intervals[unit] / linesPerInterval))
|
||||
return { unit, stepSize }
|
||||
}
|
||||
|
||||
@ -198,21 +183,22 @@ export const ChartTimeBase: React.FC<ChartTimeBaseProps> = ({options, dataParams
|
||||
const [chart, setChart] = useState<any>()
|
||||
|
||||
useEffect(() => {
|
||||
let thisOptions = {}
|
||||
Object.assign(thisOptions, defaultOptions, options)
|
||||
const chartOptions: ChartOptions = {}
|
||||
Object.assign(chartOptions, defaultOptions, options)
|
||||
|
||||
let newChart = new Chart(chartRef.current ?? "", {
|
||||
const newChart = new Chart(chartRef.current ?? '', {
|
||||
type: 'line',
|
||||
plugins: [ChartDataLabels],
|
||||
options: thisOptions,
|
||||
options: chartOptions,
|
||||
data: { datasets: [] }
|
||||
})
|
||||
|
||||
setChart(newChart)
|
||||
return () => newChart?.destroy()
|
||||
}, [options])
|
||||
|
||||
useEffect(() => {
|
||||
if (!chart) return;
|
||||
if (!chart) return
|
||||
chart.data = dataParams.data
|
||||
if(dataParams.yStart){
|
||||
const interval = Number(dataParams.yInterval ?? 600_000)
|
||||
@ -227,7 +213,7 @@ export const ChartTimeBase: React.FC<ChartTimeBaseProps> = ({options, dataParams
|
||||
}
|
||||
}
|
||||
|
||||
chart.update()
|
||||
chart.update(0)
|
||||
}, [chart, dataParams])
|
||||
|
||||
return(<canvas ref={chartRef} />)
|
||||
|
@ -1,7 +1,44 @@
|
||||
import { ChartOptions, Scriptable, ScriptableContext } from 'chart.js'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { ChartTimeBase } from './ChartTimeBase'
|
||||
import { makeDateSorter } from '../Table'
|
||||
import {
|
||||
ChartTimeBase,
|
||||
ChartTimeData,
|
||||
ChartTimeDataset,
|
||||
ChartTimeDataPoint,
|
||||
ChartTimeDataParams
|
||||
} from './ChartTimeBase'
|
||||
|
||||
const chartPluginsOptions = {
|
||||
export type ColumnLineConfig = {
|
||||
label?: string
|
||||
units?: string
|
||||
xAccessorName: string
|
||||
yAccessorName: string
|
||||
color?: string
|
||||
showLine?: boolean
|
||||
isShape?: boolean
|
||||
xConstValue?: number | string
|
||||
dash?: Array<number>
|
||||
borderColor?: string
|
||||
backgroundColor?: string
|
||||
borderWidth?: Scriptable<number, ScriptableContext<'radar'>>
|
||||
fill?: string
|
||||
}
|
||||
export type ColumnPostParsing = (data: ChartTimeDataParams) => void
|
||||
export type ColumnData = { [accessors: string]: any }
|
||||
export type ColumnAdditionalData = (point: ColumnData, cfg: ColumnLineConfig) => object
|
||||
export type ColumnProps = {
|
||||
postParsing?: ColumnPostParsing
|
||||
additionalPointData?: ColumnAdditionalData
|
||||
interval?: number
|
||||
yDisplay?: boolean
|
||||
yStart?: Date
|
||||
lineGroup: ColumnLineConfig[]
|
||||
data: ColumnData[]
|
||||
}
|
||||
|
||||
|
||||
const chartPluginsOptions: ChartOptions = {
|
||||
plugins: {
|
||||
datalabels: {
|
||||
backgroundColor: 'transparent',
|
||||
@ -15,16 +52,16 @@ const chartPluginsOptions = {
|
||||
clip: true
|
||||
},
|
||||
legend: { display: false },
|
||||
tooltip: { enable: true }
|
||||
tooltip: { enabled: true }
|
||||
}
|
||||
}
|
||||
|
||||
const GetRandomColor = () => '#' + Math.floor(Math.random() * (16**6 - 1)).toString(16)
|
||||
|
||||
export const GetOrCreateDatasetByLineConfig = (data, lineConfig) => {
|
||||
export const GetOrCreateDatasetByLineConfig = (data: ChartTimeData, lineConfig: ColumnLineConfig): ChartTimeDataset => {
|
||||
let dataset = data?.datasets.find(d => d.label === lineConfig.label)
|
||||
if (!dataset) {
|
||||
let color = lineConfig.borderColor
|
||||
const color = lineConfig.borderColor
|
||||
?? lineConfig.backgroundColor
|
||||
?? lineConfig.color
|
||||
?? GetRandomColor()
|
||||
@ -45,8 +82,8 @@ export const GetOrCreateDatasetByLineConfig = (data, lineConfig) => {
|
||||
return dataset
|
||||
}
|
||||
|
||||
export const Column = React.memo(({ lineGroup, data, postParsing, additionalPointData, interval, yDisplay, yStart }) => {
|
||||
const [dataParams, setDataParams] = useState({data: {datasets:[]}, yStart, })
|
||||
export const Column: React.NamedExoticComponent<ColumnProps> = React.memo(({ lineGroup, data, postParsing, additionalPointData, interval, yDisplay, yStart }) => {
|
||||
const [dataParams, setDataParams] = useState<ChartTimeDataParams>({data: {datasets:[]}, yStart, })
|
||||
|
||||
useEffect(()=>{
|
||||
if((lineGroup.length === 0) || (data.length === 0)) return
|
||||
@ -54,16 +91,17 @@ export const Column = React.memo(({ lineGroup, data, postParsing, additionalPoin
|
||||
setDataParams((preDataParams) => {
|
||||
lineGroup.forEach(lineCfg => {
|
||||
const dataset = GetOrCreateDatasetByLineConfig(preDataParams.data, lineCfg)
|
||||
let points = data.map(dataItem => ({
|
||||
let points: ChartTimeDataPoint[] = data.map(dataItem => ({
|
||||
x: lineCfg.xConstValue ?? dataItem[lineCfg.xAccessorName],
|
||||
label: dataItem[lineCfg.xAccessorName],
|
||||
y: new Date(dataItem[lineCfg.yAccessorName]),
|
||||
depth: dataItem.wellDepth,
|
||||
...additionalPointData?.(dataItem, lineCfg)
|
||||
})).filter(point => (point.x ?? null) !== null && (point.y ?? null) !== null)
|
||||
}))
|
||||
|
||||
points = points.filter(point => (point.x ?? null) !== null && (point.y ?? null) !== null)
|
||||
|
||||
if(points?.length > 2)
|
||||
points.sort((a,b) => a.y > b.y ? 1 : -1)
|
||||
points.sort(makeDateSorter('y'))
|
||||
|
||||
dataset.data = points
|
||||
})
|
@ -4,8 +4,6 @@ import { ChartTimeOnlineFooter } from './ChartTimeOnlineFooter'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { makeDateSorter } from '../../components/Table'
|
||||
|
||||
const stroke = (sz = '2px', c = 'white') => ({ textShadow: `-${sz} -${sz} 0 ${c}, ${sz} -${sz} 0 ${c}, -${sz} ${sz} 0 ${c}, ${sz} ${sz} 0 ${c}` })
|
||||
|
||||
const GetLimitShape = (flowChartData, points, accessor) => {
|
||||
const min = [], max = []
|
||||
|
||||
@ -29,12 +27,12 @@ const RemoveSimilar = (input, accessor) => {
|
||||
return data
|
||||
}
|
||||
|
||||
export const MonitoringColumn = ({ lineGroup, data, flowChartData, interval, showBorder, style, headerHeight, pointCount }) => {
|
||||
export const MonitoringColumn = ({ lineGroup, data, flowChartData, interval, showBorder, style, headerHeight, pointCount = 2048, additionalLabels }) => {
|
||||
const [dataStore, setDataStore] = useState([])
|
||||
const [lineGroupWithoutShapes, setLineGroupWithoutShapes] = useState([])
|
||||
const dataLast = data?.[data.length - 1]
|
||||
const yStart = new Date(+(dataLast?.date ? new Date(dataLast.date) : new Date()) - interval * 0.97)
|
||||
const pv = lineGroup.filter(line => line.showLabels).map(line => ({
|
||||
const yStart = new Date((dataLast?.date ? +new Date(dataLast.date) : Date.now()) - interval * 0.97)
|
||||
let pv = lineGroup.filter(line => line.showLabels).map(line => ({
|
||||
color: line.color,
|
||||
label: line.label,
|
||||
unit: line.units,
|
||||
@ -80,8 +78,30 @@ export const MonitoringColumn = ({ lineGroup, data, flowChartData, interval, sho
|
||||
</Grid>
|
||||
<div style={{ position: 'relative' }}>
|
||||
<Grid className={'display_chart_values'}>
|
||||
{pv?.map((v, idx) => (
|
||||
<GridItem key={idx} col={1} row={idx} style={{ ...stroke(), color: v.color, padding: '0 4px' }}>{v.value?.toFixed(2) ?? '--'} {v.unit}</GridItem>
|
||||
{pv?.map((v, idx) => {
|
||||
const text = `${v.value?.toFixed(2) ?? '--'} ${v.unit}`
|
||||
return (
|
||||
<GridItem
|
||||
key={idx}
|
||||
row={idx + 1}
|
||||
col={1}
|
||||
className={'monitoring_value'}
|
||||
style={{ color: v.color, padding: '0 4px' }}
|
||||
data-before={text}
|
||||
children={text}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{additionalLabels?.map((label, idx) => (
|
||||
<GridItem
|
||||
key={idx}
|
||||
row={(pv?.length ?? 0) + idx + 1}
|
||||
col={1}
|
||||
className={'monitoring_value'}
|
||||
style={{ color: 'black', padding: '0 4px' }}
|
||||
data-before={label}
|
||||
children={label}
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
<Column
|
||||
@ -98,7 +118,3 @@ export const MonitoringColumn = ({ lineGroup, data, flowChartData, interval, sho
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
MonitoringColumn.defaultProps = {
|
||||
pointCount: 2048
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import { Grid, GridItem, Flex } from '../../components/Grid'
|
||||
import { Subscribe } from '../../services/signalr'
|
||||
import {
|
||||
DrillFlowChartService,
|
||||
OperationStatService,
|
||||
TelemetryDataSaubService,
|
||||
TelemetryDataSpinService,
|
||||
WellService
|
||||
@ -306,6 +307,7 @@ export default function TelemetryView({ idWell }) {
|
||||
const [wellData, setWellData] = useState({ idState: 0 })
|
||||
const [showLoader, setShowLoader] = useState(false)
|
||||
const [flowChartData, setFlowChartData] = useState([])
|
||||
const [rop, setRop] = useState(null)
|
||||
|
||||
const handleDataSaub = (data) => {
|
||||
if (data) {
|
||||
@ -345,6 +347,8 @@ export default function TelemetryView({ idWell }) {
|
||||
useEffect(() => invokeWebApiWrapperAsync(
|
||||
async () => {
|
||||
const well = await WellService.get(idWell)
|
||||
const rop = await OperationStatService.getClusterRopStatByIdWell(idWell)
|
||||
setRop(rop)
|
||||
setWellData(well ?? {})
|
||||
},
|
||||
setShowLoader,
|
||||
@ -403,6 +407,10 @@ export default function TelemetryView({ idWell }) {
|
||||
interval={chartInterval * 1000}
|
||||
headerHeight={'50px'}
|
||||
showBorder={getIndexOfDrillingBy(dataSaub) === index}
|
||||
additionalLabels={rop && (index === 1) ? [
|
||||
`ROP сред: ${rop.ropAverage.toFixed(2)} м/ч`,
|
||||
`ROP макс: ${rop.ropMax.toFixed(2)} м/ч`
|
||||
] : null}
|
||||
/>
|
||||
</GridItem>
|
||||
)}
|
||||
|
@ -24,6 +24,21 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.monitoring_value {
|
||||
position: relative;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.monitoring_value:before {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
left: 4px;
|
||||
top: 0;
|
||||
-webkit-text-stroke: 4px white;
|
||||
content: attr(data-before);
|
||||
}
|
||||
|
||||
|
||||
.display_label{
|
||||
font-size: 16px;
|
||||
color: rgb(70, 70, 70);
|
||||
|
Loading…
Reference in New Issue
Block a user