@operato/chart 7.0.1 → 7.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/dist/src/chartjs/config-converter.js +7 -1
- package/dist/src/chartjs/config-converter.js.map +1 -1
- package/dist/src/editors/configurer.d.ts +2 -2
- package/dist/src/editors/configurer.js +0 -1
- package/dist/src/editors/configurer.js.map +1 -1
- package/dist/src/editors/input-chart-abstract.js +3 -2
- package/dist/src/editors/input-chart-abstract.js.map +1 -1
- package/dist/src/scichart/ox-scichart.js +11 -3
- package/dist/src/scichart/ox-scichart.js.map +1 -1
- package/dist/src/scichart/scichart-builder.js +169 -29
- package/dist/src/scichart/scichart-builder.js.map +1 -1
- package/dist/stories/common.js +2 -2
- package/dist/stories/common.js.map +1 -1
- package/dist/stories/ox-input-chart-timeseries.stories.js +42 -8
- package/dist/stories/ox-input-chart-timeseries.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/src/chartjs/config-converter.ts +12 -4
- package/src/editors/configurer.ts +0 -1
- package/src/editors/input-chart-abstract.ts +3 -2
- package/src/scichart/ox-scichart.ts +11 -3
- package/src/scichart/scichart-builder.ts +214 -30
- package/src/types.d.ts +14 -2
- package/stories/common.ts +2 -2
- package/stories/ox-input-chart-timeseries.stories.ts +42 -8
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { TinyColor } from '@ctrl/tinycolor'
|
|
2
2
|
import { format as formatText } from '../utils/text-formatter'
|
|
3
3
|
|
|
4
|
+
function getBaseColorFromTheme(theme?: 'light' | 'dark' | 'auto') {
|
|
5
|
+
return new TinyColor(theme == 'dark' ? '#fff' : '#000')
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function getThemeFromBrowser() {
|
|
9
|
+
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
|
10
|
+
}
|
|
11
|
+
|
|
4
12
|
export async function buildSciChart(
|
|
5
13
|
config: OperatoChart.ChartConfig | undefined | null,
|
|
6
14
|
container: any,
|
|
7
|
-
{ fontSize, fontFamily, fontColor
|
|
15
|
+
{ fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string }
|
|
8
16
|
): Promise<{ chart: any; dataSeries: any[] } | undefined> {
|
|
9
17
|
if (!config) {
|
|
10
18
|
return
|
|
@@ -12,10 +20,16 @@ export async function buildSciChart(
|
|
|
12
20
|
|
|
13
21
|
const {
|
|
14
22
|
SciChartSurface,
|
|
15
|
-
|
|
23
|
+
SciChartJSLightTheme,
|
|
24
|
+
SciChartJSDarkv2Theme,
|
|
16
25
|
XyDataSeries,
|
|
17
26
|
FastLineRenderableSeries,
|
|
27
|
+
SplineLineRenderableSeries,
|
|
18
28
|
FastColumnRenderableSeries,
|
|
29
|
+
StackedColumnRenderableSeries,
|
|
30
|
+
StackedMountainRenderableSeries,
|
|
31
|
+
StackedColumnCollection,
|
|
32
|
+
StackedMountainCollection,
|
|
19
33
|
NumericAxis,
|
|
20
34
|
DateTimeNumericAxis,
|
|
21
35
|
EAutoRange,
|
|
@@ -24,25 +38,60 @@ export async function buildSciChart(
|
|
|
24
38
|
MouseWheelZoomModifier,
|
|
25
39
|
RubberBandXyZoomModifier,
|
|
26
40
|
ZoomExtentsModifier,
|
|
27
|
-
RolloverModifier
|
|
41
|
+
RolloverModifier,
|
|
42
|
+
SmartDateLabelProvider,
|
|
43
|
+
EllipsePointMarker,
|
|
44
|
+
SquarePointMarker,
|
|
45
|
+
TrianglePointMarker,
|
|
46
|
+
CrossPointMarker,
|
|
47
|
+
XPointMarker,
|
|
48
|
+
WaveAnimation,
|
|
49
|
+
LegendModifier
|
|
28
50
|
} = SciChart
|
|
29
51
|
|
|
30
52
|
const { type: chartType, options, data: fromData } = config
|
|
31
|
-
const { theme, legend, scales: fromScales, xGridLine, yGridLine, y2ndGridLine } = options || {}
|
|
32
53
|
const { datasets = [] } = fromData || {}
|
|
54
|
+
var {
|
|
55
|
+
theme,
|
|
56
|
+
tooltip,
|
|
57
|
+
animation,
|
|
58
|
+
legend,
|
|
59
|
+
scales: fromScales,
|
|
60
|
+
xGridLine,
|
|
61
|
+
yGridLine,
|
|
62
|
+
y2ndGridLine,
|
|
63
|
+
stacked
|
|
64
|
+
} = options || {}
|
|
65
|
+
|
|
66
|
+
var baseColor = getBaseColorFromTheme(theme)
|
|
67
|
+
|
|
68
|
+
if (theme === 'auto') {
|
|
69
|
+
theme = getThemeFromBrowser()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fontColor = fontColor || baseColor.clone().toString()
|
|
33
73
|
|
|
34
74
|
const { xAxes = [], yAxes = [] } = fromScales || {}
|
|
35
75
|
|
|
36
76
|
const chart = await SciChartSurface.create(container, {
|
|
37
|
-
theme: new
|
|
77
|
+
theme: theme == 'dark' ? new SciChartJSDarkv2Theme() : new SciChartJSLightTheme()
|
|
38
78
|
})
|
|
39
79
|
const { sciChartSurface, wasmContext } = chart
|
|
40
80
|
|
|
41
81
|
// X 축 설정
|
|
42
82
|
xAxes.forEach((axis, index) => {
|
|
43
83
|
const { axisTitle, ticks } = axis
|
|
44
|
-
const {
|
|
45
|
-
|
|
84
|
+
const {
|
|
85
|
+
autoMax,
|
|
86
|
+
autoMin,
|
|
87
|
+
min,
|
|
88
|
+
max,
|
|
89
|
+
stepSize,
|
|
90
|
+
beginAtZero,
|
|
91
|
+
color = fontColor,
|
|
92
|
+
textStrokeColor = fontColor,
|
|
93
|
+
display = !!axisTitle
|
|
94
|
+
} = ticks || {}
|
|
46
95
|
|
|
47
96
|
const xAxis = new DateTimeNumericAxis(wasmContext, {
|
|
48
97
|
axisTitle,
|
|
@@ -54,13 +103,14 @@ export async function buildSciChart(
|
|
|
54
103
|
labelStyle: {
|
|
55
104
|
fontFamily,
|
|
56
105
|
fontSize,
|
|
57
|
-
color
|
|
106
|
+
color
|
|
58
107
|
},
|
|
59
108
|
axisTitleStyle: {
|
|
60
109
|
fontFamily,
|
|
61
110
|
fontSize,
|
|
62
|
-
color:
|
|
63
|
-
}
|
|
111
|
+
color: textStrokeColor
|
|
112
|
+
},
|
|
113
|
+
labelProvider: new SmartDateLabelProvider()
|
|
64
114
|
})
|
|
65
115
|
|
|
66
116
|
sciChartSurface.xAxes.add(xAxis)
|
|
@@ -70,12 +120,12 @@ export async function buildSciChart(
|
|
|
70
120
|
yAxes.forEach((axis, index) => {
|
|
71
121
|
const { axisTitle, ticks } = axis
|
|
72
122
|
const { autoMax, autoMin, min, max, stepSize, beginAtZero } = ticks || {}
|
|
73
|
-
const id = yAxes.length > 1 ? `right` : 'left'
|
|
74
123
|
|
|
75
124
|
const yAxis = new NumericAxis(wasmContext, {
|
|
125
|
+
id: `yAxis${index}`,
|
|
76
126
|
axisTitle,
|
|
77
127
|
autoRange: autoMin || autoMax ? EAutoRange.Always : undefined,
|
|
78
|
-
axisAlignment:
|
|
128
|
+
axisAlignment: index === 0 ? EAxisAlignment.Left : EAxisAlignment.Right,
|
|
79
129
|
visibleRange: min !== undefined && max !== undefined ? new NumberRange(min, max) : undefined,
|
|
80
130
|
majorDelta: stepSize,
|
|
81
131
|
growBy: beginAtZero ? new NumberRange(0.1, 0.1) : undefined,
|
|
@@ -90,6 +140,7 @@ export async function buildSciChart(
|
|
|
90
140
|
color: fontColor
|
|
91
141
|
}
|
|
92
142
|
})
|
|
143
|
+
|
|
93
144
|
sciChartSurface.yAxes.add(yAxis)
|
|
94
145
|
})
|
|
95
146
|
|
|
@@ -100,36 +151,158 @@ export async function buildSciChart(
|
|
|
100
151
|
containsNaN: false
|
|
101
152
|
})
|
|
102
153
|
|
|
154
|
+
const yAxisId = dataset.yAxisID || 'yAxis0'
|
|
155
|
+
const stackGroupId = dataset.stack || `__stack${index}__`
|
|
156
|
+
|
|
103
157
|
let series: any
|
|
104
158
|
if (dataset.type === 'bar') {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
159
|
+
if (stacked) {
|
|
160
|
+
series = new StackedColumnRenderableSeries(wasmContext, {
|
|
161
|
+
dataSeries,
|
|
162
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
163
|
+
fill: dataset.backgroundColor || '#FF6600',
|
|
164
|
+
yAxisId,
|
|
165
|
+
stackedGroupId: stackGroupId
|
|
166
|
+
})
|
|
167
|
+
} else {
|
|
168
|
+
series = new FastColumnRenderableSeries(wasmContext, {
|
|
169
|
+
dataSeries,
|
|
170
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
171
|
+
fill: dataset.backgroundColor || '#FF6600',
|
|
172
|
+
animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
|
|
173
|
+
yAxisId
|
|
174
|
+
})
|
|
175
|
+
}
|
|
110
176
|
} else {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
177
|
+
const { pointStyle, lineTension } = dataset
|
|
178
|
+
let pointMarker
|
|
179
|
+
|
|
180
|
+
switch (pointStyle) {
|
|
181
|
+
case 'circle':
|
|
182
|
+
pointMarker = new EllipsePointMarker(wasmContext, {
|
|
183
|
+
width: 10,
|
|
184
|
+
height: 10,
|
|
185
|
+
strokeThickness: 2,
|
|
186
|
+
fill: dataset.color || '#FF6600',
|
|
187
|
+
stroke: '#000000'
|
|
188
|
+
})
|
|
189
|
+
break
|
|
190
|
+
case 'triangle':
|
|
191
|
+
pointMarker = new TrianglePointMarker(wasmContext, {
|
|
192
|
+
width: 10,
|
|
193
|
+
height: 10,
|
|
194
|
+
strokeThickness: 2,
|
|
195
|
+
fill: dataset.color || '#FF6600',
|
|
196
|
+
stroke: '#000000'
|
|
197
|
+
})
|
|
198
|
+
break
|
|
199
|
+
case 'rect':
|
|
200
|
+
pointMarker = new SquarePointMarker(wasmContext, {
|
|
201
|
+
width: 10,
|
|
202
|
+
height: 10,
|
|
203
|
+
strokeThickness: 2,
|
|
204
|
+
fill: dataset.color || '#FF6600',
|
|
205
|
+
stroke: '#000000'
|
|
206
|
+
})
|
|
207
|
+
break
|
|
208
|
+
case 'cross':
|
|
209
|
+
pointMarker = new CrossPointMarker(wasmContext, {
|
|
210
|
+
width: 10,
|
|
211
|
+
height: 10,
|
|
212
|
+
strokeThickness: 2,
|
|
213
|
+
fill: dataset.color || '#FF6600',
|
|
214
|
+
stroke: '#000000'
|
|
215
|
+
})
|
|
216
|
+
break
|
|
217
|
+
case 'crossRot':
|
|
218
|
+
pointMarker = new XPointMarker(wasmContext, {
|
|
219
|
+
width: 10,
|
|
220
|
+
height: 10,
|
|
221
|
+
strokeThickness: 2,
|
|
222
|
+
fill: dataset.color || '#FF6600',
|
|
223
|
+
stroke: '#000000'
|
|
224
|
+
})
|
|
225
|
+
break
|
|
226
|
+
default:
|
|
227
|
+
pointMarker = new EllipsePointMarker(wasmContext, {
|
|
228
|
+
width: 10,
|
|
229
|
+
height: 10,
|
|
230
|
+
strokeThickness: 2,
|
|
231
|
+
fill: dataset.color || '#FF6600',
|
|
232
|
+
stroke: '#000000'
|
|
233
|
+
})
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (stacked) {
|
|
237
|
+
series = new StackedMountainRenderableSeries(wasmContext, {
|
|
238
|
+
dataSeries,
|
|
239
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
240
|
+
stroke: dataset.color || '#FF6600',
|
|
241
|
+
fill: dataset.backgroundColor || '#FF6600',
|
|
242
|
+
yAxisId,
|
|
243
|
+
stackedGroupId: stackGroupId
|
|
244
|
+
})
|
|
245
|
+
} else {
|
|
246
|
+
series =
|
|
247
|
+
!!lineTension && lineTension > 0
|
|
248
|
+
? new SplineLineRenderableSeries(wasmContext, {
|
|
249
|
+
dataSeries,
|
|
250
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
251
|
+
stroke: dataset.color || '#FF6600',
|
|
252
|
+
pointMarker,
|
|
253
|
+
animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
|
|
254
|
+
yAxisId
|
|
255
|
+
})
|
|
256
|
+
: new FastLineRenderableSeries(wasmContext, {
|
|
257
|
+
dataSeries,
|
|
258
|
+
strokeThickness: dataset.borderWidth || 2,
|
|
259
|
+
stroke: dataset.color || '#FF6600',
|
|
260
|
+
pointMarker,
|
|
261
|
+
animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
|
|
262
|
+
yAxisId
|
|
263
|
+
})
|
|
264
|
+
}
|
|
116
265
|
}
|
|
117
266
|
|
|
118
267
|
sciChartSurface.renderableSeries.add(series)
|
|
119
268
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
269
|
+
if (tooltip) {
|
|
270
|
+
const rolloverModifier = new RolloverModifier({
|
|
271
|
+
showTooltip: true,
|
|
272
|
+
showAxisLabels: true,
|
|
273
|
+
tooltipColor: 'white',
|
|
274
|
+
tooltipBackgroundColor: 'rgba(0, 0, 0, 0.7)',
|
|
275
|
+
rollOverDataSeries: dataSeries
|
|
276
|
+
})
|
|
127
277
|
|
|
128
|
-
|
|
278
|
+
sciChartSurface.chartModifiers.add(rolloverModifier)
|
|
279
|
+
}
|
|
129
280
|
|
|
130
281
|
return dataSeries
|
|
131
282
|
})
|
|
132
283
|
|
|
284
|
+
// Stacked collections 추가
|
|
285
|
+
if (stacked) {
|
|
286
|
+
const stackedColumnCollection = new StackedColumnCollection(wasmContext)
|
|
287
|
+
const stackedMountainCollection = new StackedMountainCollection(wasmContext)
|
|
288
|
+
|
|
289
|
+
sciChartSurface.renderableSeries.asArray().forEach((series: any) => {
|
|
290
|
+
if (series instanceof StackedColumnRenderableSeries) {
|
|
291
|
+
stackedColumnCollection.add(series)
|
|
292
|
+
} else if (series instanceof StackedMountainRenderableSeries) {
|
|
293
|
+
stackedMountainCollection.add(series)
|
|
294
|
+
}
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
if (stackedColumnCollection.size() > 0) {
|
|
298
|
+
sciChartSurface.renderableSeries.add(stackedColumnCollection)
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (stackedMountainCollection.size() > 0) {
|
|
302
|
+
sciChartSurface.renderableSeries.add(stackedMountainCollection)
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
133
306
|
// 줌인/줌아웃 모디파이어 추가
|
|
134
307
|
sciChartSurface.chartModifiers.add(
|
|
135
308
|
new RubberBandXyZoomModifier(),
|
|
@@ -137,5 +310,16 @@ export async function buildSciChart(
|
|
|
137
310
|
new ZoomExtentsModifier()
|
|
138
311
|
)
|
|
139
312
|
|
|
313
|
+
// Legend 설정
|
|
314
|
+
if (legend?.display) {
|
|
315
|
+
const legendModifier = new LegendModifier({
|
|
316
|
+
showCheckboxes: true,
|
|
317
|
+
showSeriesMarkers: true,
|
|
318
|
+
showLegend: true,
|
|
319
|
+
placement: legend.position || 'bottom-right'
|
|
320
|
+
})
|
|
321
|
+
sciChartSurface.chartModifiers.add(legendModifier)
|
|
322
|
+
}
|
|
323
|
+
|
|
140
324
|
return { chart, dataSeries: dataSeriesArray }
|
|
141
325
|
}
|
package/src/types.d.ts
CHANGED
|
@@ -24,7 +24,17 @@ declare namespace OperatoChart {
|
|
|
24
24
|
stack?: string
|
|
25
25
|
fill?: boolean
|
|
26
26
|
lineTension?: number
|
|
27
|
-
pointStyle?:
|
|
27
|
+
pointStyle?:
|
|
28
|
+
| 'circle'
|
|
29
|
+
| 'triangle'
|
|
30
|
+
| 'rect'
|
|
31
|
+
| 'rectRot'
|
|
32
|
+
| 'cross'
|
|
33
|
+
| 'crossRot'
|
|
34
|
+
| 'star'
|
|
35
|
+
| 'line'
|
|
36
|
+
| 'dash'
|
|
37
|
+
| undefined
|
|
28
38
|
pointRadius?: number
|
|
29
39
|
valuePrefix?: string
|
|
30
40
|
valueSuffix?: string
|
|
@@ -34,7 +44,7 @@ declare namespace OperatoChart {
|
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
export interface ChartOptions {
|
|
37
|
-
theme?: 'dark' | 'light'
|
|
47
|
+
theme?: 'dark' | 'light' | 'auto'
|
|
38
48
|
tooltip?: boolean
|
|
39
49
|
animation?: boolean
|
|
40
50
|
legend?: LegendOptions
|
|
@@ -74,5 +84,7 @@ declare namespace OperatoChart {
|
|
|
74
84
|
max?: number
|
|
75
85
|
stepSize?: number
|
|
76
86
|
beginAtZero?: boolean
|
|
87
|
+
color?: string
|
|
88
|
+
textStrokeColor?: string
|
|
77
89
|
}
|
|
78
90
|
}
|
package/stories/common.ts
CHANGED
|
@@ -63,10 +63,10 @@ function getRandomInRange(min: number, max: number) {
|
|
|
63
63
|
// 랜덤 데이터를 생성하는 함수
|
|
64
64
|
function generateRandomData(count: number) {
|
|
65
65
|
const randomData = []
|
|
66
|
-
const startTimestamp = Math.floor(Date.now()
|
|
66
|
+
const startTimestamp = Math.floor(Date.now()) // 현재 시간을 Unix 타임스탬프로 설정
|
|
67
67
|
|
|
68
68
|
for (let i = 0; i < count; i++) {
|
|
69
|
-
const timestamp = startTimestamp + i *
|
|
69
|
+
const timestamp = startTimestamp + i * 360 * 30 * 1000 // 3초씩 증가하는 타임스탬프 설정
|
|
70
70
|
const randomCount = getRandomInRange(5, 35) // count 값을 5에서 35 사이로 랜덤 생성
|
|
71
71
|
const randomAverage = getRandomInRange(50, 150) // average 값을 50에서 150 사이로 랜덤 생성
|
|
72
72
|
|
|
@@ -105,7 +105,7 @@ const Template: Story<ArgTypes> = ({ value }: ArgTypes) => html`
|
|
|
105
105
|
></ox-input-chart-timeseries>
|
|
106
106
|
<div id="charts">
|
|
107
107
|
<ox-scichart id="scichart" .data=${data} attr-x="timestamp" attr-y="count"></ox-scichart>
|
|
108
|
-
<ox-chart-js id="chartjs" .data=${data}></ox-chart-js>
|
|
108
|
+
<!-- <ox-chart-js id="chartjs" .data=${data}></ox-chart-js> -->
|
|
109
109
|
</div>
|
|
110
110
|
</div>
|
|
111
111
|
`
|
|
@@ -141,8 +141,22 @@ WithData.args = {
|
|
|
141
141
|
},
|
|
142
142
|
options: {
|
|
143
143
|
scales: {
|
|
144
|
-
xAxes: [
|
|
145
|
-
|
|
144
|
+
xAxes: [
|
|
145
|
+
{
|
|
146
|
+
axisTitle: 'timestamp',
|
|
147
|
+
ticks: { beginAtZero: true }
|
|
148
|
+
}
|
|
149
|
+
],
|
|
150
|
+
yAxes: [
|
|
151
|
+
{
|
|
152
|
+
axisTitle: 'count',
|
|
153
|
+
ticks: { beginAtZero: true }
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
axisTitle: 'average',
|
|
157
|
+
ticks: { beginAtZero: true }
|
|
158
|
+
}
|
|
159
|
+
]
|
|
146
160
|
},
|
|
147
161
|
legend: { display: true }
|
|
148
162
|
}
|
|
@@ -153,16 +167,13 @@ export const MultiAxis = Template.bind({})
|
|
|
153
167
|
MultiAxis.args = {
|
|
154
168
|
value: {
|
|
155
169
|
...getDefaultChartConfig('line'),
|
|
156
|
-
options: {
|
|
157
|
-
...getDefaultChartConfig('line').options,
|
|
158
|
-
multiAxis: true
|
|
159
|
-
},
|
|
160
170
|
data: {
|
|
161
171
|
datasets: [
|
|
162
172
|
{
|
|
163
173
|
label: 'Bar Series',
|
|
164
174
|
type: 'bar',
|
|
165
175
|
dataKey: 'count',
|
|
176
|
+
axisTitle: 'count',
|
|
166
177
|
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
|
167
178
|
borderColor: 'rgba(255, 99, 132, 1)',
|
|
168
179
|
borderWidth: 1,
|
|
@@ -172,16 +183,39 @@ MultiAxis.args = {
|
|
|
172
183
|
label: 'Line Series',
|
|
173
184
|
type: 'line',
|
|
174
185
|
dataKey: 'average',
|
|
186
|
+
axisTitle: 'average',
|
|
175
187
|
color: 'rgba(54, 162, 235, 1)',
|
|
176
188
|
borderWidth: 1,
|
|
177
189
|
fill: false,
|
|
178
190
|
lineTension: 0.4,
|
|
179
|
-
pointStyle: '
|
|
191
|
+
pointStyle: 'rect',
|
|
180
192
|
pointRadius: 3,
|
|
181
193
|
yAxisID: 'right'
|
|
182
194
|
}
|
|
183
195
|
],
|
|
184
196
|
labelDataKey: 'timestamp'
|
|
197
|
+
},
|
|
198
|
+
options: {
|
|
199
|
+
scales: {
|
|
200
|
+
xAxes: [
|
|
201
|
+
{
|
|
202
|
+
axisTitle: 'timestamp',
|
|
203
|
+
ticks: { beginAtZero: true }
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
yAxes: [
|
|
207
|
+
{
|
|
208
|
+
axisTitle: 'count',
|
|
209
|
+
ticks: { beginAtZero: true }
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
axisTitle: 'average',
|
|
213
|
+
ticks: { beginAtZero: true }
|
|
214
|
+
}
|
|
215
|
+
]
|
|
216
|
+
},
|
|
217
|
+
multiAxis: true,
|
|
218
|
+
legend: { display: true }
|
|
185
219
|
}
|
|
186
220
|
}
|
|
187
221
|
}
|