@operato/scene-scichart 7.0.5 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/db.sqlite +0 -0
  3. package/dist/charts/axis-synchronizer.d.ts +10 -0
  4. package/dist/charts/axis-synchronizer.js +32 -0
  5. package/dist/charts/axis-synchronizer.js.map +1 -0
  6. package/dist/charts/ox-scichart-multiple.d.ts +40 -0
  7. package/dist/charts/ox-scichart-multiple.js +272 -0
  8. package/dist/charts/ox-scichart-multiple.js.map +1 -0
  9. package/dist/charts/ox-scichart.d.ts +1 -1
  10. package/dist/charts/ox-scichart.js.map +1 -1
  11. package/dist/charts/scichart-builder.d.ts +10 -1
  12. package/dist/charts/scichart-builder.js +154 -12
  13. package/dist/charts/scichart-builder.js.map +1 -1
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +1 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/scichart-multiple-timeseries.d.ts +14 -0
  18. package/dist/scichart-multiple-timeseries.js +60 -0
  19. package/dist/scichart-multiple-timeseries.js.map +1 -0
  20. package/dist/scichart-timeseries.d.ts +2 -11
  21. package/dist/scichart-timeseries.js +2 -42
  22. package/dist/scichart-timeseries.js.map +1 -1
  23. package/dist/templates/index.d.ts +2 -19
  24. package/dist/templates/index.js +2 -1
  25. package/dist/templates/index.js.map +1 -1
  26. package/dist/templates/scichart-multiple-timeseries.d.ts +53 -0
  27. package/dist/templates/scichart-multiple-timeseries.js +81 -0
  28. package/dist/templates/scichart-multiple-timeseries.js.map +1 -0
  29. package/dist/templates/scichart-timeseries.d.ts +2 -19
  30. package/dist/templates/scichart-timeseries.js +2 -19
  31. package/dist/templates/scichart-timeseries.js.map +1 -1
  32. package/helps/scene/component/scichart-multiple-timeseries.md +23 -0
  33. package/helps/scene/component/scichart-timeseries.md +18 -0
  34. package/icons/scichart-multiple-timeseries.png +0 -0
  35. package/logs/.08636eb59927f12972f6774f5947c8507b3564c2-audit.json +9 -9
  36. package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +24 -9
  37. package/logs/{application-2024-07-08-22.log → application-2024-07-28-03.log} +9 -9
  38. package/logs/{application-2024-07-08-23.log → application-2024-07-28-17.log} +140 -43
  39. package/logs/{application-2024-07-09-15.log → application-2024-07-28-18.log} +18 -18
  40. package/logs/connections-2024-07-23-14.log +50 -0
  41. package/logs/connections-2024-07-25-23.log +50 -0
  42. package/logs/connections-2024-07-26-18.log +50 -0
  43. package/logs/connections-2024-07-28-03.log +50 -0
  44. package/logs/connections-2024-07-28-17.log +200 -0
  45. package/logs/connections-2024-07-28-18.log +100 -0
  46. package/package.json +2 -2
  47. package/schema.graphql +211 -0
  48. package/src/charts/axis-synchronizer.ts +37 -0
  49. package/src/charts/ox-scichart-multiple.ts +334 -0
  50. package/src/charts/ox-scichart.ts +1 -1
  51. package/src/charts/scichart-builder.ts +197 -11
  52. package/src/index.ts +1 -0
  53. package/src/scichart-multiple-timeseries.ts +74 -0
  54. package/src/scichart-timeseries.ts +3 -54
  55. package/src/templates/index.ts +2 -1
  56. package/src/templates/scichart-multiple-timeseries.ts +87 -0
  57. package/src/templates/scichart-timeseries.ts +2 -19
  58. package/things-scene.config.js +0 -2
  59. package/translations/en.json +3 -1
  60. package/translations/ja.json +3 -1
  61. package/translations/ko.json +3 -1
  62. package/translations/ms.json +3 -1
  63. package/translations/zh.json +3 -1
  64. package/tsconfig.tsbuildinfo +1 -1
  65. package/cache/translations/system/en.json +0 -1
  66. package/cache/translations/system/ko.json +0 -1
  67. package/logs/connections-2024-07-08-22.log +0 -50
  68. package/logs/connections-2024-07-08-23.log +0 -100
  69. package/logs/connections-2024-07-09-15.log +0 -100
