@operato/chart 7.1.31 → 7.1.33

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/tsconfig.tsbuildinfo +1 -1
  3. package/package.json +9 -9
  4. package/.editorconfig +0 -29
  5. package/.storybook/main.js +0 -3
  6. package/.storybook/preview.js +0 -52
  7. package/.storybook/server.mjs +0 -8
  8. package/demo/index.html +0 -33
  9. package/src/chartjs/config-converter.ts +0 -341
  10. package/src/chartjs/ox-chart-js.ts +0 -207
  11. package/src/editors/configurer.ts +0 -336
  12. package/src/editors/index.ts +0 -8
  13. package/src/editors/input-chart-abstract.ts +0 -202
  14. package/src/editors/input-chart-styles.ts +0 -206
  15. package/src/editors/ox-input-chart-hbar.ts +0 -157
  16. package/src/editors/ox-input-chart-mixed.ts +0 -241
  17. package/src/editors/ox-input-chart-pie.ts +0 -69
  18. package/src/editors/ox-input-chart-radar.ts +0 -56
  19. package/src/editors/ox-input-chart-timeseries.ts +0 -279
  20. package/src/editors/ox-property-editor-chart.ts +0 -72
  21. package/src/editors/templates/annotations.ts +0 -295
  22. package/src/editors/templates/display-value.ts +0 -111
  23. package/src/editors/templates/series.ts +0 -316
  24. package/src/index.ts +0 -0
  25. package/src/progress/ox-progress-circle.ts +0 -133
  26. package/src/scichart/ox-scichart.ts +0 -151
  27. package/src/scichart/scichart-builder.ts +0 -490
  28. package/stories/common.ts +0 -87
  29. package/stories/ox-input-chart-bar.stories.ts +0 -188
  30. package/stories/ox-input-chart-doughnut.stories.ts +0 -130
  31. package/stories/ox-input-chart-hbar.stories.ts +0 -188
  32. package/stories/ox-input-chart-line.stories.ts +0 -198
  33. package/stories/ox-input-chart-pie.stories.ts +0 -130
  34. package/stories/ox-input-chart-polar-area.stories.ts +0 -130
  35. package/stories/ox-input-chart-radar.stories.ts +0 -141
  36. package/stories/ox-input-chart-timeseries.stories.ts +0 -268
  37. package/tsconfig.json +0 -25
  38. package/web-dev-server.config.mjs +0 -27
  39. package/web-test-runner.config.mjs +0 -41
  40. /package/{src → types}/global.d.ts +0 -0
  41. /package/{src → types}/types.d.ts +0 -0
