@operato/scene-scichart 7.0.7 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +9 -0
- package/db.sqlite +0 -0
- package/dist/charts/axis-synchronizer.d.ts +10 -0
- package/dist/charts/axis-synchronizer.js +32 -0
- package/dist/charts/axis-synchronizer.js.map +1 -0
- package/dist/charts/ox-scichart-multiple.d.ts +40 -0
- package/dist/charts/ox-scichart-multiple.js +272 -0
- package/dist/charts/ox-scichart-multiple.js.map +1 -0
- package/dist/charts/ox-scichart.d.ts +1 -1
- package/dist/charts/ox-scichart.js.map +1 -1
- package/dist/charts/scichart-builder.d.ts +10 -1
- package/dist/charts/scichart-builder.js +80 -8
- package/dist/charts/scichart-builder.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/scichart-multiple-timeseries.d.ts +14 -0
- package/dist/scichart-multiple-timeseries.js +60 -0
- package/dist/scichart-multiple-timeseries.js.map +1 -0
- package/dist/scichart-timeseries.d.ts +2 -11
- package/dist/scichart-timeseries.js +2 -42
- package/dist/scichart-timeseries.js.map +1 -1
- package/dist/templates/index.js +2 -1
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/scichart-multiple-timeseries.d.ts +53 -0
- package/dist/templates/scichart-multiple-timeseries.js +81 -0
- package/dist/templates/scichart-multiple-timeseries.js.map +1 -0
- package/helps/scene/component/scichart-multiple-timeseries.md +23 -0
- package/helps/scene/component/scichart-timeseries.md +18 -0
- package/icons/scichart-multiple-timeseries.png +0 -0
- package/logs/.08636eb59927f12972f6774f5947c8507b3564c2-audit.json +11 -6
- package/logs/.5e5d741d8b7784a2fbad65eedc0fd46946aaf6f2-audit.json +18 -23
- package/logs/{application-2024-07-13-21.log → application-2024-07-28-03.log} +8 -8
- package/logs/{application-2024-07-13-20.log → application-2024-07-28-17.log} +32 -36
- package/logs/application-2024-07-28-18.log +210 -0
- package/logs/connections-2024-07-23-14.log +50 -0
- package/logs/connections-2024-07-25-23.log +50 -0
- package/logs/connections-2024-07-26-18.log +50 -0
- package/logs/connections-2024-07-28-03.log +50 -0
- package/logs/connections-2024-07-28-17.log +200 -0
- package/logs/connections-2024-07-28-18.log +100 -0
- package/package.json +2 -2
- package/schema.graphql +112 -0
- package/src/charts/axis-synchronizer.ts +37 -0
- package/src/charts/ox-scichart-multiple.ts +334 -0
- package/src/charts/ox-scichart.ts +1 -1
- package/src/charts/scichart-builder.ts +109 -8
- package/src/index.ts +1 -0
- package/src/scichart-multiple-timeseries.ts +74 -0
- package/src/scichart-timeseries.ts +3 -54
- package/src/templates/index.ts +2 -1
- package/src/templates/scichart-multiple-timeseries.ts +87 -0
- package/things-scene.config.js +0 -2
- package/translations/en.json +3 -1
- package/translations/ja.json +3 -1
- package/translations/ko.json +3 -1
- package/translations/ms.json +3 -1
- package/translations/zh.json +3 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/cache/translations/system/en.json +0 -1
- package/cache/translations/system/ko.json +0 -1
- package/logs/connections-2024-07-08-22.log +0 -50
- package/logs/connections-2024-07-08-23.log +0 -100
- package/logs/connections-2024-07-09-15.log +0 -100
- package/logs/connections-2024-07-10-00.log +0 -50
- package/logs/connections-2024-07-10-10.log +0 -50
- package/logs/connections-2024-07-13-20.log +0 -200
- package/logs/connections-2024-07-13-21.log +0 -50
@@ -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
|
-
|
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,7 @@ import {
|
|
16
15
|
DateTimeNumericAxis,
|
17
16
|
EAutoRange,
|
18
17
|
EAxisAlignment,
|
18
|
+
EExecuteOn,
|
19
19
|
ECoordinateMode,
|
20
20
|
EHorizontalAnchorPoint,
|
21
21
|
EVerticalAnchorPoint,
|
@@ -41,8 +41,11 @@ import {
|
|
41
41
|
LineAnnotation,
|
42
42
|
BoxAnnotation,
|
43
43
|
HorizontalLineAnnotation,
|
44
|
-
VerticalLineAnnotation
|
44
|
+
VerticalLineAnnotation,
|
45
|
+
OverviewRangeSelectionModifier,
|
46
|
+
ENumericFormat
|
45
47
|
} from 'scichart'
|
48
|
+
import { AxisSynchroniser } from './axis-synchronizer'
|
46
49
|
|
47
50
|
SciChartSurface.UseCommunityLicense()
|
48
51
|
|
@@ -57,6 +60,11 @@ const POINT_MARKER_SIZE = 10
|
|
57
60
|
const STROKE_THICKNESS = 2
|
58
61
|
const ANIMATION_DURATION = 1000
|
59
62
|
|
63
|
+
function getLocalTimeOffset() {
|
64
|
+
const now = new Date()
|
65
|
+
return now.getTimezoneOffset() * -60
|
66
|
+
}
|
67
|
+
|
60
68
|
function getBaseColorFromTheme(theme?: 'light' | 'dark' | 'auto') {
|
61
69
|
return new TinyColor(theme == 'dark' ? '#fff' : '#000')
|
62
70
|
}
|
@@ -106,7 +114,8 @@ function createAxis(
|
|
106
114
|
isXAxis: boolean,
|
107
115
|
fontColor: string,
|
108
116
|
fontFamily?: string,
|
109
|
-
fontSize?: number
|
117
|
+
fontSize?: number,
|
118
|
+
options?: any
|
110
119
|
) {
|
111
120
|
const { axisTitle, ticks } = axis
|
112
121
|
const {
|
@@ -136,11 +145,24 @@ function createAxis(
|
|
136
145
|
fontFamily,
|
137
146
|
fontSize,
|
138
147
|
color: textStrokeColor
|
139
|
-
}
|
148
|
+
},
|
149
|
+
...options
|
140
150
|
}
|
141
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
|
+
|
142
161
|
return isXAxis
|
143
|
-
? new DateTimeNumericAxis(wasmContext, {
|
162
|
+
? new DateTimeNumericAxis(wasmContext, {
|
163
|
+
...axisOptions,
|
164
|
+
labelProvider
|
165
|
+
})
|
144
166
|
: new NumericAxis(wasmContext, { ...axisOptions, id: index !== 0 ? `yAxis${index}` : undefined })
|
145
167
|
}
|
146
168
|
|
@@ -212,7 +234,8 @@ function createSeries(
|
|
212
234
|
export async function buildSciChart(
|
213
235
|
config: OperatoChart.ChartConfig | undefined | null,
|
214
236
|
container: any,
|
215
|
-
{ fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string }
|
237
|
+
{ fontSize, fontFamily, fontColor }: { fontSize?: number; fontFamily?: string; fontColor?: string },
|
238
|
+
grouped?: string
|
216
239
|
): Promise<{ chart: any; dataSeries: any[] } | undefined> {
|
217
240
|
if (!config) return
|
218
241
|
|
@@ -269,7 +292,8 @@ export async function buildSciChart(
|
|
269
292
|
if (tooltip) {
|
270
293
|
const rolloverModifier = new RolloverModifier({
|
271
294
|
showTooltip: true,
|
272
|
-
showAxisLabel: true
|
295
|
+
showAxisLabel: true,
|
296
|
+
modifierGroup: grouped
|
273
297
|
})
|
274
298
|
|
275
299
|
sciChartSurface.chartModifiers.add(rolloverModifier)
|
@@ -377,7 +401,7 @@ export async function buildSciChart(
|
|
377
401
|
|
378
402
|
// 줌인/줌아웃 모디파이어 추가
|
379
403
|
sciChartSurface.chartModifiers.add(
|
380
|
-
|
404
|
+
new RubberBandXyZoomModifier({ executeOn: EExecuteOn.MouseRightButton, modifierGroup: grouped }),
|
381
405
|
// new ZoomPanModifier({ xyDirection: EXyDirection.XDirection }),
|
382
406
|
new ZoomPanModifier(),
|
383
407
|
new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
|
@@ -406,3 +430,80 @@ export async function buildSciChart(
|
|
406
430
|
|
407
431
|
return { chart, dataSeries: dataSeriesArray }
|
408
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
@@ -0,0 +1,74 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
3
|
+
*/
|
4
|
+
|
5
|
+
const NATURE: ComponentNature = {
|
6
|
+
mutable: false,
|
7
|
+
resizable: true,
|
8
|
+
rotatable: true,
|
9
|
+
properties: [
|
10
|
+
{
|
11
|
+
type: 'boolean',
|
12
|
+
label: 'show-overview',
|
13
|
+
name: 'showOverview'
|
14
|
+
},
|
15
|
+
{
|
16
|
+
type: 'scichart',
|
17
|
+
label: '',
|
18
|
+
name: 'chart'
|
19
|
+
}
|
20
|
+
],
|
21
|
+
'value-property': 'visibleSeries',
|
22
|
+
help: 'scene/component/scichart-multiple-timeseries'
|
23
|
+
}
|
24
|
+
|
25
|
+
import './charts/ox-scichart-multiple'
|
26
|
+
|
27
|
+
import { Component, HTMLOverlayContainer, Properties, ComponentNature, error } from '@hatiolab/things-scene'
|
28
|
+
|
29
|
+
import { OxSciChartMultiple } from './charts/ox-scichart-multiple'
|
30
|
+
|
31
|
+
export default class ScichartMultipleTimeseries extends HTMLOverlayContainer {
|
32
|
+
static get nature() {
|
33
|
+
return NATURE
|
34
|
+
}
|
35
|
+
|
36
|
+
async oncreate_element(scichart: OxSciChartMultiple) {}
|
37
|
+
|
38
|
+
dispose() {
|
39
|
+
super.dispose()
|
40
|
+
}
|
41
|
+
|
42
|
+
setElementProperties(scichart: OxSciChartMultiple) {
|
43
|
+
const { data, chart, showOverview, visibleSeries } = this.state
|
44
|
+
|
45
|
+
scichart.config = chart
|
46
|
+
scichart.data = data
|
47
|
+
scichart.showOverview = showOverview
|
48
|
+
scichart.visibleSeries = visibleSeries || []
|
49
|
+
}
|
50
|
+
|
51
|
+
reposition() {
|
52
|
+
super.reposition()
|
53
|
+
}
|
54
|
+
|
55
|
+
get tagName() {
|
56
|
+
return 'ox-scichart-multiple'
|
57
|
+
}
|
58
|
+
|
59
|
+
get visibleSeries() {
|
60
|
+
const { visibleSeries } = this.state
|
61
|
+
return visibleSeries || []
|
62
|
+
}
|
63
|
+
|
64
|
+
set visibleSeries(visibleSeries: string[]) {
|
65
|
+
this.setState('visibleSeries', visibleSeries)
|
66
|
+
;(this.element as OxSciChartMultiple).visibleSeries = visibleSeries
|
67
|
+
}
|
68
|
+
|
69
|
+
async onchangeData(after: Properties, before: Properties): Promise<void> {
|
70
|
+
;(this.element as OxSciChartMultiple).data = this.data
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
Component.register('scichart-multiple-timeseries', ScichartMultipleTimeseries)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
3
3
|
*/
|
4
4
|
|
5
|
-
const NATURE = {
|
5
|
+
const NATURE: ComponentNature = {
|
6
6
|
mutable: false,
|
7
7
|
resizable: true,
|
8
8
|
rotatable: true,
|
@@ -12,7 +12,8 @@ const NATURE = {
|
|
12
12
|
label: '',
|
13
13
|
name: 'chart'
|
14
14
|
}
|
15
|
-
]
|
15
|
+
],
|
16
|
+
help: 'scene/component/scichart-timeseries'
|
16
17
|
}
|
17
18
|
|
18
19
|
import './charts/ox-scichart'
|
@@ -43,58 +44,6 @@ export default class ScichartTimeSeries extends HTMLOverlayContainer {
|
|
43
44
|
super.reposition()
|
44
45
|
}
|
45
46
|
|
46
|
-
// get dataSet(): { xValue: number; yValue: number }[] {
|
47
|
-
// var { attrX, attrY, data } = this.state
|
48
|
-
|
49
|
-
// if (!(data instanceof Array)) {
|
50
|
-
// return []
|
51
|
-
// }
|
52
|
-
|
53
|
-
// return data
|
54
|
-
// .map((item, i) => {
|
55
|
-
// if (!item || typeof item !== 'object') {
|
56
|
-
// return
|
57
|
-
// }
|
58
|
-
|
59
|
-
// console.log('Data item:', item) // 데이터 항목을 로그로 출력
|
60
|
-
// const xValue = new Date(item[attrX])
|
61
|
-
// console.log('Parsed Date:', xValue) // 파싱된 날짜를 로그로 출력
|
62
|
-
// if (isNaN(xValue.getTime())) {
|
63
|
-
// console.error('Invalid date:', item[attrX]) // 유효하지 않은 날짜를 로그로 출력
|
64
|
-
// return
|
65
|
-
// }
|
66
|
-
|
67
|
-
// return {
|
68
|
-
// xValue: xValue.getTime() / 1000, // 타임스탬프를 초 단위로 변환
|
69
|
-
// yValue: item[attrY]
|
70
|
-
// }
|
71
|
-
// })
|
72
|
-
// .filter(Boolean) as { xValue: number; yValue: number }[]
|
73
|
-
// }
|
74
|
-
|
75
|
-
// async onchangeData(after: Properties, before: Properties): Promise<void> {
|
76
|
-
// console.log('onchangeData called') // 데이터 변경 시 로그 출력
|
77
|
-
// this.updateDataSeries()
|
78
|
-
// this.surface?.sciChartSurface.zoomExtents()
|
79
|
-
// }
|
80
|
-
|
81
|
-
// updateDataSeries() {
|
82
|
-
// if (!this.dataSeries) return
|
83
|
-
|
84
|
-
// this.dataSeries.clear()
|
85
|
-
// const newData = this.dataSet
|
86
|
-
|
87
|
-
// console.log('Updating data series with:', newData) // 새 데이터 로그 출력
|
88
|
-
|
89
|
-
// this.dataSeries.appendRange(
|
90
|
-
// newData.map(d => d.xValue), // Date 객체를 타임스탬프로 변환
|
91
|
-
// newData.map(d => d.yValue)
|
92
|
-
// )
|
93
|
-
|
94
|
-
// this.surface?.sciChartSurface.zoomExtents() // 데이터 변경 후 영역 조정
|
95
|
-
// this.surface?.sciChartSurface.invalidateElement() // 차트를 다시 그리도록 요청
|
96
|
-
// }
|
97
|
-
|
98
47
|
get tagName() {
|
99
48
|
return 'ox-scichart'
|
100
49
|
}
|
package/src/templates/index.ts
CHANGED