@@ -0,0 +1,334 @@
1
+ import { LitElement, html, css } from 'lit'
2
+ import { property, query, customElement } from 'lit/decorators.js'
3
+ import { keyed } from 'lit/directives/keyed.js'
4
+
5
+ import { buildSciChart, buildSciChartOverview } from './scichart-builder'
6
+ import { AxisSynchroniser } from './axis-synchronizer'
7
+ import { NumberRange, SciChartVerticalGroup } from 'scichart'
8
+
9
+ import { ScrollbarStyles } from '@operato/styles'
10
+
11
+ @customElement('ox-scichart-multiple')
12
+ export class OxSciChartMultiple extends LitElement {
13
+ @property({ type: Object }) config: OperatoChart.ChartConfig | null = null
14
+ @property({ type: Array }) data: { [attr: string]: any }[] = []
15
+ @property({ type: Array }) visibleSeries: string[] = []
16
+ @property({ type: Boolean, attribute: 'show-overview' }) showOverview: boolean = true
17
+
18
+ private synchronizer: AxisSynchroniser = new AxisSynchroniser(new NumberRange(200, 500))
19
+ private verticalGroup: SciChartVerticalGroup = new SciChartVerticalGroup()
20
+
21
+ private isInitializing: boolean = false
22
+ private overviewChart: any = null
23
+ private overviewDataSeries: any[] = []
24
+ private groupCharts: {
25
+ dataKey: string
26
+ sciChartSurface: any
27
+ dataSeries: any[]
28
+ }[] = []
29
+
30
+ /*
31
+ [주의]
32
+ ox-scichart container의 id를 글로벌 유니크하게 해야한다.
33
+ SciChart가 특별히 container의 id를 기반으로 하위 컴포넌트를 구성하고 있기 때문이다.
34
+ shadowDom 안에 있는 container 이더라도, 글로벌 유니크한 id를 제공해야 한다.
35
+ 그렇지 않으면, 단 하나의 차트만 제대로 렌더링된다.
36
+ */
37
+ private containerId: string = 'ox-scichart-multiple' + ++OxSciChartMultiple.idx
38
+
39
+ @query('.overview') overviewContainer!: HTMLDivElement
40
+
41
+ static idx: number = 0
42
+
43
+ static styles = [
44
+ ScrollbarStyles,
45
+ css`
46
+ :host {
47
+ display: flex;
48
+ flex-direction: column;
49
+
50
+ width: 100%;
51
+ height: 100%;
52
+ }
53
+
54
+ .overview {
55
+ height: 80px;
56
+ }
57
+
58
+ #chart-group {
59
+ flex: 1;
60
+
61
+ display: flex;
62
+ flex-direction: column;
63
+ overflow-y: auto;
64
+ }
65
+
66
+ .grouped-chart {
67
+ flex: 1;
68
+
69
+ min-height: 25%;
70
+ }
71
+
72
+ [hidden] {
73
+ display: none;
74
+ }
75
+ `
76
+ ]
77
+
78
+ async initializeSciChart() {
79
+ this.cleanup()
80
+
81
+ const { chart, dataSeries } =
82
+ (await buildSciChartOverview(this.config, this.overviewContainer, {}, this.synchronizer)) || {}
83
+
84
+ this.verticalGroup.addSurfaceToGroup(chart.sciChartSurface)
85
+
86
+ this.overviewChart = chart
87
+ this.overviewDataSeries = dataSeries!
88
+ }
89
+
90
+ async updated(changedProperties: Map<string | number | symbol, unknown>) {
91
+ var needDataUpdate = false
92
+
93
+ if (changedProperties.has('config') && this.config) {
94
+ this.isInitializing = true
95
+ await this.initializeSciChart()
96
+ this.isInitializing = false
97
+ needDataUpdate = true
98
+ }
99
+
100
+ if (changedProperties.has('visibleSeries')) {
101
+ if (this.isInitializing) {
102
+ await this.ensureInitialization()
103
+ }
104
+ await this.updateSeries(this.visibleSeries, changedProperties.get('visibleSeries') as string[])
105
+ needDataUpdate = true
106
+ }
107
+
108
+ if (changedProperties.has('data')) {
109
+ needDataUpdate = true
110
+ }
111
+
112
+ if (needDataUpdate) {
113
+ await this.updateDataSeries()
114
+ }
115
+ }
116
+
117
+ private async ensureInitialization() {
118
+ while (this.isInitializing) {
119
+ await new Promise(resolve => setTimeout(resolve, 100)) // Check every 100ms
120
+ }
121
+ }
122
+
123
+ cleanup() {
124
+ this.cleanupGroup()
125
+
126
+ if (this.overviewChart) {
127
+ this.overviewChart.sciChartSurface?.delete()
128
+ this.overviewChart = null
129
+ }
130
+ }
131
+
132
+ cleanupGroup() {
133
+ this.groupCharts.forEach(chart => {
134
+ if (chart.sciChartSurface) {
135
+ this.synchronizer.removeAxis(chart.sciChartSurface.xAxes.get(0))
136
+ this.verticalGroup.removeSurface(chart.sciChartSurface)
137
+ chart.sciChartSurface.delete()
138
+ }
139
+ })
140
+
141
+ this.groupCharts.length = 0
142
+ }
143
+
144
+ async updateDataSeries() {
145
+ const { config, data } = this
146
+ const { datasets = [], labelDataKey: attrX } = config?.data || {}
147
+
148
+ if (!(data instanceof Array) || !attrX) {
149
+ return []
150
+ }
151
+
152
+ const newData = this.dataSet
153
+
154
+ ;(this.groupCharts || []).forEach(({ dataKey, sciChartSurface, dataSeries }) => {
155
+ dataSeries.forEach(ds => ds.clear())
156
+ const dataSet = newData.filter((data, index) => dataKey == datasets[index].dataKey!)
157
+
158
+ dataSet.forEach((data, index) => {
159
+ dataSeries[index].appendRange(
160
+ data.map(d => d.xValue),
161
+ data.map(d => d.yValue)
162
+ )
163
+ })
164
+
165
+ sciChartSurface.zoomExtents()
166
+ sciChartSurface.invalidateElement()
167
+ })
168
+
169
+ this.overviewDataSeries.forEach(ds => ds.clear())
170
+
171
+ newData.forEach((data, index) => {
172
+ if (this.visibleSeries.includes(datasets[index].dataKey!)) {
173
+ this.overviewDataSeries[index].appendRange(
174
+ data.map(d => d.xValue),
175
+ data.map(d => d.yValue)
176
+ )
177
+ }
178
+ })
179
+
180
+ this.overviewChart?.sciChartSurface.zoomExtents()
181
+ this.overviewChart?.sciChartSurface.invalidateElement()
182
+ }
183
+
184
+ get dataSet(): { xValue: number; yValue: number }[][] {
185
+ const { config, data } = this
186
+ const { datasets = [], labelDataKey: attrX } = config?.data || {}
187
+
188
+ if (!(data instanceof Array) || !attrX) {
189
+ return []
190
+ }
191
+
192
+ return datasets.map(dataset => {
193
+ return data
194
+ .map(item => {
195
+ if (!item || typeof item !== 'object') {
196
+ return
197
+ }
198
+
199
+ const xValue = new Date(item[attrX])
200
+ if (isNaN(xValue.getTime())) {
201
+ console.error('Invalid date:', item[attrX])
202
+ return
203
+ }
204
+
205
+ return {
206
+ xValue: xValue.getTime() / 1000,
207
+ yValue: item[dataset.dataKey!]
208
+ }
209
+ })
210
+ .filter(Boolean) as { xValue: number; yValue: number }[]
211
+ })
212
+ }
213
+
214
+ render() {
215
+ const { datasets = [] } = this.config?.data || {}
216
+
217
+ return html`
218
+ <div id=${this.containerId + '-overview'} class="overview" ?hidden=${!this.showOverview}></div>
219
+ <div id="chart-group">
220
+ ${datasets.map(({ dataKey }) =>
221
+ keyed(
222
+ dataKey,
223
+ html`
224
+ <div
225
+ id=${this.containerId + '-' + dataKey}
226
+ class="grouped-chart"
227
+ ?hidden=${!this.visibleSeries.includes(dataKey!)}
228
+ ></div>
229
+ `
230
+ )
231
+ )}
232
+ </div>
233
+ `
234
+ }
235
+
236
+ async buildChartGroup() {
237
+ this.cleanupGroup()
238
+
239
+ const { config } = this
240
+ const { datasets = [] } = config?.data || {}
241
+
242
+ await Promise.all(
243
+ datasets
244
+ .filter(dataset => this.visibleSeries.includes(dataset.dataKey!))
245
+ .map(async dataset => {
246
+ await this.addChart(dataset.dataKey!)
247
+ })
248
+ )
249
+ }
250
+
251
+ async updateSeries(after: string[], before: string[]) {
252
+ /* 기존 시리즈와 새로운 시리즈의 차이를 비교해서, before에는 있는데, after에는 없으면 await removeChart(string)를 호출하고, after에는 있는데, before에는 없으면, addChart(string) 한다. */
253
+ // before에는 있는데 after에는 없는 시리즈를 제거합니다.
254
+ for (const series of before || []) {
255
+ if (!after.includes(series)) {
256
+ await this.removeChart(series)
257
+ }
258
+ }
259
+
260
+ // after에는 있는데 before에는 없는 시리즈를 추가합니다.
261
+ for (const series of after || []) {
262
+ if (!before || !before.includes(series)) {
263
+ await this.addChart(series)
264
+ }
265
+ }
266
+ }
267
+
268
+ async addChart(dataKey: string) {
269
+ const groupedChart = {
270
+ dataKey: '',
271
+ sciChartSurface: undefined,
272
+ dataSeries: [] as any[]
273
+ }
274
+
275
+ const { data } = this
276
+ const { datasets = [] } = this.config?.data || {}
277
+
278
+ const config = {
279
+ ...this.config,
280
+ data: {
281
+ ...data,
282
+ datasets: datasets.filter(dataset => dataset.dataKey == dataKey)
283
+ }
284
+ }
285
+
286
+ const container = this.renderRoot.querySelector(`#${this.containerId + '-' + dataKey}`)
287
+ var { chart, dataSeries } = (await buildSciChart(
288
+ config,
289
+ container,
290
+ { fontSize: undefined, fontFamily: undefined, fontColor: undefined },
291
+ this.containerId
292
+ ))!
293
+
294
+ this.verticalGroup.addSurfaceToGroup(chart.sciChartSurface)
295
+ this.synchronizer.addAxis(chart.sciChartSurface.xAxes.get(0))
296
+
297
+ groupedChart.dataKey = config.data.datasets[0]!.dataKey!
298
+ groupedChart.sciChartSurface = chart.sciChartSurface
299
+ groupedChart.dataSeries = dataSeries
300
+
301
+ this.groupCharts = this.groupSorter([...this.groupCharts, groupedChart])
302
+ }
303
+
304
+ removeChart(dataKey: string) {
305
+ const index = this.groupCharts.findIndex((chart: any) => chart.dataKey == dataKey)
306
+ const [groupedChart] = this.groupCharts.splice(index, 1)
307
+
308
+ if (!groupedChart) {
309
+ return
310
+ }
311
+
312
+ this.verticalGroup.removeSurface(groupedChart.sciChartSurface)
313
+ this.synchronizer.removeAxis(groupedChart.sciChartSurface.xAxes.get(0))
314
+
315
+ groupedChart.sciChartSurface.delete()
316
+ groupedChart.sciChartSurface = undefined
317
+
318
+ this.groupCharts = this.groupSorter(this.groupCharts)
319
+ }
320
+
321
+ groupSorter(group: any[]) {
322
+ return group.sort(
323
+ (a, b) =>
324
+ this.visibleSeries.findIndex((s: any) => s.dataKey == a.dataKey) -
325
+ this.visibleSeries.findIndex((s: any) => s.dataKey == b.dataKey)
326
+ )
327
+ }
328
+ }
329
+
330
+ declare global {
331
+ interface HTMLElementTagNameMap {
332
+ 'ox-scichart-multiple': OxSciChartMultiple
333
+ }
334
+ }
@@ -7,7 +7,7 @@ export class OxSciChart extends LitElement {
7
7
  @property({ type: Object }) config: OperatoChart.ChartConfig | null = null
8
8
  @property({ type: Array }) data: { [attr: string]: any }[] = []
9
9
 
10
- private chart: any = null
10
+ public chart: any = null
11
11
  private dataSeries: any[] = []
12
12
  /*
13
13
  [주의]
@@ -1,5 +1,4 @@
1
1
  import { TinyColor } from '@ctrl/tinycolor'
2
- import { format as formatText } from '@operato/utils/format.js'
3
2
  import {
4
3
  SciChartSurface,
5
4
  SciChartJSLightTheme,
@@ -16,6 +15,10 @@ import {
16
15
  DateTimeNumericAxis,
17
16
  EAutoRange,
18
17
  EAxisAlignment,
18
+ EExecuteOn,
19
+ ECoordinateMode,
20
+ EHorizontalAnchorPoint,
21
+ EVerticalAnchorPoint,
19
22
  NumberRange,
20
23
  MouseWheelZoomModifier,
21
24
  RubberBandXyZoomModifier,
@@ -33,8 +36,16 @@ import {
33
36
  ELegendPlacement,
34
37
  EXyDirection,
35
38
  XAxisDragModifier,
36
- YAxisDragModifier
39
+ YAxisDragModifier,
40
+ TextAnnotation,
41
+ LineAnnotation,
42
+ BoxAnnotation,
43
+ HorizontalLineAnnotation,
44
+ VerticalLineAnnotation,
45
+ OverviewRangeSelectionModifier,
46
+ ENumericFormat
37
47
  } from 'scichart'
48
+ import { AxisSynchroniser } from './axis-synchronizer'
38
49
 
39
50
  SciChartSurface.UseCommunityLicense()
40
51
 
@@ -49,6 +60,11 @@ const POINT_MARKER_SIZE = 10
49
60
  const STROKE_THICKNESS = 2
50
61
  const ANIMATION_DURATION = 1000
51
62
 
63
+ function getLocalTimeOffset() {
64
+ const now = new Date()
65
+ return now.getTimezoneOffset() * -60
66
+ }
67
+
52
68
  function getBaseColorFromTheme(theme?: 'light' | 'dark' | 'auto') {
53
69
  return new TinyColor(theme == 'dark' ? '#fff' : '#000')
54
70
  }
@@ -98,7 +114,8 @@ function createAxis(
98
114
  isXAxis: boolean,
99
115
  fontColor: string,
100
116
  fontFamily?: string,
101
- fontSize?: number
117
+ fontSize?: number,
118
+ options?: any
102
119
  ) {
103
120
  const { axisTitle, ticks } = axis
104
121
  const {
@@ -128,11 +145,24 @@ function createAxis(
128
145
  fontFamily,
129
146
  fontSize,
130
147
  color: textStrokeColor
131
- }
148
+ },
149
+ ...options
132
150
  }
133
151
 
152
+ const labelProvider = new SmartDateLabelProvider({
153
+ labelFormat: ENumericFormat.Date_HHMMSS,
154
+ showWiderDateOnFirstLabel: true,
155
+ showYearOnWiderDate: true,
156
+ dateOffset: getLocalTimeOffset()
157
+ })
158
+
159
+ labelProvider.cursorNumericFormat = ENumericFormat.Date_DDMMHHMM
160
+
134
161
  return isXAxis
135
- ? new DateTimeNumericAxis(wasmContext, { ...axisOptions, labelProvider: new SmartDateLabelProvider() })
162
+ ? new DateTimeNumericAxis(wasmContext, {
163
+ ...axisOptions,
164
+ labelProvider
165
+ })
136
166
  : new NumericAxis(wasmContext, { ...axisOptions, id: index !== 0 ? `yAxis${index}` : undefined })
137
167
  }
138
168
 
@@ -204,7 +234,8 @@ function createSeries(
204
234
  export async function buildSciChart(
205
235
  config: OperatoChart.ChartConfig | undefined | null,
206
236
  container: any,
207
- { fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string }
237
+ { fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string },
238
+ grouped?: string
208
239
  ): Promise<{ chart: any; dataSeries: any[] } | undefined> {
209
240
  if (!config) return
210
241
 
@@ -219,7 +250,9 @@ export async function buildSciChart(
219
250
  xGridLine,
220
251
  yGridLine,
221
252
  y2ndGridLine,
222
- stacked
253
+ stacked,
254
+ multiAxis,
255
+ annotations
223
256
  } = options || {}
224
257
 
225
258
  var baseColor = getBaseColorFromTheme(theme)
@@ -244,14 +277,14 @@ export async function buildSciChart(
244
277
  })
245
278
 
246
279
  // Y 축 설정
247
- yAxes.forEach((axis, index) => {
280
+ ;(multiAxis ? yAxes : [yAxes[0]]).forEach((axis, index) => {
248
281
  const yAxis = createAxis(wasmContext, axis, index, false, fontColor, fontFamily, fontSize)
249
282
  sciChartSurface.yAxes.add(yAxis)
250
283
  })
251
284
 
252
285
  // 시리즈 설정
253
286
  const dataSeriesArray = datasets.map((dataset, index) => {
254
- const yAxisId = dataset.yAxisID == 'right' ? 'yAxis1' : undefined
287
+ const yAxisId = dataset.yAxisID == 'right' && multiAxis ? 'yAxis1' : undefined
255
288
  const { series, dataSeries } = createSeries(wasmContext, dataset, index, !!stacked, !!animation, yAxisId)
256
289
 
257
290
  sciChartSurface.renderableSeries.add(series)
@@ -259,7 +292,8 @@ export async function buildSciChart(
259
292
  if (tooltip) {
260
293
  const rolloverModifier = new RolloverModifier({
261
294
  showTooltip: true,
262
- showAxisLabel: true
295
+ showAxisLabel: true,
296
+ modifierGroup: grouped
263
297
  })
264
298
 
265
299
  sciChartSurface.chartModifiers.add(rolloverModifier)
@@ -290,9 +324,84 @@ export async function buildSciChart(
290
324
  }
291
325
  }
292
326
 
327
+ if (annotations) {
328
+ annotations.forEach(annotation => {
329
+ let sciAnnotation: any
330
+ let horizontalAnchorPoint: EHorizontalAnchorPoint =
331
+ annotation.horizontalAnchorPoint == 'Right'
332
+ ? EHorizontalAnchorPoint.Right
333
+ : annotation.horizontalAnchorPoint == 'Left'
334
+ ? EHorizontalAnchorPoint.Left
335
+ : EHorizontalAnchorPoint.Center
336
+ let verticalAnchorPoint: EVerticalAnchorPoint =
337
+ annotation.verticalAnchorPoint == 'Top'
338
+ ? EVerticalAnchorPoint.Top
339
+ : annotation.verticalAnchorPoint == 'Bottom'
340
+ ? EVerticalAnchorPoint.Bottom
341
+ : EVerticalAnchorPoint.Center
342
+
343
+ switch (annotation.type) {
344
+ case 'text':
345
+ sciAnnotation = new TextAnnotation({
346
+ x1: annotation.x1,
347
+ y1: annotation.y1,
348
+ text: annotation.text,
349
+ horizontalAnchorPoint,
350
+ verticalAnchorPoint,
351
+ fontSize: annotation.fontSize,
352
+ fontFamily: annotation.fontFamily,
353
+ textColor: convertColor(annotation.stroke, fontColor)
354
+ })
355
+ break
356
+ case 'line':
357
+ sciAnnotation = new LineAnnotation({
358
+ x1: annotation.x1,
359
+ y1: annotation.y1,
360
+ x2: annotation.x2,
361
+ y2: annotation.y2,
362
+ stroke: convertColor(annotation.stroke, '#FF0000'),
363
+ strokeThickness: annotation.strokeThickness,
364
+ xCoordinateMode: ECoordinateMode.Relative,
365
+ yCoordinateMode: ECoordinateMode.DataValue
366
+ })
367
+ break
368
+ case 'box':
369
+ sciAnnotation = new BoxAnnotation({
370
+ x1: annotation.x1,
371
+ y1: annotation.y1,
372
+ x2: annotation.x2,
373
+ y2: annotation.y2,
374
+ fill: convertColor(annotation.fill, '#FF0000'),
375
+ stroke: convertColor(annotation.stroke, '#FF0000'),
376
+ strokeThickness: annotation.strokeThickness
377
+ })
378
+ break
379
+ case 'horizontalLine':
380
+ sciAnnotation = new HorizontalLineAnnotation({
381
+ y1: annotation.y1,
382
+ stroke: convertColor(annotation.stroke, '#FF0000'),
383
+ strokeThickness: annotation.strokeThickness
384
+ })
385
+ break
386
+ case 'verticalLine':
387
+ sciAnnotation = new VerticalLineAnnotation({
388
+ x1: annotation.x1,
389
+ stroke: convertColor(annotation.stroke, '#FF0000'),
390
+ strokeThickness: annotation.strokeThickness
391
+ })
392
+ break
393
+ default:
394
+ break
395
+ }
396
+ if (sciAnnotation) {
397
+ sciChartSurface.annotations.add(sciAnnotation)
398
+ }
399
+ })
400
+ }
401
+
293
402
  // 줌인/줌아웃 모디파이어 추가
294
403
  sciChartSurface.chartModifiers.add(
295
- // new RubberBandXyZoomModifier(),
404
+ new RubberBandXyZoomModifier({ executeOn: EExecuteOn.MouseRightButton, modifierGroup: grouped }),
296
405
  // new ZoomPanModifier({ xyDirection: EXyDirection.XDirection }),
297
406
  new ZoomPanModifier(),
298
407
  new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
@@ -321,3 +430,80 @@ export async function buildSciChart(
321
430
 
322
431
  return { chart, dataSeries: dataSeriesArray }
323
432
  }
433
+
434
+ export async function buildSciChartOverview(
435
+ config: OperatoChart.ChartConfig | undefined | null,
436
+ container: any,
437
+ { fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string },
438
+ axisSynchroniser: AxisSynchroniser
439
+ ): Promise<{ chart: any; dataSeries: any[] } | undefined> {
440
+ if (!config) return
441
+
442
+ const { type: chartType, options, data: fromData } = config
443
+ const { datasets = [] } = fromData || {}
444
+ var { theme, animation, scales: fromScales, stacked, multiAxis } = options || {}
445
+
446
+ var baseColor = getBaseColorFromTheme(theme)
447
+
448
+ if (theme === 'auto') {
449
+ theme = getThemeFromBrowser()
450
+ }
451
+
452
+ fontColor = fontColor || baseColor.clone().toString()
453
+
454
+ const { xAxes = [], yAxes = [] } = fromScales || {}
455
+
456
+ // Instead we create a normal chart and then manually add the OverviewRangeSelectionModifier and bind it to the axisSynchroniser
457
+ const chart = await SciChartSurface.create(container, {
458
+ theme: theme == 'dark' ? new SciChartJSDarkv2Theme() : new SciChartJSLightTheme()
459
+ })
460
+ const { sciChartSurface, wasmContext } = chart
461
+
462
+ // X 축 설정
463
+ xAxes.forEach((axis, index) => {
464
+ const xAxis = createAxis(wasmContext, axis, index, true, fontColor, fontFamily, fontSize)
465
+ sciChartSurface.xAxes.add(xAxis)
466
+ })
467
+
468
+ // Y 축 설정
469
+ ;(multiAxis ? yAxes : [yAxes[0]]).forEach((axis, index) => {
470
+ const yAxis = createAxis(wasmContext, axis, index, false, fontColor, fontFamily, fontSize, {
471
+ drawLabels: false,
472
+ drawMajorTicks: false,
473
+ drawMinorTicks: false,
474
+ drawMajorGridLines: false,
475
+ drawMinorGridLines: false
476
+ })
477
+ sciChartSurface.yAxes.add(yAxis)
478
+ })
479
+
480
+ const rangeSelectionModifier = new OverviewRangeSelectionModifier()
481
+ // When the range selection is moved, updated the linked charts
482
+ rangeSelectionModifier.onSelectedAreaChanged = (selectedRange?: NumberRange) => {
483
+ if (!selectedRange!.equals(axisSynchroniser.visibleRange)) {
484
+ axisSynchroniser.publishChange({ visibleRange: selectedRange! })
485
+ }
486
+ }
487
+
488
+ rangeSelectionModifier.selectedArea = axisSynchroniser.visibleRange
489
+ sciChartSurface.chartModifiers.add(rangeSelectionModifier)
490
+
491
+ // When charts are moved, update the range selection
492
+ axisSynchroniser.visibleRangeChanged.subscribe(({ visibleRange }: any) => {
493
+ const updatedSelectedRange = visibleRange.clip(sciChartSurface.xAxes.get(0).visibleRange)
494
+ const shouldUpdateSelectedRange = !updatedSelectedRange.equals(rangeSelectionModifier.selectedArea)
495
+ if (shouldUpdateSelectedRange) {
496
+ rangeSelectionModifier.selectedArea = updatedSelectedRange
497
+ }
498
+ })
499
+
500
+ const dataSeriesArray = datasets.map((dataset, index) => {
501
+ const yAxisId = dataset.yAxisID == 'right' && multiAxis ? 'yAxis1' : undefined
502
+ const { series, dataSeries } = createSeries(wasmContext, dataset, index, !!stacked, !!animation, yAxisId)
503
+
504
+ sciChartSurface.renderableSeries.add(series)
505
+ return dataSeries
506
+ })
507
+
508
+ return { chart, dataSeries: dataSeriesArray }
509
+ }
package/src/index.ts CHANGED
@@ -1 +1,2 @@
1
1
  export { default as scichartTimeseries } from './scichart-timeseries'
2
+ export { default as scichartMultipleTimeseries } from './scichart-multiple-timeseries'