forked from ddrilling/asb_cloud_front
Графики для аналитики
This commit is contained in:
parent
46234d6be1
commit
f62b280ee5
41
src/components/AnalysisDepthToDay.jsx
Normal file
41
src/components/AnalysisDepthToDay.jsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { ChartDepthToDay } from './charts/ChartDepthToDay'
|
||||||
|
import { useParams } from "react-router-dom"
|
||||||
|
import notify from "../components/notify"
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { AnalyticsService } from "../services/api"
|
||||||
|
|
||||||
|
const lines = [
|
||||||
|
{ label: "Глубина забоя", yAccessorName: "wellDepth", color: '#f00' },
|
||||||
|
{ label: "Положение инструмента", yAccessorName: "bitDepth", color: '#ff0' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export function AnalysisDepthToDay() {
|
||||||
|
let { id } = useParams()
|
||||||
|
const [depthToDayData, setDepthToDayData] = useState([])
|
||||||
|
const [loader, setLoader] = useState(false)
|
||||||
|
|
||||||
|
const handleReceiveDepthToDayData = (data) => {
|
||||||
|
setDepthToDayData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoader(true)
|
||||||
|
AnalyticsService.getWellDepthToDay(id)
|
||||||
|
.then(handleReceiveDepthToDayData)
|
||||||
|
.catch(error => {
|
||||||
|
notify(`Не удалось получить данные для Анализа Глубина-День по скважине "${id}"`,
|
||||||
|
'warning')
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
.finally(setLoader(false))
|
||||||
|
}, [id])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ChartDepthToDay
|
||||||
|
data={depthToDayData}
|
||||||
|
lines={lines}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
38
src/components/AnalysisDepthToInterval.jsx
Normal file
38
src/components/AnalysisDepthToInterval.jsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { useParams } from "react-router-dom"
|
||||||
|
import notify from "../components/notify"
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
import { AnalyticsService } from "../services/api"
|
||||||
|
import { ChartDepthToInterval } from './charts/ChartDepthToInterval'
|
||||||
|
|
||||||
|
const line = {label: 'Данные по глубине скважины за период', y: 'intervalDepthProgress', x: 'intervalStartDate'}
|
||||||
|
|
||||||
|
export function AnalysisDepthToInterval() {
|
||||||
|
let { id } = useParams()
|
||||||
|
const [depthToIntervalData, setDepthToIntervalData] = useState([])
|
||||||
|
const [loader, setLoader] = useState(false)
|
||||||
|
|
||||||
|
const handleReceiveDepthToIntervalData = (data) => {
|
||||||
|
setDepthToIntervalData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoader(true)
|
||||||
|
AnalyticsService.getWellDepthToInterval(id)
|
||||||
|
.then(handleReceiveDepthToIntervalData)
|
||||||
|
.catch(error => {
|
||||||
|
notify(`Не удалось получить данные для Анализа Глубина-День по скважине "${id}"`,
|
||||||
|
'warning')
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
.finally(setLoader(false))
|
||||||
|
}, [id])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ChartDepthToInterval
|
||||||
|
data={depthToIntervalData}
|
||||||
|
line={line}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
@ -1,54 +1,38 @@
|
|||||||
import { useEffect, useState} from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import {GetRandomColor} from "./ChartTimeArchive"
|
import { ChartDepthToDayBase } from './ChartDepthToDayBase'
|
||||||
import {ChartDepthToDayBase} from "./ChartDepthToDayBase";
|
import { CreateDataset } from './ChartTimeArchive'
|
||||||
import {ChartTimeBase} from "./ChartTimeBase";
|
|
||||||
|
|
||||||
const CreateDataset = (lineConfig) => {
|
export const ChartDepthToDay = ({data, lines}) => {
|
||||||
let color = lineConfig.borderColor
|
const [depthToDayDataParams, setDepthToDayDataParams] = useState({data: {datasets: []}})
|
||||||
?? lineConfig.backgroundColor
|
|
||||||
?? lineConfig.color
|
|
||||||
?? GetRandomColor()
|
|
||||||
|
|
||||||
let dataset = {
|
|
||||||
label: lineConfig.label,
|
|
||||||
data: [],
|
|
||||||
backgroundColor: lineConfig.backgroundColor ?? color,
|
|
||||||
borderColor: lineConfig.borderColor ?? color,
|
|
||||||
borderWidth: lineConfig.borderWidth ?? 1,
|
|
||||||
borderDash: lineConfig.dash ?? [],
|
|
||||||
}
|
|
||||||
return dataset
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ChartAnalyticDepthToDay = ({lines, data, yDisplay, rangeDate, chartRatio}) => {
|
|
||||||
const [analyticDataParams, setAnalyticDataParams] = useState({data:{datasets:[]}})
|
|
||||||
let startOfDay = new Date().setHours(0,0,0,0)
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ((!lines)
|
if ((!lines)
|
||||||
|| (!data))
|
|| (!data))
|
||||||
return
|
return
|
||||||
|
|
||||||
let newDatasets = lines.map(lineCfg => {
|
let newDatasets = lines.map(lineCfg => {
|
||||||
let dataset = CreateDataset(lineCfg)
|
let datasets = CreateDataset(lineCfg)
|
||||||
dataset.data = data.map(dataItem => {
|
if(data.length !== 0)
|
||||||
return {
|
datasets.data = data.map(dataItem => {
|
||||||
x: new Date(dataItem[lineCfg.xAccessorName??'date']),
|
return {
|
||||||
y: dataItem[lineCfg.yAccessorName],
|
x: new Date(dataItem[lineCfg.xAccessorName??'date']),
|
||||||
}
|
y: dataItem[lineCfg.yAccessorName],
|
||||||
})
|
label: dataItem[lineCfg.label]
|
||||||
return dataset
|
}
|
||||||
|
})
|
||||||
|
return datasets
|
||||||
})
|
})
|
||||||
|
|
||||||
let newParams = {
|
let newParams = {
|
||||||
xStart: startOfDay,
|
displayLabels: true,
|
||||||
displayLabels: yDisplay??false,
|
|
||||||
data: {
|
data: {
|
||||||
datasets: newDatasets
|
datasets: newDatasets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setAnalyticDataParams(newParams)
|
setDepthToDayDataParams(newParams)
|
||||||
}, [data, lines, yDisplay, rangeDate, chartRatio])
|
}, [data, lines])
|
||||||
|
|
||||||
return (<ChartTimeBase dataParams={analyticDataParams}/>)
|
return (
|
||||||
|
<ChartDepthToDayBase dataParams={depthToDayDataParams} />
|
||||||
|
)
|
||||||
}
|
}
|
@ -0,0 +1,236 @@
|
|||||||
|
import {useEffect, useRef, useState} from 'react';
|
||||||
|
import {
|
||||||
|
Chart,
|
||||||
|
TimeScale,
|
||||||
|
LinearScale,
|
||||||
|
Legend,
|
||||||
|
LineController,
|
||||||
|
PointElement,
|
||||||
|
LineElement,
|
||||||
|
ChartData,
|
||||||
|
ChartTypeRegistry,
|
||||||
|
ChartOptions
|
||||||
|
} from 'chart.js'
|
||||||
|
import 'chartjs-adapter-moment';
|
||||||
|
import ChartDataLabels from 'chartjs-plugin-datalabels';
|
||||||
|
import zoomPlugin from 'chartjs-plugin-zoom';
|
||||||
|
|
||||||
|
Chart.register(TimeScale, LinearScale, LineController, LineElement, PointElement, Legend, ChartDataLabels, zoomPlugin);
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
responsive: true,
|
||||||
|
aspectRatio: 1.45,
|
||||||
|
animation: false,
|
||||||
|
tooltips: {
|
||||||
|
enabled: true,
|
||||||
|
callbacks: {
|
||||||
|
label(tooltipItem:any) {
|
||||||
|
return tooltipItem.yLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
||||||
|
scales: {
|
||||||
|
x:{
|
||||||
|
type: 'time',
|
||||||
|
reverse: true,
|
||||||
|
time: {
|
||||||
|
stepSize: 20,
|
||||||
|
displayFormats: {
|
||||||
|
millisecond: 'HH:mm:ss.SSS',
|
||||||
|
second: 'HH:mm:ss',
|
||||||
|
minute: 'HH:mm:ss',
|
||||||
|
hour: 'DD HH:mm:ss',
|
||||||
|
day: 'MM.DD HH:mm',
|
||||||
|
week: 'yy.MM.DD HH:mm',
|
||||||
|
month: 'yyyy.MM.DD',
|
||||||
|
quarter: 'yyyy.MM.DD',
|
||||||
|
year: 'yyyy.MM',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid:{
|
||||||
|
drawTicks: false,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
z: 1,
|
||||||
|
display : false,
|
||||||
|
textStrokeColor : "#ffff",
|
||||||
|
textStrokeWidth : 2,
|
||||||
|
color:"#000",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
y:{
|
||||||
|
type:'linear',
|
||||||
|
position:'top'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
elements:{
|
||||||
|
point:{
|
||||||
|
radius:0,
|
||||||
|
hoverRadius:5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins:{
|
||||||
|
legend:{
|
||||||
|
display: true,
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
// zoom: {
|
||||||
|
// zoom: {
|
||||||
|
// wheel: {
|
||||||
|
// enabled: true,
|
||||||
|
// modifierKey: 'alt',
|
||||||
|
// },
|
||||||
|
// pinch: {
|
||||||
|
// enabled: true
|
||||||
|
// },
|
||||||
|
// mode: 'x',
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChartTimeData = ChartData<keyof ChartTypeRegistry, {
|
||||||
|
x: Date;
|
||||||
|
label: number;
|
||||||
|
y: number;
|
||||||
|
}[], unknown>
|
||||||
|
|
||||||
|
export type ChartTimeDataParams = {
|
||||||
|
data: ChartTimeData,
|
||||||
|
xStart?: Date,
|
||||||
|
xInterval?: number,
|
||||||
|
displayLabels?: Boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChartTimeBaseProps = {
|
||||||
|
dataParams: ChartTimeDataParams,
|
||||||
|
// TODO: Create good type for options
|
||||||
|
options?: ChartOptions<keyof ChartTypeRegistry> | any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TimeParams = {
|
||||||
|
unit: String
|
||||||
|
stepSize: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const linesPerInterval = 32
|
||||||
|
|
||||||
|
export const timeUnitByInterval = (intervalSec:number):String => {
|
||||||
|
if(intervalSec <= 60)
|
||||||
|
return 'millisecond'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*60)
|
||||||
|
return 'second'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*60*60)
|
||||||
|
return 'minute'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*12*60*60)
|
||||||
|
return 'hour'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*24*60*60)
|
||||||
|
return 'day'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*7*24*60*60)
|
||||||
|
return 'week'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*30.4375*24*60*60)
|
||||||
|
return 'month'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*121.75*24*60*60)
|
||||||
|
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;
|
||||||
|
return {unit, stepSize}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChartDepthToDayBase: React.FC<ChartTimeBaseProps> = ({options, dataParams}) => {
|
||||||
|
const chartRef = useRef<HTMLCanvasElement>(null)
|
||||||
|
const [chart, setChart] = useState<any>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if((chartRef.current)&&(!chart)) {
|
||||||
|
let thisOptions = {}
|
||||||
|
Object.assign(thisOptions, defaultOptions, options)
|
||||||
|
|
||||||
|
let newChart = new Chart(chartRef.current, {
|
||||||
|
type: 'line',
|
||||||
|
plugins: [ChartDataLabels],
|
||||||
|
options: thisOptions,
|
||||||
|
data: dataParams.data
|
||||||
|
})
|
||||||
|
setChart(newChart)
|
||||||
|
|
||||||
|
return () => chart?.destroy()
|
||||||
|
}
|
||||||
|
}, [chart, options, dataParams])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chart)
|
||||||
|
return
|
||||||
|
|
||||||
|
chart.data = dataParams.data
|
||||||
|
chart.options.aspectRatio = options?.aspectRatio
|
||||||
|
if (dataParams.xStart) {
|
||||||
|
let interval = Number(dataParams.xInterval ?? 600)
|
||||||
|
let start = new Date(dataParams.xStart)
|
||||||
|
let end = new Date(dataParams.xStart)
|
||||||
|
end.setSeconds(end.getSeconds() + interval)
|
||||||
|
let {unit, stepSize} = timeParamsByInterval(interval)
|
||||||
|
|
||||||
|
if(chart.options.scales?.x){
|
||||||
|
chart.options.scales.x.max = end.getTime()
|
||||||
|
chart.options.scales.x.min = start.getTime()
|
||||||
|
chart.options.scales.x.ticks.display = dataParams.displayLabels ?? true
|
||||||
|
chart.options.scales.x.time.unit = unit
|
||||||
|
chart.options.scales.x.time.stepSize = stepSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.update()
|
||||||
|
}, [chart, dataParams, options])
|
||||||
|
|
||||||
|
return(<canvas ref={chartRef} />)
|
||||||
|
}
|
37
src/components/charts/ChartDepthToInterval.jsx
Normal file
37
src/components/charts/ChartDepthToInterval.jsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { ChartDepthToIntervalBase } from './ChartDepthToIntervalBase'
|
||||||
|
import { CreateDataset } from './ChartTimeArchive'
|
||||||
|
|
||||||
|
export function ChartDepthToInterval({data, lines}) {
|
||||||
|
const [depthToIntervalDataParams, setDepthToIntervalDataParams] = useState({data: {datasets: []}})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if ((!lines)
|
||||||
|
|| (!data))
|
||||||
|
return
|
||||||
|
|
||||||
|
let newDatasets = lines.map(lineCfg => {
|
||||||
|
let datasets = CreateDataset(lineCfg)
|
||||||
|
if(data.length !== 0)
|
||||||
|
datasets.data = data.map(dataItem => {
|
||||||
|
return {
|
||||||
|
x: new Date(dataItem[lineCfg.x??'date']),
|
||||||
|
y: dataItem[lineCfg.y],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return datasets
|
||||||
|
})
|
||||||
|
|
||||||
|
let newParams = {
|
||||||
|
displayLabels: true,
|
||||||
|
data: {
|
||||||
|
datasets: newDatasets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setDepthToIntervalDataParams(newParams)
|
||||||
|
}, [data, lines])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChartDepthToIntervalBase dataParams={depthToIntervalDataParams} />
|
||||||
|
)
|
||||||
|
}
|
221
src/components/charts/ChartDepthToIntervalBase.tsx
Normal file
221
src/components/charts/ChartDepthToIntervalBase.tsx
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
import {useEffect, useRef, useState} from 'react'
|
||||||
|
import {
|
||||||
|
Chart,
|
||||||
|
TimeScale,
|
||||||
|
Legend,
|
||||||
|
PointElement,
|
||||||
|
ChartData,
|
||||||
|
ChartTypeRegistry,
|
||||||
|
ChartOptions,
|
||||||
|
BarController,
|
||||||
|
BarElement
|
||||||
|
} from 'chart.js'
|
||||||
|
import 'chartjs-adapter-moment'
|
||||||
|
import ChartDataLabels from 'chartjs-plugin-datalabels'
|
||||||
|
|
||||||
|
Chart.register(TimeScale, BarController, BarElement, PointElement, Legend, ChartDataLabels)
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
responsive: true,
|
||||||
|
aspectRatio: 1.45,
|
||||||
|
animation: false,
|
||||||
|
tooltips: {
|
||||||
|
enabled: true,
|
||||||
|
callbacks: {
|
||||||
|
label(tooltipItem:any) {
|
||||||
|
return tooltipItem.yLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
||||||
|
scales: {
|
||||||
|
x:{
|
||||||
|
type: 'time',
|
||||||
|
reverse: true,
|
||||||
|
time: {
|
||||||
|
stepSize: 20,
|
||||||
|
displayFormats: {
|
||||||
|
millisecond: 'HH:mm:ss.SSS',
|
||||||
|
second: 'HH:mm:ss',
|
||||||
|
minute: 'HH:mm:ss',
|
||||||
|
hour: 'DD HH:mm:ss',
|
||||||
|
day: 'MM.DD HH:mm',
|
||||||
|
week: 'yy.MM.DD HH:mm',
|
||||||
|
month: 'yyyy.MM.DD',
|
||||||
|
quarter: 'yyyy.MM.DD',
|
||||||
|
year: 'yyyy.MM',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid:{
|
||||||
|
drawTicks: false,
|
||||||
|
},
|
||||||
|
ticks: {
|
||||||
|
z: 1,
|
||||||
|
display : false,
|
||||||
|
textStrokeColor : "#ffff",
|
||||||
|
textStrokeWidth : 2,
|
||||||
|
color:"#000",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
y:{
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
elements:{
|
||||||
|
point:{
|
||||||
|
radius:0,
|
||||||
|
hoverRadius:5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins:{
|
||||||
|
legend:{
|
||||||
|
display: true,
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
display: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChartTimeData = ChartData<keyof ChartTypeRegistry, {
|
||||||
|
x: Date;
|
||||||
|
label: number;
|
||||||
|
y: number;
|
||||||
|
}[], unknown>
|
||||||
|
|
||||||
|
export type ChartTimeDataParams = {
|
||||||
|
data: ChartTimeData,
|
||||||
|
xStart?: Date,
|
||||||
|
xInterval?: number,
|
||||||
|
displayLabels?: Boolean,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ChartTimeBaseProps = {
|
||||||
|
dataParams: ChartTimeDataParams,
|
||||||
|
// TODO: Create good type for options
|
||||||
|
options?: ChartOptions<keyof ChartTypeRegistry> | any,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TimeParams = {
|
||||||
|
unit: String
|
||||||
|
stepSize: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const linesPerInterval = 32
|
||||||
|
|
||||||
|
export const timeUnitByInterval = (intervalSec:number):String => {
|
||||||
|
if(intervalSec <= 60)
|
||||||
|
return 'millisecond'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*60)
|
||||||
|
return 'second'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*60*60)
|
||||||
|
return 'minute'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*12*60*60)
|
||||||
|
return 'hour'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*24*60*60)
|
||||||
|
return 'day'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*7*24*60*60)
|
||||||
|
return 'week'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*30.4375*24*60*60)
|
||||||
|
return 'month'
|
||||||
|
|
||||||
|
if(intervalSec <= 32*121.75*24*60*60)
|
||||||
|
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;
|
||||||
|
return {unit, stepSize}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChartDepthToIntervalBase: React.FC<ChartTimeBaseProps> = ({options, dataParams}) => {
|
||||||
|
const chartRef = useRef<HTMLCanvasElement>(null)
|
||||||
|
const [chart, setChart] = useState<any>()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if((chartRef.current)&&(!chart)) {
|
||||||
|
let thisOptions = {}
|
||||||
|
Object.assign(thisOptions, defaultOptions, options)
|
||||||
|
|
||||||
|
let newChart = new Chart(chartRef.current, {
|
||||||
|
type: 'bar',
|
||||||
|
plugins: [ChartDataLabels],
|
||||||
|
options: thisOptions,
|
||||||
|
data: dataParams.data
|
||||||
|
})
|
||||||
|
setChart(newChart)
|
||||||
|
|
||||||
|
return () => chart?.destroy()
|
||||||
|
}
|
||||||
|
}, [chart, options, dataParams])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!chart)
|
||||||
|
return
|
||||||
|
|
||||||
|
chart.data = dataParams.data
|
||||||
|
chart.options.aspectRatio = options?.aspectRatio
|
||||||
|
if (dataParams.xStart) {
|
||||||
|
let interval = Number(dataParams.xInterval ?? 600)
|
||||||
|
let start = new Date(dataParams.xStart)
|
||||||
|
let end = new Date(dataParams.xStart)
|
||||||
|
end.setSeconds(end.getSeconds() + interval)
|
||||||
|
let {unit, stepSize} = timeParamsByInterval(interval)
|
||||||
|
|
||||||
|
if(chart.options.scales?.x){
|
||||||
|
chart.options.scales.x.max = end.getTime()
|
||||||
|
chart.options.scales.x.min = start.getTime()
|
||||||
|
chart.options.scales.x.ticks.display = dataParams.displayLabels ?? true
|
||||||
|
chart.options.scales.x.time.unit = unit
|
||||||
|
chart.options.scales.x.time.stepSize = stepSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chart.update()
|
||||||
|
}, [chart, dataParams, options])
|
||||||
|
|
||||||
|
return(<canvas ref={chartRef} />)
|
||||||
|
}
|
@ -2,15 +2,15 @@ import moment from 'moment';
|
|||||||
import { useEffect, useState} from 'react';
|
import { useEffect, useState} from 'react';
|
||||||
import {ChartTimeBase} from './ChartTimeBase'
|
import {ChartTimeBase} from './ChartTimeBase'
|
||||||
|
|
||||||
const GetRandomColor = () => "#" + Math.floor(Math.random()*16777215).toString(16)
|
export const GetRandomColor = () => "#" + Math.floor(Math.random()*16777215).toString(16)
|
||||||
|
|
||||||
const CreateDataset = (lineConfig) => {
|
export const CreateDataset = (lineConfig) => {
|
||||||
let color = lineConfig.borderColor
|
let color = lineConfig.borderColor
|
||||||
?? lineConfig.backgroundColor
|
?? lineConfig.backgroundColor
|
||||||
?? lineConfig.color
|
?? lineConfig.color
|
||||||
?? GetRandomColor()
|
?? GetRandomColor()
|
||||||
|
|
||||||
let dataset = {
|
let datasets = {
|
||||||
label: lineConfig.label,
|
label: lineConfig.label,
|
||||||
data: [],
|
data: [],
|
||||||
backgroundColor: lineConfig.backgroundColor ?? color,
|
backgroundColor: lineConfig.backgroundColor ?? color,
|
||||||
@ -18,7 +18,7 @@ const CreateDataset = (lineConfig) => {
|
|||||||
borderWidth: lineConfig.borderWidth ?? 1,
|
borderWidth: lineConfig.borderWidth ?? 1,
|
||||||
borderDash: lineConfig.dash ?? [],
|
borderDash: lineConfig.dash ?? [],
|
||||||
}
|
}
|
||||||
return dataset
|
return datasets
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChartOptions = {
|
const ChartOptions = {
|
||||||
@ -28,14 +28,14 @@ const ChartOptions = {
|
|||||||
// display: false,
|
// display: false,
|
||||||
// maxHeight: 64,
|
// maxHeight: 64,
|
||||||
// fullSize: true,
|
// fullSize: true,
|
||||||
// posision:'chartArea',
|
// position: 'chartArea',
|
||||||
// align: 'start',
|
// align: 'start',
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ChartTimeArchive = ({lines, data, yDisplay, rangeDate, chartRatio}) => {
|
export const ChartTimeArchive = ({lines, data, yDisplay, rangeDate, chartRatio}) => {
|
||||||
const [dataParams, setDataParams] = useState({data:{datasets:[]}})
|
const [dataParams, setDataParams] = useState({data:{datasets: []}})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ((!lines)
|
if ((!lines)
|
||||||
@ -70,4 +70,4 @@ export const ChartTimeArchive = ({lines, data, yDisplay, rangeDate, chartRatio})
|
|||||||
opt.aspectRatio = chartRatio
|
opt.aspectRatio = chartRatio
|
||||||
|
|
||||||
return (<ChartTimeBase dataParams={dataParams} options={opt}/>)
|
return (<ChartTimeBase dataParams={dataParams} options={opt}/>)
|
||||||
}
|
}
|
@ -19,7 +19,15 @@ Chart.register( TimeScale, LinearScale, LineController, LineElement, PointElemen
|
|||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
aspectRatio: 0.45,
|
aspectRatio: 0.45,
|
||||||
animation: false,
|
animation: false,
|
||||||
|
tooltips: {
|
||||||
|
enabled: true,
|
||||||
|
callbacks: {
|
||||||
|
label(tooltipItem:any) {
|
||||||
|
return tooltipItem.yLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
||||||
scales: {
|
scales: {
|
||||||
y:{
|
y:{
|
||||||
@ -80,7 +88,7 @@ const defaultOptions = {
|
|||||||
},
|
},
|
||||||
mode: 'x',
|
mode: 'x',
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +118,7 @@ export type TimeParams = {
|
|||||||
|
|
||||||
const linesPerInterval = 32
|
const linesPerInterval = 32
|
||||||
|
|
||||||
const timeUnitByInterval = (intervalSec:number):String => {
|
export const timeUnitByInterval = (intervalSec:number):String => {
|
||||||
if(intervalSec <= 60)
|
if(intervalSec <= 60)
|
||||||
return 'millisecond'
|
return 'millisecond'
|
||||||
|
|
||||||
@ -138,7 +146,7 @@ const timeUnitByInterval = (intervalSec:number):String => {
|
|||||||
return 'year'
|
return 'year'
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeParamsByInterval = (intervalSec:number) :TimeParams => {
|
export const timeParamsByInterval = (intervalSec:number) :TimeParams => {
|
||||||
let stepSize = intervalSec
|
let stepSize = intervalSec
|
||||||
let unit = timeUnitByInterval(intervalSec)
|
let unit = timeUnitByInterval(intervalSec)
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ import { useEffect, useState} from 'react';
|
|||||||
import {ChartTimeBase, ChartTimeData, ChartTimeDataParams} from './ChartTimeBase'
|
import {ChartTimeBase, ChartTimeData, ChartTimeDataParams} from './ChartTimeBase'
|
||||||
|
|
||||||
const GetRandomColor = () => "#" + Math.floor(Math.random()*16777215).toString(16)
|
const GetRandomColor = () => "#" + Math.floor(Math.random()*16777215).toString(16)
|
||||||
|
|
||||||
function GetOrCreateDatasetByLineConfig (data: ChartTimeData, lineConfig: LineConfig) {
|
function GetOrCreateDatasetByLineConfig (data: ChartTimeData, lineConfig: LineConfig) {
|
||||||
let dataset = data?.datasets.find(d=>d.label === lineConfig.label)
|
let dataset = data?.datasets.find(d=>d.label === lineConfig.label)
|
||||||
if(!dataset)
|
if(!dataset)
|
||||||
@ -111,6 +110,9 @@ export const ChartTimeOnline: React.FC<ChartTimeProps> = (props) => {
|
|||||||
anchor: 'center',
|
anchor: 'center',
|
||||||
clip: true
|
clip: true
|
||||||
},
|
},
|
||||||
|
tooltip: {
|
||||||
|
enable: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
// import {UserOfWells} from "../components/UserOfWells";
|
import { AnalysisDepthToDay } from '../components/AnalysisDepthToDay'
|
||||||
|
import { AnalysisDepthToInterval } from '../components/AnalysisDepthToInterval'
|
||||||
|
|
||||||
export default function Analysis(props) {
|
export default function Analysis() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="menu_title">
|
<>
|
||||||
<h2>Анализ</h2>
|
<AnalysisDepthToDay />
|
||||||
{/*<UserOfWells data={saubData}/>*/}
|
<AnalysisDepthToInterval />
|
||||||
<hr/>
|
</>
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -10,12 +10,16 @@ export type { DatesRangeDto } from './models/DatesRangeDto';
|
|||||||
export type { EventDto } from './models/EventDto';
|
export type { EventDto } from './models/EventDto';
|
||||||
export type { MessageDto } from './models/MessageDto';
|
export type { MessageDto } from './models/MessageDto';
|
||||||
export type { MessageDtoPaginationContainer } from './models/MessageDtoPaginationContainer';
|
export type { MessageDtoPaginationContainer } from './models/MessageDtoPaginationContainer';
|
||||||
|
export type { OperationDurationDto } from './models/OperationDurationDto';
|
||||||
export type { TelemetryInfoDto } from './models/TelemetryInfoDto';
|
export type { TelemetryInfoDto } from './models/TelemetryInfoDto';
|
||||||
export type { TelemetryMessageDto } from './models/TelemetryMessageDto';
|
export type { TelemetryMessageDto } from './models/TelemetryMessageDto';
|
||||||
export type { TelemetryUserDto } from './models/TelemetryUserDto';
|
export type { TelemetryUserDto } from './models/TelemetryUserDto';
|
||||||
export type { UserTokenDto } from './models/UserTokenDto';
|
export type { UserTokenDto } from './models/UserTokenDto';
|
||||||
|
export type { WellDepthToDayDto } from './models/WellDepthToDayDto';
|
||||||
|
export type { WellDepthToIntervalDto } from './models/WellDepthToIntervalDto';
|
||||||
export type { WellDto } from './models/WellDto';
|
export type { WellDto } from './models/WellDto';
|
||||||
|
|
||||||
|
export { AnalyticsService } from './services/AnalyticsService';
|
||||||
export { AuthService } from './services/AuthService';
|
export { AuthService } from './services/AuthService';
|
||||||
export { DataService } from './services/DataService';
|
export { DataService } from './services/DataService';
|
||||||
export { MessageService } from './services/MessageService';
|
export { MessageService } from './services/MessageService';
|
||||||
|
8
src/services/api/models/OperationDurationDto.ts
Normal file
8
src/services/api/models/OperationDurationDto.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export type OperationDurationDto = {
|
||||||
|
processName?: string | null;
|
||||||
|
duration?: number;
|
||||||
|
}
|
9
src/services/api/models/WellDepthToDayDto.ts
Normal file
9
src/services/api/models/WellDepthToDayDto.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export type WellDepthToDayDto = {
|
||||||
|
wellDepth?: number;
|
||||||
|
bitDepth?: number;
|
||||||
|
date?: string;
|
||||||
|
}
|
8
src/services/api/models/WellDepthToIntervalDto.ts
Normal file
8
src/services/api/models/WellDepthToIntervalDto.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
export type WellDepthToIntervalDto = {
|
||||||
|
intervalStartDate?: string;
|
||||||
|
intervalDepthProgress?: number;
|
||||||
|
}
|
99
src/services/api/services/AnalyticsService.ts
Normal file
99
src/services/api/services/AnalyticsService.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/* istanbul ignore file */
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
import type { OperationDurationDto } from '../models/OperationDurationDto';
|
||||||
|
import type { WellDepthToDayDto } from '../models/WellDepthToDayDto';
|
||||||
|
import type { WellDepthToIntervalDto } from '../models/WellDepthToIntervalDto';
|
||||||
|
import { request as __request } from '../core/request';
|
||||||
|
|
||||||
|
export class AnalyticsService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает данные по скважине "глубина-день"
|
||||||
|
* @param wellId id скважины
|
||||||
|
* @returns WellDepthToDayDto Success
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async getWellDepthToDay(
|
||||||
|
wellId: number,
|
||||||
|
): Promise<Array<WellDepthToDayDto>> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'GET',
|
||||||
|
path: `/api/analytics/${wellId}/wellDepthToDay`,
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает данные по глубине скважины за период
|
||||||
|
* @param wellId id скважины
|
||||||
|
* @param intervalHoursTimestamp количество секунд в необходимом интервале времени
|
||||||
|
* @param workBeginTimestamp количество секунд в времени начала смены
|
||||||
|
* @returns WellDepthToIntervalDto Success
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async getWellDepthToInterval(
|
||||||
|
wellId: number,
|
||||||
|
intervalHoursTimestamp?: number,
|
||||||
|
workBeginTimestamp?: number,
|
||||||
|
): Promise<Array<WellDepthToIntervalDto>> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'GET',
|
||||||
|
path: `/api/analytics/${wellId}/wellDepthToInterval`,
|
||||||
|
query: {
|
||||||
|
'intervalHoursTimestamp': intervalHoursTimestamp,
|
||||||
|
'workBeginTimestamp': workBeginTimestamp,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает данные по операциям на скважине "операции-время"
|
||||||
|
* @param wellId id скважины
|
||||||
|
* @param begin дата начала интервала
|
||||||
|
* @param end дата окончания интервала
|
||||||
|
* @returns OperationDurationDto Success
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async getOperationsSummary(
|
||||||
|
wellId: number,
|
||||||
|
begin?: string,
|
||||||
|
end?: string,
|
||||||
|
): Promise<Array<OperationDurationDto>> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'GET',
|
||||||
|
path: `/api/analytics/${wellId}/operationsSummary`,
|
||||||
|
query: {
|
||||||
|
'begin': begin,
|
||||||
|
'end': end,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Возвращает детальные данные по операциям на скважине за период
|
||||||
|
* @param wellId id скважины
|
||||||
|
* @param intervalHoursTimestamp количество секунд в необходимом интервале времени
|
||||||
|
* @param workBeginTimestamp количество секунд в времени начала смены
|
||||||
|
* @returns OperationDurationDto Success
|
||||||
|
* @throws ApiError
|
||||||
|
*/
|
||||||
|
public static async getOperationsToInterval(
|
||||||
|
wellId: number,
|
||||||
|
intervalHoursTimestamp?: number,
|
||||||
|
workBeginTimestamp?: number,
|
||||||
|
): Promise<Array<OperationDurationDto>> {
|
||||||
|
const result = await __request({
|
||||||
|
method: 'GET',
|
||||||
|
path: `/api/analytics/${wellId}/operationsToInterval`,
|
||||||
|
query: {
|
||||||
|
'intervalHoursTimestamp': intervalHoursTimestamp,
|
||||||
|
'workBeginTimestamp': workBeginTimestamp,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return result.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user