График скорость проходки-интервал

This commit is contained in:
Alexey 2021-07-20 16:15:44 +05:00
parent f62b280ee5
commit c119f22aa4
7 changed files with 149 additions and 123 deletions

View File

@ -1,15 +1,35 @@
import { useParams } from "react-router-dom" import { useParams } from "react-router-dom"
import { DatePicker } from 'antd'
import notify from "../components/notify" import notify from "../components/notify"
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { AnalyticsService } from "../services/api" import { AnalyticsService } from '../services/api'
import { ChartDepthToInterval } from './charts/ChartDepthToInterval' import { ChartDepthToInterval } from './charts/ChartDepthToInterval'
import { Select } from 'antd'
const line = {label: 'Данные по глубине скважины за период', y: 'intervalDepthProgress', x: 'intervalStartDate'} const { Option } = Select
const timePeriodCollection = [
{ value: '60', label: '1 минута' },
{ value: '300', label: '5 минут' },
{ value: '600', label: '10 минут' },
{ value: '1800', label: '30 минут' },
{ value: '3600', label: '1 час' },
{ value: '21600', label: '6 часов' },
{ value: '43200', label: '12 часов' },
{ value: '86400', label: '24 часа' }
]
const { RangePicker } = DatePicker
const lines = [{ label: 'График скорость проходки-интервал', yAccessorName: "intervalDepthProgress", xAccessorName: "intervalStartDate", color: '#00f' }]
export function AnalysisDepthToInterval() { export function AnalysisDepthToInterval() {
let { id } = useParams() let { id } = useParams()
const [depthToIntervalData, setDepthToIntervalData] = useState([]) const [depthToIntervalData, setDepthToIntervalData] = useState([])
const [loader, setLoader] = useState(false) const [loader, setLoader] = useState(false)
const [chartInterval, setChartInterval] = useState(600)
const children = timePeriodCollection.map((line) => <Option key={line.value}>{line.label}</Option>)
const handleReceiveDepthToIntervalData = (data) => { const handleReceiveDepthToIntervalData = (data) => {
setDepthToIntervalData(data) setDepthToIntervalData(data)
@ -17,7 +37,7 @@ export function AnalysisDepthToInterval() {
useEffect(() => { useEffect(() => {
setLoader(true) setLoader(true)
AnalyticsService.getWellDepthToInterval(id) AnalyticsService.getWellDepthToInterval(id, chartInterval)
.then(handleReceiveDepthToIntervalData) .then(handleReceiveDepthToIntervalData)
.catch(error => { .catch(error => {
notify(`Не удалось получить данные для Анализа Глубина-День по скважине "${id}"`, notify(`Не удалось получить данные для Анализа Глубина-День по скважине "${id}"`,
@ -25,13 +45,16 @@ export function AnalysisDepthToInterval() {
console.log(error) console.log(error)
}) })
.finally(setLoader(false)) .finally(setLoader(false))
}, [id]) }, [id, chartInterval])
return ( return (
<> <>
<Select defaultValue="600" onChange={setChartInterval}>
{children}
</Select>
<ChartDepthToInterval <ChartDepthToInterval
data={depthToIntervalData} data={depthToIntervalData}
line={line} lines={lines}
/> />
</> </>
) )

View File

@ -19,7 +19,7 @@ Chart.register(TimeScale, LinearScale, LineController, LineElement, PointElement
const defaultOptions = { const defaultOptions = {
responsive: true, responsive: true,
aspectRatio: 1.45, aspectRatio: 6,
animation: false, animation: false,
tooltips: { tooltips: {
enabled: true, enabled: true,
@ -33,7 +33,7 @@ const defaultOptions = {
scales: { scales: {
x:{ x:{
type: 'time', type: 'time',
reverse: true, reverse: false,
time: { time: {
stepSize: 20, stepSize: 20,
displayFormats: { displayFormats: {
@ -53,7 +53,7 @@ const defaultOptions = {
}, },
ticks: { ticks: {
z: 1, z: 1,
display : false, display : true,
textStrokeColor : "#ffff", textStrokeColor : "#ffff",
textStrokeWidth : 2, textStrokeWidth : 2,
color:"#000", color:"#000",
@ -78,18 +78,6 @@ const defaultOptions = {
datalabels: { datalabels: {
display: false, display: false,
}, },
// zoom: {
// zoom: {
// wheel: {
// enabled: true,
// modifierKey: 'alt',
// },
// pinch: {
// enabled: true
// },
// mode: 'x',
// }
// },
} }
} }

View File

@ -2,8 +2,8 @@ import { useEffect, useState } from 'react'
import { ChartDepthToIntervalBase } from './ChartDepthToIntervalBase' import { ChartDepthToIntervalBase } from './ChartDepthToIntervalBase'
import { CreateDataset } from './ChartTimeArchive' import { CreateDataset } from './ChartTimeArchive'
export function ChartDepthToInterval({data, lines}) { export const ChartDepthToInterval = ({ lines, data }) => {
const [depthToIntervalDataParams, setDepthToIntervalDataParams] = useState({data: {datasets: []}}) const [depthToIntervalDataParams, setDepthToIntervalDataParams] = useState({ data: { datasets: [] } })
useEffect(() => { useEffect(() => {
if ((!lines) if ((!lines)
@ -12,11 +12,11 @@ export function ChartDepthToInterval({data, lines}) {
let newDatasets = lines.map(lineCfg => { let newDatasets = lines.map(lineCfg => {
let datasets = CreateDataset(lineCfg) let datasets = CreateDataset(lineCfg)
if(data.length !== 0) if (data.length !== 0)
datasets.data = data.map(dataItem => { datasets.data = data.map(dataItem => {
return { return {
x: new Date(dataItem[lineCfg.x??'date']), x: new Date(dataItem[lineCfg.xAccessorName ?? 'intervalStartDate']),
y: dataItem[lineCfg.y], y: dataItem[lineCfg.yAccessorName ?? 'intervalDepthProgress'],
} }
}) })
return datasets return datasets
@ -29,9 +29,11 @@ export function ChartDepthToInterval({data, lines}) {
} }
} }
setDepthToIntervalDataParams(newParams) setDepthToIntervalDataParams(newParams)
}, [data, lines]) }, [data, lines])
return ( return (<>
<ChartDepthToIntervalBase dataParams={depthToIntervalDataParams} /> <ChartDepthToIntervalBase dataParams={depthToIntervalDataParams} />
) </>
)
} }

View File

@ -1,37 +1,41 @@
import {useEffect, useRef, useState} from 'react' import { useEffect, useRef, useState } from 'react'
import { import {
Chart, Chart,
TimeScale, TimeScale,
Legend, Legend,
PointElement, PointElement,
ChartData, ChartData,
ChartTypeRegistry, ChartTypeRegistry,
ChartOptions, ChartOptions,
BarController, BarController,
BarElement BarElement,
TimeSeriesScale,
LinearScale,
LineController,
} from 'chart.js' } from 'chart.js'
import 'chartjs-adapter-moment' import 'chartjs-adapter-moment'
import ChartDataLabels from 'chartjs-plugin-datalabels' import ChartDataLabels from 'chartjs-plugin-datalabels'
Chart.register(TimeScale, BarController, BarElement, PointElement, Legend, ChartDataLabels) Chart.register(TimeScale, BarController, BarElement, PointElement, TimeSeriesScale, LineController, LinearScale, Legend, ChartDataLabels)
const defaultOptions = { const defaultOptions = {
responsive: true, responsive: true,
aspectRatio: 1.45, aspectRatio: 4,
animation: false, animation: false,
tooltips: { tooltips: {
enabled: true, enabled: true,
callbacks: { callbacks: {
label(tooltipItem:any) { label(tooltipItem: any) {
return tooltipItem.yLabel; return tooltipItem.yLabel;
} }
} }
}, },
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'], events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
scales: { scales: {
x:{ x: {
position: 'bottom',
type: 'time', type: 'time',
reverse: true, reverse: false,
time: { time: {
stepSize: 20, stepSize: 20,
displayFormats: { displayFormats: {
@ -46,34 +50,33 @@ const defaultOptions = {
year: 'yyyy.MM', year: 'yyyy.MM',
}, },
}, },
grid:{ grid: {
drawTicks: false, drawTicks: false,
}, },
ticks: { ticks: {
z: 1, z: 1,
display : false, display: true,
textStrokeColor : "#ffff", textStrokeColor: "#ffff",
textStrokeWidth : 2, textStrokeWidth: 2,
color:"#000", color: "#000",
} }
}, },
y: {
y:{ beginAtZero: true,
beginAtZero: true
} }
}, },
elements:{ elements: {
point:{ point: {
radius:0, radius: 0,
hoverRadius:5, hoverRadius: 5,
}, },
}, },
plugins:{ plugins: {
legend:{ legend: {
display: true, display: true,
}, },
datalabels: { datalabels: {
display: false, display: true,
}, },
} }
} }
@ -104,39 +107,39 @@ export type TimeParams = {
const linesPerInterval = 32 const linesPerInterval = 32
export const timeUnitByInterval = (intervalSec:number):String => { export const timeUnitByInterval = (intervalSec: number): String => {
if(intervalSec <= 60) if (intervalSec <= 60)
return 'millisecond' return 'millisecond'
if(intervalSec <= 32*60) if (intervalSec <= 32 * 60)
return 'second' return 'second'
if(intervalSec <= 32*60*60) if (intervalSec <= 32 * 60 * 60)
return 'minute' return 'minute'
if(intervalSec <= 32*12*60*60) if (intervalSec <= 32 * 12 * 60 * 60)
return 'hour' return 'hour'
if(intervalSec <= 32*24*60*60) if (intervalSec <= 32 * 24 * 60 * 60)
return 'day' return 'day'
if(intervalSec <= 32*7*24*60*60) if (intervalSec <= 32 * 7 * 24 * 60 * 60)
return 'week' return 'week'
if(intervalSec <= 32*30.4375*24*60*60) if (intervalSec <= 32 * 30.4375 * 24 * 60 * 60)
return 'month' return 'month'
if(intervalSec <= 32*121.75*24*60*60) if (intervalSec <= 32 * 121.75 * 24 * 60 * 60)
return 'quarter' return 'quarter'
else else
return 'year' return 'year'
} }
export 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)
switch(unit){ switch (unit) {
case "millisecond": case "millisecond":
stepSize *= 1000 stepSize *= 1000
break; break;
@ -147,65 +150,65 @@ export const timeParamsByInterval = (intervalSec:number) :TimeParams => {
stepSize /= 60 stepSize /= 60
break; break;
case "hour": case "hour":
stepSize /= 60*60 stepSize /= 60 * 60
break; break;
case "day": case "day":
stepSize /= 24*60*60 stepSize /= 24 * 60 * 60
break; break;
case "week": case "week":
stepSize /= 7*24*60*60 stepSize /= 7 * 24 * 60 * 60
break; break;
case "month": case "month":
stepSize /= 30*24*60*60 stepSize /= 30 * 24 * 60 * 60
break; break;
case "quarter": case "quarter":
stepSize /= 91*24*60*60 stepSize /= 91 * 24 * 60 * 60
break; break;
case "year": case "year":
stepSize /= 365.25*24*60*60 stepSize /= 365.25 * 24 * 60 * 60
break; break;
} }
stepSize = Math.round(stepSize/linesPerInterval) stepSize = Math.round(stepSize / linesPerInterval)
stepSize = stepSize > 0 ? stepSize : 1; stepSize = stepSize > 0 ? stepSize : 1;
return {unit, stepSize} return { unit, stepSize }
} }
export const ChartDepthToIntervalBase: React.FC<ChartTimeBaseProps> = ({options, dataParams}) => { export const ChartDepthToIntervalBase: React.FC<ChartTimeBaseProps> = ({ options, dataParams }) => {
const chartRef = useRef<HTMLCanvasElement>(null) const chartRef = useRef<HTMLCanvasElement>(null)
const [chart, setChart] = useState<any>() const [chart, setChart] = useState<any>()
useEffect(() => { useEffect(() => {
if((chartRef.current)&&(!chart)) { if ((chartRef.current) && (!chart)) {
let thisOptions = {} let thisOptions = {}
Object.assign(thisOptions, defaultOptions, options) Object.assign(thisOptions, defaultOptions, options)
let newChart = new Chart(chartRef.current, { let newChart = new Chart(chartRef.current, {
type: 'bar', type: 'bar',
plugins: [ChartDataLabels], plugins: [ChartDataLabels],
options: thisOptions, options: thisOptions,
data: dataParams.data data: dataParams.data
}) })
setChart(newChart) setChart(newChart)
return () => chart?.destroy() return () => chart?.destroy()
} }
}, [chart, options, dataParams]) }, [chart, options, dataParams])
useEffect(() => { useEffect(() => {
if (!chart) if (!chart)
return return
chart.data = dataParams.data chart.data = dataParams.data
chart.options.aspectRatio = options?.aspectRatio chart.options.aspectRatio = options?.aspectRatio
if (dataParams.xStart) { if (dataParams.xStart) {
let interval = Number(dataParams.xInterval ?? 600) let interval = Number(dataParams.xInterval ?? 600)
let start = new Date(dataParams.xStart) let start = new Date(dataParams.xStart)
let end = new Date(dataParams.xStart) let end = new Date(dataParams.xStart)
end.setSeconds(end.getSeconds() + interval) end.setSeconds(end.getSeconds() + interval)
let {unit, stepSize} = timeParamsByInterval(interval) let { unit, stepSize } = timeParamsByInterval(interval)
if(chart.options.scales?.x){ if (chart.options.scales?.x) {
chart.options.scales.x.max = end.getTime() chart.options.scales.x.max = end.getTime()
chart.options.scales.x.min = start.getTime() chart.options.scales.x.min = start.getTime()
chart.options.scales.x.ticks.display = dataParams.displayLabels ?? true chart.options.scales.x.ticks.display = dataParams.displayLabels ?? true
@ -214,8 +217,11 @@ export const ChartDepthToIntervalBase: React.FC<ChartTimeBaseProps> = ({options,
} }
} }
chart.update() chart.update()
}, [chart, dataParams, options]) }, [chart, dataParams, options])
return(<canvas ref={chartRef} />) return (<canvas style={{
width: "100px",
height: "100px"
}} ref={chartRef} />)
} }

View File

@ -6,6 +6,7 @@ export default function Analysis() {
return ( return (
<> <>
<AnalysisDepthToDay /> <AnalysisDepthToDay />
<div style={{ marginTop: '100px' }}>&nbsp;</div>
<AnalysisDepthToInterval /> <AnalysisDepthToInterval />
</> </>
) )

View File

@ -15,7 +15,7 @@ import moment from 'moment'
import notify from '../components/notify' import notify from '../components/notify'
import LoaderPortal from '../components/LoaderPortal' import LoaderPortal from '../components/LoaderPortal'
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker
const SaveObject = (key, obj) => { const SaveObject = (key, obj) => {
let json = JSON.stringify(obj) let json = JSON.stringify(obj)

View File

@ -183,6 +183,17 @@ const columns = [
}, },
]; ];
const timePeriodCollection = [
{value: '60', label: '1 минута'},
{value: '300', label: '5 минут'},
{value: '600', label: '10 минут'},
{value: '1800', label: '30 минут'},
{value: '3600', label: '1 час'},
{value: '21600', label: '6 часов'},
{value: '43200', label: '12 часов'},
{value: '86400', label: '24 часа'}
]
export default function TelemetryView(props) { export default function TelemetryView(props) {
let {id} = useParams() let {id} = useParams()
const [saubData, setSaubData] = useState([]) const [saubData, setSaubData] = useState([])
@ -191,6 +202,8 @@ export default function TelemetryView(props) {
const [loader, setLoader] = useState(false) // , setLoader const [loader, setLoader] = useState(false) // , setLoader
const children = timePeriodCollection.map((line) => <Option key={line.value}>{line.label}</Option>)
const handleReceiveDataSaub = (data) => { const handleReceiveDataSaub = (data) => {
if (data) { if (data) {
setSaubData(data) setSaubData(data)
@ -248,14 +261,7 @@ export default function TelemetryView(props) {
<Col> <Col>
Интервал:&nbsp; Интервал:&nbsp;
<Select defaultValue="600" onChange={setChartInterval}> <Select defaultValue="600" onChange={setChartInterval}>
<Option value='60'>1 минута</Option> {children}
<Option value='300'>5 минут</Option>
<Option value='600'>10 минут</Option>
<Option value='1800'>30 минут</Option>
<Option value='3600'>1 час</Option>
<Option value='21600'>6 час</Option>
<Option value='43200'>12 часов</Option>
<Option value='86400'>1 день</Option>
</Select> </Select>
</Col> </Col>
<span style={{flexGrow: 1}}>&nbsp;</span> <span style={{flexGrow: 1}}>&nbsp;</span>