@@ -1,490 +0,0 @@
1
- import { TinyColor } from '@ctrl/tinycolor'
2
- import { format as formatText } from '@operato/utils/format.js'
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
-
12
- function convertColor(color: string | string[] | undefined, defaultColor?: string) {
13
- const tinyColor = new TinyColor(color as string)
14
- return tinyColor.toHex8String() || defaultColor
15
- }
16
-
17
- function getLocalTimeOffset() {
18
- const now = new Date()
19
- return now.getTimezoneOffset() * -60
20
- }
21
-
22
- function calculatePrecision(stepSize: number = 1) {
23
- // stepSize를 문자열로 변환한 다음, 소수점 이후 자릿수를 계산
24
- const stepSizeString = stepSize.toString()
25
-
26
- // 소수점이 있는 경우, 소수점 이후 자릿수 계산
27
- if (stepSizeString.indexOf('.') !== -1) {
28
- return stepSizeString.split('.')[1].length
29
- }
30
-
31
- // 소수점이 없는 경우, precision은 0
32
- return 0
33
- }
34
-
35
- export async function buildSciChart(
36
- config: OperatoChart.ChartConfig | undefined | null,
37
- container: any,
38
- { fontSize = 14, fontFamily = 'Roboto', fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string }
39
- ): Promise<{ chart: any; dataSeries: any[] } | undefined> {
40
- if (!config) {
41
- return
42
- }
43
-
44
- const {
45
- SciChartSurface,
46
- SciChartJSLightTheme,
47
- SciChartJSDarkv2Theme,
48
- XyDataSeries,
49
- FastLineRenderableSeries,
50
- SplineLineRenderableSeries,
51
- FastColumnRenderableSeries,
52
- StackedColumnRenderableSeries,
53
- StackedMountainRenderableSeries,
54
- StackedColumnCollection,
55
- StackedMountainCollection,
56
- NumericAxis,
57
- DateTimeNumericAxis,
58
- ENumericFormat,
59
- EAutoRange,
60
- EAxisAlignment,
61
- ECoordinateMode,
62
- EHorizontalAnchorPoint,
63
- EVerticalAnchorPoint,
64
- NumberRange,
65
- MouseWheelZoomModifier,
66
- RubberBandXyZoomModifier,
67
- ZoomPanModifier,
68
- ZoomExtentsModifier,
69
- RolloverModifier,
70
- SmartDateLabelProvider,
71
- NumericLabelProvider,
72
- EllipsePointMarker,
73
- SquarePointMarker,
74
- TrianglePointMarker,
75
- CrossPointMarker,
76
- XPointMarker,
77
- WaveAnimation,
78
- LegendModifier,
79
- XAxisDragModifier,
80
- YAxisDragModifier,
81
- TextAnnotation,
82
- LineAnnotation,
83
- BoxAnnotation,
84
- HorizontalLineAnnotation,
85
- VerticalLineAnnotation
86
- } = SciChart
87
-
88
- class LocalTimeLabelProvider extends SmartDateLabelProvider {
89
- formatLabel(value: number): string {
90
- const date = new Date(value)
91
- return new Intl.DateTimeFormat('default', {
92
- year: 'numeric',
93
- month: '2-digit',
94
- day: '2-digit',
95
- hour: '2-digit',
96
- minute: '2-digit',
97
- second: '2-digit'
98
- }).format(date)
99
- }
100
- }
101
-
102
- const { type: chartType, options, data: fromData } = config
103
- const { datasets = [] } = fromData || {}
104
- var {
105
- theme,
106
- tooltip = true,
107
- animation = true,
108
- legend = {
109
- display: true,
110
- position: 'top'
111
- },
112
- scales: fromScales,
113
- xGridLine = true,
114
- yGridLine = true,
115
- y2ndGridLine = false,
116
- stacked = false,
117
- multiAxis = false,
118
- annotations = []
119
- } = options || {}
120
-
121
- var baseColor = getBaseColorFromTheme(theme)
122
-
123
- if (theme === 'auto') {
124
- theme = getThemeFromBrowser()
125
- }
126
-
127
- fontColor = fontColor || baseColor.clone().toString()
128
-
129
- const { xAxes = [], yAxes = [] } = fromScales || {}
130
-
131
- const chart = await SciChartSurface.create(container, {
132
- theme: theme == 'dark' ? new SciChartJSDarkv2Theme() : new SciChartJSLightTheme()
133
- })
134
- const { sciChartSurface, wasmContext } = chart
135
-
136
- // X 축 설정
137
- xAxes.forEach((axis, index) => {
138
- const { axisTitle, ticks } = axis
139
- const {
140
- autoMax,
141
- autoMin,
142
- min,
143
- max,
144
- stepSize,
145
- beginAtZero,
146
- color = fontColor,
147
- textStrokeColor = fontColor,
148
- display = !!axisTitle
149
- } = ticks || {}
150
-
151
- const labelProvider = new SmartDateLabelProvider({
152
- showWiderDateOnFirstLabel: true,
153
- showYearOnWiderDate: true,
154
- dateOffset: getLocalTimeOffset()
155
- })
156
-
157
- labelProvider.cursorNumericFormat = ENumericFormat.Date_MMHHSS
158
-
159
- const xAxis = new DateTimeNumericAxis(wasmContext, {
160
- axisTitle,
161
- autoRange: autoMin || autoMax ? EAutoRange.Always : undefined,
162
- axisAlignment: EAxisAlignment.Bottom,
163
- visibleRange: min !== undefined && max !== undefined ? new NumberRange(min, max) : undefined,
164
- majorDelta: stepSize,
165
- growBy: beginAtZero ? new NumberRange(0.1, 0.1) : undefined,
166
- labelStyle: {
167
- fontFamily,
168
- fontSize,
169
- color
170
- },
171
- axisTitleStyle: {
172
- fontFamily,
173
- fontSize,
174
- color: textStrokeColor
175
- },
176
- labelProvider
177
- })
178
-
179
- sciChartSurface.xAxes.add(xAxis)
180
- })
181
-
182
- // Y 축 설정
183
- ;(multiAxis ? yAxes : [yAxes[0]]).forEach((axis, index) => {
184
- const { axisTitle, ticks } = axis
185
- const { autoMax, autoMin, min, max, stepSize, beginAtZero, display } = ticks || {}
186
-
187
- const labelProvider = display ? new NumericLabelProvider() : undefined
188
-
189
- if (labelProvider) {
190
- labelProvider.numericFormat = ENumericFormat.Decimal
191
- labelProvider.precision = calculatePrecision(stepSize || 0.1)
192
- labelProvider.cursorNumericFormat = ENumericFormat.NoFormat
193
- }
194
-
195
- const yAxis = new NumericAxis(wasmContext, {
196
- id: index == 0 ? undefined : `yAxis${index}`,
197
- axisTitle,
198
- autoRange: autoMin || autoMax ? EAutoRange.Always : undefined,
199
- axisAlignment: index === 0 ? EAxisAlignment.Left : EAxisAlignment.Right,
200
- visibleRange: min !== undefined && max !== undefined ? new NumberRange(min, max) : undefined,
201
- majorDelta: stepSize || 0.1,
202
- minorDelta: (stepSize || 1) * 0.1,
203
- growBy: beginAtZero ? new NumberRange(0.1, 0.1) : undefined,
204
- labelStyle: {
205
- display: !!display,
206
- fontFamily,
207
- fontSize,
208
- color: fontColor
209
- },
210
- axisTitleStyle: {
211
- fontFamily,
212
- fontSize,
213
- color: fontColor
214
- },
215
- labelProvider
216
- })
217
-
218
- sciChartSurface.yAxes.add(yAxis)
219
- })
220
-
221
- // 시리즈 설정
222
- const dataSeriesArray = datasets.map((dataset, index) => {
223
- const dataSeries = new XyDataSeries(wasmContext, {
224
- dataSeriesName: dataset.label,
225
- containsNaN: false
226
- })
227
-
228
- const yAxisId = dataset.yAxisID == 'right' && multiAxis ? 'yAxis1' : undefined
229
- const stackGroupId = dataset.stack || `__stack${index}__`
230
-
231
- let series: any
232
- if (dataset.type === 'bar') {
233
- if (stacked) {
234
- series = new StackedColumnRenderableSeries(wasmContext, {
235
- dataSeries,
236
- strokeThickness: dataset.borderWidth || 2,
237
- fill: convertColor(dataset.backgroundColor, '#FF6600'),
238
- yAxisId,
239
- stackedGroupId: stackGroupId
240
- })
241
- } else {
242
- series = new FastColumnRenderableSeries(wasmContext, {
243
- dataSeries,
244
- strokeThickness: dataset.borderWidth || 2,
245
- stroke: convertColor(dataset.backgroundColor, '#FF6600'),
246
- animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
247
- yAxisId
248
- })
249
- }
250
- } else {
251
- const { pointStyle, pointRadius = 10, lineTension } = dataset
252
- let pointMarker = null // 초기값을 null로 설정
253
-
254
- if (pointStyle) {
255
- switch (pointStyle) {
256
- case 'circle':
257
- pointMarker = new EllipsePointMarker(wasmContext, {
258
- width: pointRadius,
259
- height: pointRadius,
260
- strokeThickness: 2,
261
- fill: convertColor(dataset.color, '#FF6600'),
262
- stroke: '#000000'
263
- })
264
- break
265
- case 'triangle':
266
- pointMarker = new TrianglePointMarker(wasmContext, {
267
- width: pointRadius,
268
- height: pointRadius,
269
- strokeThickness: 2,
270
- fill: convertColor(dataset.color, '#FF6600'),
271
- stroke: '#000000'
272
- })
273
- break
274
- case 'rect':
275
- pointMarker = new SquarePointMarker(wasmContext, {
276
- width: pointRadius,
277
- height: pointRadius,
278
- strokeThickness: 2,
279
- fill: convertColor(dataset.color, '#FF6600'),
280
- stroke: '#000000'
281
- })
282
- break
283
- case 'cross':
284
- pointMarker = new CrossPointMarker(wasmContext, {
285
- width: pointRadius,
286
- height: pointRadius,
287
- strokeThickness: 2,
288
- fill: convertColor(dataset.color, '#FF6600'),
289
- stroke: '#000000'
290
- })
291
- break
292
- case 'crossRot':
293
- pointMarker = new XPointMarker(wasmContext, {
294
- width: pointRadius,
295
- height: pointRadius,
296
- strokeThickness: 2,
297
- fill: convertColor(dataset.color, '#FF6600'),
298
- stroke: '#000000'
299
- })
300
- break
301
- default:
302
- pointMarker = new EllipsePointMarker(wasmContext, {
303
- width: pointRadius,
304
- height: pointRadius,
305
- strokeThickness: 2,
306
- fill: convertColor(dataset.color, '#FF6600'),
307
- stroke: '#000000'
308
- })
309
- }
310
- }
311
-
312
- if (stacked) {
313
- series = new StackedMountainRenderableSeries(wasmContext, {
314
- dataSeries,
315
- strokeThickness: dataset.borderWidth || 2,
316
- stroke: convertColor(dataset.color, '#FF6600'),
317
- fill: dataset.backgroundColor || '#FF6600',
318
- yAxisId,
319
- stackedGroupId: stackGroupId
320
- })
321
- } else {
322
- series =
323
- !!lineTension && lineTension > 0
324
- ? new SplineLineRenderableSeries(wasmContext, {
325
- dataSeries,
326
- strokeThickness: dataset.borderWidth || 2,
327
- stroke: convertColor(dataset.color, '#FF6600'),
328
- pointMarker,
329
- animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
330
- yAxisId
331
- })
332
- : new FastLineRenderableSeries(wasmContext, {
333
- dataSeries,
334
- strokeThickness: dataset.borderWidth || 2,
335
- stroke: convertColor(dataset.color, '#FF6600'),
336
- pointMarker,
337
- animation: animation && new WaveAnimation({ duration: 1000, fadeEffect: true }),
338
- yAxisId
339
- })
340
- }
341
- }
342
-
343
- sciChartSurface.renderableSeries.add(series)
344
-
345
- if (tooltip) {
346
- const rolloverModifier = new RolloverModifier({
347
- showTooltip: true,
348
- showAxisLabel: false /* 한글의 크기를 잘 계산하지 못하므로 false */,
349
- tooltipColor: 'white',
350
- tooltipBackgroundColor: 'rgba(0, 0, 0, 0.7)',
351
- rollOverDataSeries: dataSeries
352
- })
353
-
354
- sciChartSurface.chartModifiers.add(rolloverModifier)
355
- }
356
-
357
- return dataSeries
358
- })
359
-
360
- // Stacked collections 추가
361
- if (stacked) {
362
- const stackedColumnCollection = new StackedColumnCollection(wasmContext)
363
- const stackedMountainCollection = new StackedMountainCollection(wasmContext)
364
-
365
- sciChartSurface.renderableSeries.asArray().forEach((series: any) => {
366
- if (series instanceof StackedColumnRenderableSeries) {
367
- stackedColumnCollection.add(series)
368
- } else if (series instanceof StackedMountainRenderableSeries) {
369
- stackedMountainCollection.add(series)
370
- }
371
- })
372
-
373
- if (stackedColumnCollection.size() > 0) {
374
- sciChartSurface.renderableSeries.add(stackedColumnCollection)
375
- }
376
-
377
- if (stackedMountainCollection.size() > 0) {
378
- sciChartSurface.renderableSeries.add(stackedMountainCollection)
379
- }
380
- }
381
-
382
- if (annotations) {
383
- annotations.forEach(annotation => {
384
- let sciAnnotation
385
- let horizontalAnchorPoint =
386
- annotation.horizontalAnchorPoint == 'Right'
387
- ? EHorizontalAnchorPoint.Right
388
- : annotation.horizontalAnchorPoint == 'Left'
389
- ? EHorizontalAnchorPoint.Left
390
- : EHorizontalAnchorPoint.Center
391
- let verticalAnchorPoint =
392
- annotation.verticalAnchorPoint == 'Top'
393
- ? EVerticalAnchorPoint.Top
394
- : annotation.verticalAnchorPoint == 'Bottom'
395
- ? EVerticalAnchorPoint.Bottom
396
- : EVerticalAnchorPoint.Center
397
-
398
- switch (annotation.type) {
399
- case 'text':
400
- sciAnnotation = new TextAnnotation({
401
- x1: annotation.x1,
402
- y1: annotation.y1,
403
- text: annotation.text,
404
- horizontalAnchorPoint,
405
- verticalAnchorPoint,
406
- fontSize: annotation.fontSize,
407
- fontFamily: annotation.fontFamily,
408
- textColor: convertColor(annotation.stroke, fontColor),
409
- xCoordinateMode: annotation.xCoordinateMode || ECoordinateMode.DataValue,
410
- yCoordinateMode: annotation.yCoordinateMode || ECoordinateMode.DataValue
411
- })
412
- break
413
- case 'line':
414
- sciAnnotation = new LineAnnotation({
415
- x1: annotation.x1,
416
- y1: annotation.y1,
417
- x2: annotation.x2,
418
- y2: annotation.y2,
419
- stroke: convertColor(annotation.stroke, '#FF0000'),
420
- strokeThickness: annotation.strokeThickness,
421
- xCoordinateMode: annotation.xCoordinateMode || ECoordinateMode.DataValue,
422
- yCoordinateMode: annotation.yCoordinateMode || ECoordinateMode.DataValue
423
- })
424
- break
425
- case 'box':
426
- sciAnnotation = new BoxAnnotation({
427
- x1: annotation.x1,
428
- y1: annotation.y1,
429
- x2: annotation.x2,
430
- y2: annotation.y2,
431
- fill: convertColor(annotation.fill, '#FF0000'),
432
- stroke: convertColor(annotation.stroke, '#FF0000'),
433
- strokeThickness: annotation.strokeThickness,
434
- xCoordinateMode: annotation.xCoordinateMode || ECoordinateMode.DataValue,
435
- yCoordinateMode: annotation.yCoordinateMode || ECoordinateMode.DataValue
436
- })
437
- break
438
- case 'horizontalLine':
439
- sciAnnotation = new HorizontalLineAnnotation({
440
- y1: annotation.y1,
441
- stroke: convertColor(annotation.stroke, '#FF0000'),
442
- strokeThickness: annotation.strokeThickness,
443
- xCoordinateMode: annotation.xCoordinateMode || ECoordinateMode.DataValue,
444
- yCoordinateMode: annotation.yCoordinateMode || ECoordinateMode.DataValue
445
- })
446
- break
447
- case 'verticalLine':
448
- sciAnnotation = new VerticalLineAnnotation({
449
- x1: annotation.x1,
450
- stroke: convertColor(annotation.stroke, '#FF0000'),
451
- strokeThickness: annotation.strokeThickness,
452
- xCoordinateMode: annotation.xCoordinateMode || ECoordinateMode.DataValue,
453
- yCoordinateMode: annotation.yCoordinateMode || ECoordinateMode.DataValue
454
- })
455
- break
456
- default:
457
- console.error('Unknown annotation type:', annotation.type)
458
- break
459
- }
460
- if (sciAnnotation) {
461
- sciChartSurface.annotations.add(sciAnnotation)
462
- } else {
463
- console.error('Failed to create annotation:', annotation)
464
- }
465
- })
466
- }
467
-
468
- // 줌인/줌아웃 모디파이어 추가
469
- sciChartSurface.chartModifiers.add(
470
- // new RubberBandXyZoomModifier(),
471
- new ZoomPanModifier(),
472
- new MouseWheelZoomModifier(),
473
- new ZoomExtentsModifier(),
474
- new XAxisDragModifier(),
475
- new YAxisDragModifier()
476
- )
477
-
478
- // Legend 설정
479
- if (legend?.display) {
480
- const legendModifier = new LegendModifier({
481
- showCheckboxes: true,
482
- showSeriesMarkers: true,
483
- showLegend: true,
484
- placement: legend.position || 'bottom-right'
485
- })
486
- sciChartSurface.chartModifiers.add(legendModifier)
487
- }
488
-
489
- return { chart, dataSeries: dataSeriesArray }
490
- }
package/stories/common.ts DELETED
@@ -1,87 +0,0 @@
1
- export function getDefaultChartConfig(
2
- type: OperatoChart.ChartType,
3
- datasets?: OperatoChart.Dataset[]
4
- ): OperatoChart.ChartConfig {
5
- return {
6
- data: {
7
- datasets: datasets || [],
8
- labelDataKey: ''
9
- },
10
- options: {
11
- theme: 'light',
12
- tooltip: true,
13
- animation: true,
14
- legend: {
15
- display: true,
16
- position: 'top'
17
- },
18
- scales: {
19
- xAxes: [getDefaultAxisOptions()],
20
- yAxes: [getDefaultAxisOptions(), getDefaultAxisOptions()] // Two y-axes for multi-axis support
21
- },
22
- stacked: false,
23
- xGridLine: true,
24
- yGridLine: true,
25
- y2ndGridLine: false,
26
- multiAxis: false
27
- },
28
- type
29
- }
30
- }
31
-
32
- export function getDefaultAxisOptions(): OperatoChart.AxisOptions {
33
- return {
34
- axisTitle: '',
35
- barSpacing: 0,
36
- categorySpacing: 0,
37
- barPercentage: 0.9,
38
- ticks: {
39
- display: true,
40
- autoMin: true,
41
- autoMax: true,
42
- min: undefined,
43
- max: undefined,
44
- stepSize: undefined
45
- }
46
- }
47
- }
48
-
49
- // export const data = [
50
- // { timestamp: 2010, count: 10, average: 120 },
51
- // { timestamp: 2011, count: 20, average: 110 },
52
- // { timestamp: 2012, count: 15, average: 80 },
53
- // { timestamp: 2013, count: 25, average: 130 },
54
- // { timestamp: 2014, count: 22, average: 120 },
55
- // { timestamp: 2015, count: 30, average: 60 },
56
- // { timestamp: 2016, count: 28, average: 90 }
57
- // ]
58
- // 랜덤한 범위의 숫자를 생성하는 함수
59
- function getRandomInRange(i: number, min: number, max: number) {
60
- if (!(i % 11)) {
61
- return null
62
- }
63
- return Math.floor(Math.random() * (max - min + 1)) + min
64
- }
65
-
66
- // 랜덤 데이터를 생성하는 함수
67
- function generateRandomData(count: number) {
68
- const randomData = []
69
- const startTimestamp = Math.floor(Date.now()) // 현재 시간을 Unix 타임스탬프로 설정
70
-
71
- for (let i = 0; i < count; i++) {
72
- const timestamp = startTimestamp + i * 360 * 30 * 1000 // 3초씩 증가하는 타임스탬프 설정
73
- const randomCount = getRandomInRange(i, 5, 35) // count 값을 5에서 35 사이로 랜덤 생성
74
- const randomAverage = getRandomInRange(i, 50, 150) // average 값을 50에서 150 사이로 랜덤 생성
75
-
76
- randomData.push({
77
- timestamp: timestamp,
78
- count: randomCount,
79
- average: randomAverage
80
- })
81
- }
82
-
83
- return randomData
84
- }
85
-
86
- // 100개의 랜덤 데이터를 생성
87
- export const data = generateRandomData(100)