forked from ddrilling/asb_cloud_front
chart.js полностью вырезан из проекта
This commit is contained in:
parent
183e9b8cde
commit
7a3f7e05c9
75
package-lock.json
generated
75
package-lock.json
generated
@ -10,10 +10,6 @@
|
||||
"dependencies": {
|
||||
"@microsoft/signalr": "^6.0.5",
|
||||
"antd": "^4.20.7",
|
||||
"chart.js": "^3.8.0",
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"chartjs-plugin-datalabels": "^2.0.0",
|
||||
"chartjs-plugin-zoom": "^1.2.1",
|
||||
"d3": "^7.4.4",
|
||||
"moment": "^2.29.3",
|
||||
"pigeon-maps": "^0.21.0",
|
||||
@ -4532,39 +4528,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/chart.js": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz",
|
||||
"integrity": "sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg=="
|
||||
},
|
||||
"node_modules/chartjs-adapter-moment": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.0.tgz",
|
||||
"integrity": "sha512-PqlerEvQcc5hZLQ/NQWgBxgVQ4TRdvkW3c/t+SUEQSj78ia3hgLkf2VZ2yGJtltNbEEFyYGm+cA6XXevodYvWA==",
|
||||
"peerDependencies": {
|
||||
"chart.js": "^3.0.0",
|
||||
"moment": "^2.10.2"
|
||||
}
|
||||
},
|
||||
"node_modules/chartjs-plugin-datalabels": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.0.0.tgz",
|
||||
"integrity": "sha512-WBsWihphzM0Y8fmQVm89+iy99mmgejmj5/jcsYqwxSioLRL/zqJ4Scv/eXq5ZqvG3TpojlGzZLeaOaSvDm7fwA==",
|
||||
"peerDependencies": {
|
||||
"chart.js": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chartjs-plugin-zoom": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.2.1.tgz",
|
||||
"integrity": "sha512-2zbWvw2pljrtMLMXkKw1uxYzAne5PtjJiOZftcut4Lo3Ee8qUt95RpMKDWrZ+pBZxZKQKOD/etdU4pN2jxZUmg==",
|
||||
"dependencies": {
|
||||
"hammerjs": "^2.0.8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chart.js": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
@ -6458,14 +6421,6 @@
|
||||
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/hammerjs": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
||||
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/handle-thing": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||
@ -15549,31 +15504,6 @@
|
||||
"integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
|
||||
"dev": true
|
||||
},
|
||||
"chart.js": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.8.0.tgz",
|
||||
"integrity": "sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg=="
|
||||
},
|
||||
"chartjs-adapter-moment": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.0.tgz",
|
||||
"integrity": "sha512-PqlerEvQcc5hZLQ/NQWgBxgVQ4TRdvkW3c/t+SUEQSj78ia3hgLkf2VZ2yGJtltNbEEFyYGm+cA6XXevodYvWA==",
|
||||
"requires": {}
|
||||
},
|
||||
"chartjs-plugin-datalabels": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-plugin-datalabels/-/chartjs-plugin-datalabels-2.0.0.tgz",
|
||||
"integrity": "sha512-WBsWihphzM0Y8fmQVm89+iy99mmgejmj5/jcsYqwxSioLRL/zqJ4Scv/eXq5ZqvG3TpojlGzZLeaOaSvDm7fwA==",
|
||||
"requires": {}
|
||||
},
|
||||
"chartjs-plugin-zoom": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.2.1.tgz",
|
||||
"integrity": "sha512-2zbWvw2pljrtMLMXkKw1uxYzAne5PtjJiOZftcut4Lo3Ee8qUt95RpMKDWrZ+pBZxZKQKOD/etdU4pN2jxZUmg==",
|
||||
"requires": {
|
||||
"hammerjs": "^2.0.8"
|
||||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
@ -16996,11 +16926,6 @@
|
||||
"integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==",
|
||||
"dev": true
|
||||
},
|
||||
"hammerjs": {
|
||||
"version": "2.0.8",
|
||||
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
||||
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
|
||||
},
|
||||
"handle-thing": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
|
||||
|
@ -5,10 +5,6 @@
|
||||
"dependencies": {
|
||||
"@microsoft/signalr": "^6.0.5",
|
||||
"antd": "^4.20.7",
|
||||
"chart.js": "^3.8.0",
|
||||
"chartjs-adapter-moment": "^1.0.0",
|
||||
"chartjs-plugin-datalabels": "^2.0.0",
|
||||
"chartjs-plugin-zoom": "^1.2.1",
|
||||
"d3": "^7.4.4",
|
||||
"moment": "^2.29.3",
|
||||
"pigeon-maps": "^0.21.0",
|
||||
|
@ -1,222 +0,0 @@
|
||||
import { memo, useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
Chart,
|
||||
TimeScale,
|
||||
LinearScale,
|
||||
Legend,
|
||||
LineController,
|
||||
PointElement,
|
||||
LineElement,
|
||||
ChartData,
|
||||
ChartOptions,
|
||||
ChartType,
|
||||
ChartDataset,
|
||||
Tooltip
|
||||
} 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,
|
||||
Tooltip,
|
||||
)
|
||||
|
||||
const defaultOptions: ChartOptions = {
|
||||
responsive: true,
|
||||
aspectRatio: 0.45,
|
||||
animation: false,
|
||||
events: ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove'],
|
||||
scales: {
|
||||
y: {
|
||||
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',
|
||||
}
|
||||
},
|
||||
|
||||
x: {
|
||||
type: 'linear',
|
||||
position: 'top'
|
||||
}
|
||||
},
|
||||
parsing: false,
|
||||
elements: {
|
||||
point: {
|
||||
radius: 0,
|
||||
hoverRadius: 5,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
datalabels: {
|
||||
display: false,
|
||||
},
|
||||
zoom: {
|
||||
zoom: {
|
||||
wheel: {
|
||||
enabled: true,
|
||||
modifierKey: 'alt',
|
||||
},
|
||||
pinch: {
|
||||
enabled: true
|
||||
},
|
||||
mode: 'x',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
callbacks: {
|
||||
label: (tooltipItem: any) => tooltipItem.yLabel
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
export type ChartTimeBaseProps = {
|
||||
dataParams: ChartTimeDataParams
|
||||
options?: ChartOptions
|
||||
}
|
||||
|
||||
export type TimeParams = {
|
||||
unit: string
|
||||
stepSize: number
|
||||
}
|
||||
|
||||
const linesPerInterval = 32
|
||||
|
||||
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 * intervals.minute)
|
||||
return 'second'
|
||||
|
||||
if(intervalSec <= 32 * intervals.hour)
|
||||
return 'minute'
|
||||
|
||||
if(intervalSec <= 32 * intervals.day / 2)
|
||||
return 'hour'
|
||||
|
||||
if(intervalSec <= 32 * intervals.day)
|
||||
return 'day'
|
||||
|
||||
if(intervalSec <= 32 * intervals.week)
|
||||
return 'week'
|
||||
|
||||
if(intervalSec <= 32 * intervals.year / 12)
|
||||
return 'month'
|
||||
|
||||
if(intervalSec <= 32 * intervals.year / 3)
|
||||
return 'quarter'
|
||||
|
||||
return 'year'
|
||||
}
|
||||
|
||||
export const timeParamsByInterval = (intervalSec: number): TimeParams => {
|
||||
const unit = timeUnitByInterval(intervalSec)
|
||||
const stepSize = Math.max(1, Math.round(intervalSec / intervals[unit] / linesPerInterval))
|
||||
return { unit, stepSize }
|
||||
}
|
||||
|
||||
export const ChartTimeBase = memo<ChartTimeBaseProps>(({ options, dataParams }) => {
|
||||
const chartRef = useRef<HTMLCanvasElement>(null)
|
||||
const [chart, setChart] = useState<any>()
|
||||
|
||||
useEffect(() => {
|
||||
const chartOptions: ChartOptions = {}
|
||||
Object.assign(chartOptions, defaultOptions, options)
|
||||
|
||||
const newChart = new Chart(chartRef.current ?? '', {
|
||||
type: 'line',
|
||||
plugins: [ChartDataLabels],
|
||||
options: chartOptions,
|
||||
data: { datasets: [] }
|
||||
})
|
||||
|
||||
setChart(newChart)
|
||||
return () => newChart?.destroy()
|
||||
}, [options])
|
||||
|
||||
useEffect(() => {
|
||||
if (!chart) return
|
||||
chart.data = dataParams.data
|
||||
if(dataParams.yStart){
|
||||
const interval = Number(dataParams.yInterval ?? 600_000)
|
||||
const { unit, stepSize } = timeParamsByInterval(Number(interval / 1000))
|
||||
|
||||
if(chart.options.scales?.y){
|
||||
chart.options.scales.y.max = +dataParams.yStart + interval
|
||||
chart.options.scales.y.min = +dataParams.yStart
|
||||
chart.options.scales.y.ticks.display = dataParams.displayLabels ?? true
|
||||
chart.options.scales.y.time.unit = unit
|
||||
chart.options.scales.y.time.stepSize = stepSize
|
||||
}
|
||||
}
|
||||
|
||||
chart.update(0)
|
||||
}, [chart, dataParams])
|
||||
|
||||
return(<canvas ref={chartRef} />)
|
||||
})
|
@ -1,122 +0,0 @@
|
||||
import { ChartOptions, Scriptable, ScriptableContext } from 'chart.js'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
import { makeDateSorter } from '@components/Table'
|
||||
import {
|
||||
ChartTimeBase,
|
||||
ChartTimeData,
|
||||
ChartTimeDataset,
|
||||
ChartTimeDataPoint,
|
||||
ChartTimeDataParams
|
||||
} from './ChartTimeBase'
|
||||
|
||||
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<'line'>>
|
||||
showDatalabels?: boolean
|
||||
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',
|
||||
borderRadius: 4,
|
||||
color: '#000B',
|
||||
display: context => !!context.dataset.label?.endsWith(' ') && 'auto',
|
||||
formatter: value => `${value.y.toLocaleTimeString()} ${value.label.toPrecision(4)}`,
|
||||
padding: 6,
|
||||
align: 'left',
|
||||
anchor: 'center',
|
||||
clip: true
|
||||
},
|
||||
legend: { display: false },
|
||||
tooltip: { enabled: true }
|
||||
}
|
||||
}
|
||||
|
||||
const GetRandomColor = () => '#' + Math.floor(Math.random() * (16**6 - 1)).toString(16)
|
||||
|
||||
export const GetOrCreateDatasetByLineConfig = (data: ChartTimeData, lineConfig: ColumnLineConfig): ChartTimeDataset => {
|
||||
let dataset = data?.datasets.find(d => d.label === lineConfig.label)
|
||||
if (!dataset) {
|
||||
const color = lineConfig.borderColor
|
||||
?? lineConfig.backgroundColor
|
||||
?? lineConfig.color
|
||||
?? GetRandomColor()
|
||||
|
||||
dataset = {
|
||||
label: lineConfig.label?.trimEnd() + (lineConfig.showDatalabels ? ' ' : ''),
|
||||
data: [],
|
||||
backgroundColor: lineConfig.backgroundColor ?? color,
|
||||
borderColor: lineConfig.borderColor ?? color,
|
||||
borderWidth: lineConfig.borderWidth ?? 1,
|
||||
borderDash: lineConfig.dash ?? [],
|
||||
showLine: lineConfig.showLine ?? !lineConfig.isShape,
|
||||
fill: lineConfig.fill ?? (lineConfig.isShape ? 'shape' : 'none'),
|
||||
}
|
||||
|
||||
data.datasets.push(dataset)
|
||||
}
|
||||
return dataset
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
setDataParams((preDataParams) => {
|
||||
lineGroup.forEach(lineCfg => {
|
||||
const dataset = GetOrCreateDatasetByLineConfig(preDataParams.data, lineCfg)
|
||||
let points: ChartTimeDataPoint[] = data.map(dataItem => ({
|
||||
x: lineCfg.xConstValue ?? dataItem[lineCfg.xAccessorName],
|
||||
label: dataItem[lineCfg.xAccessorName],
|
||||
y: new Date(dataItem[lineCfg.yAccessorName]),
|
||||
...additionalPointData?.(dataItem, lineCfg)
|
||||
}))
|
||||
|
||||
points = points.filter(point => (point.x ?? null) !== null && (point.y ?? null) !== null)
|
||||
|
||||
if(points?.length > 2)
|
||||
points.sort(makeDateSorter('y'))
|
||||
|
||||
dataset.data = points
|
||||
})
|
||||
|
||||
preDataParams.yStart = yStart
|
||||
preDataParams.yInterval = interval
|
||||
preDataParams.displayLabels = yDisplay
|
||||
|
||||
postParsing?.(preDataParams)
|
||||
return {...preDataParams}
|
||||
})
|
||||
|
||||
}, [data, lineGroup, interval, yDisplay, yStart, postParsing, additionalPointData])
|
||||
|
||||
return <ChartTimeBase dataParams = { dataParams } options = { chartPluginsOptions } />
|
||||
})
|
Loading…
Reference in New Issue
Block a user