@rm-graph/core 0.1.0
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/README.md +65 -0
- package/dist/chunk-KATRK3C3.js +336 -0
- package/dist/chunk-KATRK3C3.js.map +1 -0
- package/dist/chunk-Q2ZHY445.mjs +328 -0
- package/dist/chunk-Q2ZHY445.mjs.map +1 -0
- package/dist/index-DWzDIVQ9.d.mts +404 -0
- package/dist/index-DWzDIVQ9.d.ts +404 -0
- package/dist/index.d.mts +556 -0
- package/dist/index.d.ts +556 -0
- package/dist/index.js +1655 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1600 -0
- package/dist/index.mjs.map +1 -0
- package/dist/themes/index.d.mts +1 -0
- package/dist/themes/index.d.ts +1 -0
- package/dist/themes/index.js +32 -0
- package/dist/themes/index.js.map +1 -0
- package/dist/themes/index.mjs +3 -0
- package/dist/themes/index.mjs.map +1 -0
- package/package.json +54 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1600 @@
|
|
|
1
|
+
import { ThemeManager, __require } from './chunk-Q2ZHY445.mjs';
|
|
2
|
+
export { ThemeManager, darkTheme, getThemeManager, lightTheme, midnightTheme, modernTheme } from './chunk-Q2ZHY445.mjs';
|
|
3
|
+
import { SciChartSurface, NumericAxis, EAutoRange, NumberRange, RolloverModifier, ZoomPanModifier, MouseWheelZoomModifier, XyDataSeries, FastLineRenderableSeries, EllipsePointMarker, SweepAnimation, FastColumnRenderableSeries, WaveAnimation, GradientParams, Point, FastMountainRenderableSeries, UniformHeatmapDataSeries, UniformHeatmapRenderableSeries, HeatmapColorMap, SciChart3DSurface, NumericAxis3D, MouseWheelZoomModifier3D, OrbitModifier3D, CameraController, Vector3, UniformGridDataSeries3D, GradientColorPalette, SurfaceMeshRenderableSeries3D, EDrawMeshAs, XyzDataSeries3D, ColumnRenderableSeries3D, PointLineRenderableSeries3D, TooltipModifier3D, SciChartJSDarkTheme, SciChartJSLightTheme } from 'scichart';
|
|
4
|
+
export { SciChartSurface } from 'scichart';
|
|
5
|
+
|
|
6
|
+
// src/utils/helpers.ts
|
|
7
|
+
function generateId(prefix = "chart") {
|
|
8
|
+
return `${prefix}-${Math.random().toString(36).substring(2, 11)}`;
|
|
9
|
+
}
|
|
10
|
+
function parseSize(value, fallback) {
|
|
11
|
+
if (value === void 0) return fallback;
|
|
12
|
+
if (typeof value === "number") return value;
|
|
13
|
+
if (value.endsWith("%")) {
|
|
14
|
+
return fallback;
|
|
15
|
+
}
|
|
16
|
+
const parsed = parseInt(value, 10);
|
|
17
|
+
return isNaN(parsed) ? fallback : parsed;
|
|
18
|
+
}
|
|
19
|
+
function normalizeDataPoints(data) {
|
|
20
|
+
if (data.length === 0) return [];
|
|
21
|
+
if (typeof data[0] === "object" && "x" in data[0]) {
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
return data.map((y, index) => ({
|
|
25
|
+
x: index,
|
|
26
|
+
y
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
function extractXValues(data) {
|
|
30
|
+
return data.map((point) => {
|
|
31
|
+
if (typeof point.x === "number") return point.x;
|
|
32
|
+
if (point.x instanceof Date) return point.x.getTime();
|
|
33
|
+
return 0;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function extractYValues(data) {
|
|
37
|
+
return data.map((point) => point.y);
|
|
38
|
+
}
|
|
39
|
+
function deepMerge(target, source) {
|
|
40
|
+
const result = { ...target };
|
|
41
|
+
for (const key in source) {
|
|
42
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
43
|
+
const sourceValue = source[key];
|
|
44
|
+
const targetValue = target[key];
|
|
45
|
+
if (sourceValue !== null && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue !== null && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
46
|
+
result[key] = deepMerge(
|
|
47
|
+
targetValue,
|
|
48
|
+
sourceValue
|
|
49
|
+
);
|
|
50
|
+
} else if (sourceValue !== void 0) {
|
|
51
|
+
result[key] = sourceValue;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
function debounce(fn, delay) {
|
|
58
|
+
let timeoutId = null;
|
|
59
|
+
return (...args) => {
|
|
60
|
+
if (timeoutId) {
|
|
61
|
+
clearTimeout(timeoutId);
|
|
62
|
+
}
|
|
63
|
+
timeoutId = setTimeout(() => {
|
|
64
|
+
fn(...args);
|
|
65
|
+
timeoutId = null;
|
|
66
|
+
}, delay);
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function throttle(fn, limit) {
|
|
70
|
+
let inThrottle = false;
|
|
71
|
+
return (...args) => {
|
|
72
|
+
if (!inThrottle) {
|
|
73
|
+
fn(...args);
|
|
74
|
+
inThrottle = true;
|
|
75
|
+
setTimeout(() => {
|
|
76
|
+
inThrottle = false;
|
|
77
|
+
}, limit);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function calculateDataRange(series) {
|
|
82
|
+
let xMin = Infinity;
|
|
83
|
+
let xMax = -Infinity;
|
|
84
|
+
let yMin = Infinity;
|
|
85
|
+
let yMax = -Infinity;
|
|
86
|
+
for (const s of series) {
|
|
87
|
+
const normalized = normalizeDataPoints(s.data);
|
|
88
|
+
for (const point of normalized) {
|
|
89
|
+
const x = typeof point.x === "number" ? point.x : 0;
|
|
90
|
+
xMin = Math.min(xMin, x);
|
|
91
|
+
xMax = Math.max(xMax, x);
|
|
92
|
+
yMin = Math.min(yMin, point.y);
|
|
93
|
+
yMax = Math.max(yMax, point.y);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
xMin: xMin === Infinity ? 0 : xMin,
|
|
98
|
+
xMax: xMax === -Infinity ? 100 : xMax,
|
|
99
|
+
yMin: yMin === Infinity ? 0 : yMin,
|
|
100
|
+
yMax: yMax === -Infinity ? 100 : yMax
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function formatNumber(value, precision = 2) {
|
|
104
|
+
if (Math.abs(value) >= 1e9) {
|
|
105
|
+
return (value / 1e9).toFixed(precision) + "B";
|
|
106
|
+
}
|
|
107
|
+
if (Math.abs(value) >= 1e6) {
|
|
108
|
+
return (value / 1e6).toFixed(precision) + "M";
|
|
109
|
+
}
|
|
110
|
+
if (Math.abs(value) >= 1e3) {
|
|
111
|
+
return (value / 1e3).toFixed(precision) + "K";
|
|
112
|
+
}
|
|
113
|
+
return value.toFixed(precision);
|
|
114
|
+
}
|
|
115
|
+
function clamp(value, min, max) {
|
|
116
|
+
return Math.min(Math.max(value, min), max);
|
|
117
|
+
}
|
|
118
|
+
function lerp(start, end, t) {
|
|
119
|
+
return start + (end - start) * clamp(t, 0, 1);
|
|
120
|
+
}
|
|
121
|
+
function hexToRgba(hex, alpha = 1) {
|
|
122
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
123
|
+
if (!result) return hex;
|
|
124
|
+
const r = parseInt(result[1], 16);
|
|
125
|
+
const g = parseInt(result[2], 16);
|
|
126
|
+
const b = parseInt(result[3], 16);
|
|
127
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/charts/BaseChart.ts
|
|
131
|
+
var BaseChart = class {
|
|
132
|
+
constructor(config) {
|
|
133
|
+
this.container = null;
|
|
134
|
+
this.surface = null;
|
|
135
|
+
this.isInitialized = false;
|
|
136
|
+
this.isDestroyed = false;
|
|
137
|
+
// Event handlers
|
|
138
|
+
this.eventHandlers = /* @__PURE__ */ new Map();
|
|
139
|
+
// Resize observer
|
|
140
|
+
this.resizeObserver = null;
|
|
141
|
+
this.id = config.id ?? generateId("chart");
|
|
142
|
+
this.config = config;
|
|
143
|
+
this.theme = ThemeManager.getInstance().resolveTheme(config.theme);
|
|
144
|
+
this.debouncedResize = debounce(() => this.handleResize(), 100);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Initialize the chart in the given container
|
|
148
|
+
*/
|
|
149
|
+
async init(container) {
|
|
150
|
+
if (this.isDestroyed) {
|
|
151
|
+
throw new Error("Cannot initialize a destroyed chart");
|
|
152
|
+
}
|
|
153
|
+
if (typeof container === "string") {
|
|
154
|
+
const el = document.getElementById(container);
|
|
155
|
+
if (!el) {
|
|
156
|
+
throw new Error(`Container element "${container}" not found`);
|
|
157
|
+
}
|
|
158
|
+
this.container = el;
|
|
159
|
+
} else {
|
|
160
|
+
this.container = container;
|
|
161
|
+
}
|
|
162
|
+
this.setupContainer();
|
|
163
|
+
this.configureSciChartDefaults();
|
|
164
|
+
await this.createSurface();
|
|
165
|
+
this.setupResizeObserver();
|
|
166
|
+
this.isInitialized = true;
|
|
167
|
+
this.emit("rendered", { chartId: this.id, renderTime: performance.now() });
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Setup container element
|
|
171
|
+
*/
|
|
172
|
+
setupContainer() {
|
|
173
|
+
if (!this.container) return;
|
|
174
|
+
const { width, height } = this.config;
|
|
175
|
+
if (width) {
|
|
176
|
+
this.container.style.width = typeof width === "number" ? `${width}px` : width;
|
|
177
|
+
}
|
|
178
|
+
if (height) {
|
|
179
|
+
this.container.style.height = typeof height === "number" ? `${height}px` : height;
|
|
180
|
+
}
|
|
181
|
+
const computedStyle = window.getComputedStyle(this.container);
|
|
182
|
+
if (computedStyle.position === "static") {
|
|
183
|
+
this.container.style.position = "relative";
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Configure SciChart library defaults
|
|
188
|
+
*/
|
|
189
|
+
configureSciChartDefaults() {
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Update chart options
|
|
193
|
+
*/
|
|
194
|
+
setOptions(options) {
|
|
195
|
+
this.config = { ...this.config, ...options };
|
|
196
|
+
if (options.theme) {
|
|
197
|
+
this.theme = ThemeManager.getInstance().resolveTheme(options.theme);
|
|
198
|
+
this.applyTheme();
|
|
199
|
+
}
|
|
200
|
+
this.update();
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Apply current theme to the chart
|
|
204
|
+
*/
|
|
205
|
+
applyTheme() {
|
|
206
|
+
if (!this.surface) return;
|
|
207
|
+
this.surface.background = this.theme.backgroundColor ?? "#ffffff";
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Set up resize observer for responsive charts
|
|
211
|
+
*/
|
|
212
|
+
setupResizeObserver() {
|
|
213
|
+
if (!this.container || typeof ResizeObserver === "undefined") return;
|
|
214
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
215
|
+
this.debouncedResize();
|
|
216
|
+
});
|
|
217
|
+
this.resizeObserver.observe(this.container);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Handle container resize
|
|
221
|
+
*/
|
|
222
|
+
handleResize() {
|
|
223
|
+
if (!this.surface || !this.container) return;
|
|
224
|
+
const { width, height } = this.container.getBoundingClientRect();
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Manually resize the chart
|
|
228
|
+
*/
|
|
229
|
+
resize(width, height) {
|
|
230
|
+
if (!this.container) return;
|
|
231
|
+
if (width !== void 0) {
|
|
232
|
+
this.container.style.width = `${width}px`;
|
|
233
|
+
}
|
|
234
|
+
if (height !== void 0) {
|
|
235
|
+
this.container.style.height = `${height}px`;
|
|
236
|
+
}
|
|
237
|
+
this.handleResize();
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Export chart as image
|
|
241
|
+
*/
|
|
242
|
+
async exportImage(format = "png") {
|
|
243
|
+
if (!this.surface) {
|
|
244
|
+
throw new Error("Chart not initialized");
|
|
245
|
+
}
|
|
246
|
+
const canvas = this.container?.querySelector("canvas");
|
|
247
|
+
if (!canvas) {
|
|
248
|
+
throw new Error("Canvas not found");
|
|
249
|
+
}
|
|
250
|
+
const mimeType = format === "jpeg" ? "image/jpeg" : "image/png";
|
|
251
|
+
return canvas.toDataURL(mimeType);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Add event listener
|
|
255
|
+
*/
|
|
256
|
+
on(event, handler) {
|
|
257
|
+
if (!this.eventHandlers.has(event)) {
|
|
258
|
+
this.eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
259
|
+
}
|
|
260
|
+
this.eventHandlers.get(event).add(handler);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Remove event listener
|
|
264
|
+
*/
|
|
265
|
+
off(event, handler) {
|
|
266
|
+
const handlers = this.eventHandlers.get(event);
|
|
267
|
+
if (handlers) {
|
|
268
|
+
handlers.delete(handler);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Emit an event
|
|
273
|
+
*/
|
|
274
|
+
emit(event, data) {
|
|
275
|
+
const handlers = this.eventHandlers.get(event);
|
|
276
|
+
if (handlers) {
|
|
277
|
+
handlers.forEach((handler) => handler(data));
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Destroy the chart and clean up resources
|
|
282
|
+
*/
|
|
283
|
+
destroy() {
|
|
284
|
+
if (this.isDestroyed) return;
|
|
285
|
+
if (this.resizeObserver) {
|
|
286
|
+
this.resizeObserver.disconnect();
|
|
287
|
+
this.resizeObserver = null;
|
|
288
|
+
}
|
|
289
|
+
this.eventHandlers.clear();
|
|
290
|
+
if (this.surface) {
|
|
291
|
+
this.surface.delete();
|
|
292
|
+
this.surface = null;
|
|
293
|
+
}
|
|
294
|
+
if (this.container) {
|
|
295
|
+
this.container.innerHTML = "";
|
|
296
|
+
}
|
|
297
|
+
this.isDestroyed = true;
|
|
298
|
+
this.isInitialized = false;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Get current configuration
|
|
302
|
+
*/
|
|
303
|
+
getConfig() {
|
|
304
|
+
return { ...this.config };
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get current theme
|
|
308
|
+
*/
|
|
309
|
+
getTheme() {
|
|
310
|
+
return { ...this.theme };
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Check if chart is initialized
|
|
314
|
+
*/
|
|
315
|
+
isReady() {
|
|
316
|
+
return this.isInitialized && !this.isDestroyed;
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function getSciChartTheme(themeName) {
|
|
320
|
+
switch (themeName) {
|
|
321
|
+
case "light":
|
|
322
|
+
return new SciChartJSLightTheme();
|
|
323
|
+
case "dark":
|
|
324
|
+
case "modern":
|
|
325
|
+
case "midnight":
|
|
326
|
+
default:
|
|
327
|
+
return new SciChartJSDarkTheme();
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
var LineChart = class extends BaseChart {
|
|
331
|
+
constructor(config) {
|
|
332
|
+
super(config);
|
|
333
|
+
this.dataSeries = /* @__PURE__ */ new Map();
|
|
334
|
+
this.renderableSeries = [];
|
|
335
|
+
this.wasmContext = null;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Create the SciChart surface for line chart
|
|
339
|
+
*/
|
|
340
|
+
async createSurface() {
|
|
341
|
+
if (!this.container) {
|
|
342
|
+
throw new Error("Container not set");
|
|
343
|
+
}
|
|
344
|
+
const sciChartTheme = getSciChartTheme(this.config.theme);
|
|
345
|
+
if (!this.container.id) {
|
|
346
|
+
this.container.id = this.id;
|
|
347
|
+
}
|
|
348
|
+
const { sciChartSurface, wasmContext } = await SciChartSurface.create(
|
|
349
|
+
this.container,
|
|
350
|
+
{
|
|
351
|
+
theme: sciChartTheme
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
this.surface = sciChartSurface;
|
|
355
|
+
this.wasmContext = wasmContext;
|
|
356
|
+
const xAxis = new NumericAxis(wasmContext, {
|
|
357
|
+
axisTitle: this.config.xAxis?.title,
|
|
358
|
+
drawMajorGridLines: this.config.xAxis?.gridLines?.show ?? true,
|
|
359
|
+
drawMinorGridLines: false,
|
|
360
|
+
axisTitleStyle: {
|
|
361
|
+
fontSize: 14,
|
|
362
|
+
fontFamily: this.theme.fontFamily,
|
|
363
|
+
color: this.theme.axis?.titleColor
|
|
364
|
+
},
|
|
365
|
+
labelStyle: {
|
|
366
|
+
fontSize: 12,
|
|
367
|
+
fontFamily: this.theme.fontFamily,
|
|
368
|
+
color: this.theme.axis?.labelColor
|
|
369
|
+
},
|
|
370
|
+
majorGridLineStyle: {
|
|
371
|
+
color: this.theme.axis?.gridLineColor ?? "#e9ecef",
|
|
372
|
+
strokeThickness: 1
|
|
373
|
+
},
|
|
374
|
+
axisBorder: {
|
|
375
|
+
color: this.theme.axis?.lineColor ?? "#dee2e6"
|
|
376
|
+
},
|
|
377
|
+
autoRange: EAutoRange.Always
|
|
378
|
+
});
|
|
379
|
+
const yAxis = new NumericAxis(wasmContext, {
|
|
380
|
+
axisTitle: this.config.yAxis?.title,
|
|
381
|
+
drawMajorGridLines: this.config.yAxis?.gridLines?.show ?? true,
|
|
382
|
+
drawMinorGridLines: false,
|
|
383
|
+
axisTitleStyle: {
|
|
384
|
+
fontSize: 14,
|
|
385
|
+
fontFamily: this.theme.fontFamily,
|
|
386
|
+
color: this.theme.axis?.titleColor
|
|
387
|
+
},
|
|
388
|
+
labelStyle: {
|
|
389
|
+
fontSize: 12,
|
|
390
|
+
fontFamily: this.theme.fontFamily,
|
|
391
|
+
color: this.theme.axis?.labelColor
|
|
392
|
+
},
|
|
393
|
+
majorGridLineStyle: {
|
|
394
|
+
color: this.theme.axis?.gridLineColor ?? "#e9ecef",
|
|
395
|
+
strokeThickness: 1
|
|
396
|
+
},
|
|
397
|
+
axisBorder: {
|
|
398
|
+
color: this.theme.axis?.lineColor ?? "#dee2e6"
|
|
399
|
+
},
|
|
400
|
+
autoRange: EAutoRange.Always
|
|
401
|
+
});
|
|
402
|
+
if (this.config.xAxis?.min !== void 0 && this.config.xAxis?.max !== void 0) {
|
|
403
|
+
xAxis.visibleRange = new NumberRange(this.config.xAxis.min, this.config.xAxis.max);
|
|
404
|
+
xAxis.autoRange = EAutoRange.Never;
|
|
405
|
+
}
|
|
406
|
+
if (this.config.yAxis?.min !== void 0 && this.config.yAxis?.max !== void 0) {
|
|
407
|
+
yAxis.visibleRange = new NumberRange(this.config.yAxis.min, this.config.yAxis.max);
|
|
408
|
+
yAxis.autoRange = EAutoRange.Never;
|
|
409
|
+
}
|
|
410
|
+
sciChartSurface.xAxes.add(xAxis);
|
|
411
|
+
sciChartSurface.yAxes.add(yAxis);
|
|
412
|
+
if (this.config.tooltip?.enabled !== false) {
|
|
413
|
+
sciChartSurface.chartModifiers.add(
|
|
414
|
+
new RolloverModifier({
|
|
415
|
+
showTooltip: true,
|
|
416
|
+
showAxisLabel: true
|
|
417
|
+
})
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
sciChartSurface.chartModifiers.add(new ZoomPanModifier());
|
|
421
|
+
sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());
|
|
422
|
+
this.addSeries(this.config.series);
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Add series to the chart
|
|
426
|
+
*/
|
|
427
|
+
addSeries(seriesConfigs) {
|
|
428
|
+
if (!this.surface || !this.wasmContext) return;
|
|
429
|
+
const wasmContext = this.wasmContext;
|
|
430
|
+
const colorPalette = this.theme.colorPalette ?? [];
|
|
431
|
+
seriesConfigs.forEach((seriesConfig, index) => {
|
|
432
|
+
const data = normalizeDataPoints(seriesConfig.data);
|
|
433
|
+
const xValues = extractXValues(data);
|
|
434
|
+
const yValues = extractYValues(data);
|
|
435
|
+
const dataSeries = new XyDataSeries(wasmContext, {
|
|
436
|
+
xValues,
|
|
437
|
+
yValues,
|
|
438
|
+
dataSeriesName: seriesConfig.name
|
|
439
|
+
});
|
|
440
|
+
this.dataSeries.set(seriesConfig.name, dataSeries);
|
|
441
|
+
const color = seriesConfig.color ?? colorPalette[index % colorPalette.length] ?? "#6366f1";
|
|
442
|
+
const lineSeries = new FastLineRenderableSeries(wasmContext);
|
|
443
|
+
lineSeries.dataSeries = dataSeries;
|
|
444
|
+
lineSeries.stroke = color;
|
|
445
|
+
lineSeries.strokeThickness = this.config.lineWidth ?? 2;
|
|
446
|
+
if (this.config.showPoints) {
|
|
447
|
+
lineSeries.pointMarker = new EllipsePointMarker(wasmContext, {
|
|
448
|
+
width: this.config.pointSize ?? 8,
|
|
449
|
+
height: this.config.pointSize ?? 8,
|
|
450
|
+
fill: color,
|
|
451
|
+
stroke: color,
|
|
452
|
+
strokeThickness: 0
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
if (this.config.animation !== false) {
|
|
456
|
+
lineSeries.animation = new SweepAnimation({
|
|
457
|
+
duration: typeof this.config.animation === "object" ? this.config.animation.duration ?? 500 : 500
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
this.renderableSeries.push(lineSeries);
|
|
461
|
+
this.surface.renderableSeries.add(lineSeries);
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Set new data for the chart
|
|
466
|
+
*/
|
|
467
|
+
setData(data) {
|
|
468
|
+
if (!this.surface) {
|
|
469
|
+
this.config.series = data;
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
this.clearSeries();
|
|
473
|
+
this.config.series = data;
|
|
474
|
+
this.addSeries(data);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Update specific series data
|
|
478
|
+
*/
|
|
479
|
+
updateSeriesData(seriesName, data) {
|
|
480
|
+
const dataSeries = this.dataSeries.get(seriesName);
|
|
481
|
+
if (!dataSeries) {
|
|
482
|
+
console.warn(`Series "${seriesName}" not found`);
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const normalized = normalizeDataPoints(data);
|
|
486
|
+
const xValues = extractXValues(normalized);
|
|
487
|
+
const yValues = extractYValues(normalized);
|
|
488
|
+
dataSeries.clear();
|
|
489
|
+
dataSeries.appendRange(xValues, yValues);
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Append data to a series
|
|
493
|
+
*/
|
|
494
|
+
appendData(seriesName, data) {
|
|
495
|
+
const dataSeries = this.dataSeries.get(seriesName);
|
|
496
|
+
if (!dataSeries) {
|
|
497
|
+
console.warn(`Series "${seriesName}" not found`);
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
const points = Array.isArray(data) ? data : [data];
|
|
501
|
+
const normalized = normalizeDataPoints(points);
|
|
502
|
+
const xValues = extractXValues(normalized);
|
|
503
|
+
const yValues = extractYValues(normalized);
|
|
504
|
+
dataSeries.appendRange(xValues, yValues);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Clear all series
|
|
508
|
+
*/
|
|
509
|
+
clearSeries() {
|
|
510
|
+
if (!this.surface) return;
|
|
511
|
+
this.renderableSeries.forEach((series) => {
|
|
512
|
+
this.surface.renderableSeries.remove(series);
|
|
513
|
+
series.delete();
|
|
514
|
+
});
|
|
515
|
+
this.renderableSeries = [];
|
|
516
|
+
this.dataSeries.forEach((ds) => ds.delete());
|
|
517
|
+
this.dataSeries.clear();
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Update chart
|
|
521
|
+
*/
|
|
522
|
+
update() {
|
|
523
|
+
if (!this.surface) return;
|
|
524
|
+
this.applyTheme();
|
|
525
|
+
this.surface.invalidateElement();
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Apply theme to line chart
|
|
529
|
+
*/
|
|
530
|
+
applyTheme() {
|
|
531
|
+
super.applyTheme();
|
|
532
|
+
if (!this.surface) return;
|
|
533
|
+
const colorPalette = this.theme.colorPalette ?? [];
|
|
534
|
+
this.renderableSeries.forEach((series, index) => {
|
|
535
|
+
const originalColor = this.config.series[index]?.color;
|
|
536
|
+
if (!originalColor) {
|
|
537
|
+
series.stroke = colorPalette[index % colorPalette.length];
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Destroy and clean up
|
|
543
|
+
*/
|
|
544
|
+
destroy() {
|
|
545
|
+
this.clearSeries();
|
|
546
|
+
super.destroy();
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
async function createLineChart(container, config) {
|
|
550
|
+
const chart = new LineChart(config);
|
|
551
|
+
await chart.init(container);
|
|
552
|
+
return chart;
|
|
553
|
+
}
|
|
554
|
+
function getSciChartTheme2(themeName) {
|
|
555
|
+
switch (themeName) {
|
|
556
|
+
case "light":
|
|
557
|
+
return new SciChartJSLightTheme();
|
|
558
|
+
case "dark":
|
|
559
|
+
case "modern":
|
|
560
|
+
case "midnight":
|
|
561
|
+
default:
|
|
562
|
+
return new SciChartJSDarkTheme();
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
var BarChart = class extends BaseChart {
|
|
566
|
+
constructor(config) {
|
|
567
|
+
super(config);
|
|
568
|
+
this.dataSeries = /* @__PURE__ */ new Map();
|
|
569
|
+
this.renderableSeries = [];
|
|
570
|
+
this.wasmContext = null;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Create the SciChart surface for bar chart
|
|
574
|
+
*/
|
|
575
|
+
async createSurface() {
|
|
576
|
+
if (!this.container) {
|
|
577
|
+
throw new Error("Container not set");
|
|
578
|
+
}
|
|
579
|
+
const sciChartTheme = getSciChartTheme2(this.config.theme);
|
|
580
|
+
if (!this.container.id) {
|
|
581
|
+
this.container.id = this.id;
|
|
582
|
+
}
|
|
583
|
+
const { sciChartSurface, wasmContext } = await SciChartSurface.create(
|
|
584
|
+
this.container,
|
|
585
|
+
{
|
|
586
|
+
theme: sciChartTheme
|
|
587
|
+
}
|
|
588
|
+
);
|
|
589
|
+
this.surface = sciChartSurface;
|
|
590
|
+
this.wasmContext = wasmContext;
|
|
591
|
+
const xAxis = new NumericAxis(wasmContext, {
|
|
592
|
+
axisTitle: this.config.xAxis?.title,
|
|
593
|
+
drawMajorGridLines: this.config.xAxis?.gridLines?.show ?? false,
|
|
594
|
+
drawMinorGridLines: false,
|
|
595
|
+
axisTitleStyle: {
|
|
596
|
+
fontSize: 14,
|
|
597
|
+
fontFamily: this.theme.fontFamily,
|
|
598
|
+
color: this.theme.axis?.titleColor
|
|
599
|
+
},
|
|
600
|
+
labelStyle: {
|
|
601
|
+
fontSize: 12,
|
|
602
|
+
fontFamily: this.theme.fontFamily,
|
|
603
|
+
color: this.theme.axis?.labelColor
|
|
604
|
+
},
|
|
605
|
+
autoRange: EAutoRange.Always
|
|
606
|
+
});
|
|
607
|
+
const yAxis = new NumericAxis(wasmContext, {
|
|
608
|
+
axisTitle: this.config.yAxis?.title,
|
|
609
|
+
drawMajorGridLines: this.config.yAxis?.gridLines?.show ?? true,
|
|
610
|
+
drawMinorGridLines: false,
|
|
611
|
+
axisTitleStyle: {
|
|
612
|
+
fontSize: 14,
|
|
613
|
+
fontFamily: this.theme.fontFamily,
|
|
614
|
+
color: this.theme.axis?.titleColor
|
|
615
|
+
},
|
|
616
|
+
labelStyle: {
|
|
617
|
+
fontSize: 12,
|
|
618
|
+
fontFamily: this.theme.fontFamily,
|
|
619
|
+
color: this.theme.axis?.labelColor
|
|
620
|
+
},
|
|
621
|
+
autoRange: EAutoRange.Always,
|
|
622
|
+
growBy: new NumberRange(0, 0.1)
|
|
623
|
+
// Add 10% padding at top
|
|
624
|
+
});
|
|
625
|
+
if (this.config.xAxis?.min !== void 0 && this.config.xAxis?.max !== void 0) {
|
|
626
|
+
xAxis.visibleRange = new NumberRange(this.config.xAxis.min, this.config.xAxis.max);
|
|
627
|
+
xAxis.autoRange = EAutoRange.Never;
|
|
628
|
+
}
|
|
629
|
+
if (this.config.yAxis?.min !== void 0 && this.config.yAxis?.max !== void 0) {
|
|
630
|
+
yAxis.visibleRange = new NumberRange(this.config.yAxis.min, this.config.yAxis.max);
|
|
631
|
+
yAxis.autoRange = EAutoRange.Never;
|
|
632
|
+
}
|
|
633
|
+
sciChartSurface.xAxes.add(xAxis);
|
|
634
|
+
sciChartSurface.yAxes.add(yAxis);
|
|
635
|
+
if (this.config.tooltip?.enabled !== false) {
|
|
636
|
+
sciChartSurface.chartModifiers.add(
|
|
637
|
+
new RolloverModifier({
|
|
638
|
+
showTooltip: true,
|
|
639
|
+
showAxisLabel: true
|
|
640
|
+
})
|
|
641
|
+
);
|
|
642
|
+
}
|
|
643
|
+
sciChartSurface.chartModifiers.add(new ZoomPanModifier());
|
|
644
|
+
this.addSeries(this.config.series);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Add series to the chart
|
|
648
|
+
*/
|
|
649
|
+
addSeries(seriesConfigs) {
|
|
650
|
+
if (!this.surface || !this.wasmContext) return;
|
|
651
|
+
const wasmContext = this.wasmContext;
|
|
652
|
+
const colorPalette = this.theme.colorPalette ?? [];
|
|
653
|
+
const seriesCount = seriesConfigs.length;
|
|
654
|
+
const dataPointWidth = this.config.barWidth ?? 0.7;
|
|
655
|
+
seriesConfigs.forEach((seriesConfig, index) => {
|
|
656
|
+
const data = normalizeDataPoints(seriesConfig.data);
|
|
657
|
+
let xValues = extractXValues(data);
|
|
658
|
+
if (!this.config.stacked && seriesCount > 1) {
|
|
659
|
+
const offset = (index - (seriesCount - 1) / 2) * (dataPointWidth / seriesCount);
|
|
660
|
+
xValues = xValues.map((x) => x + offset);
|
|
661
|
+
}
|
|
662
|
+
const yValues = extractYValues(data);
|
|
663
|
+
const dataSeries = new XyDataSeries(wasmContext, {
|
|
664
|
+
xValues,
|
|
665
|
+
yValues,
|
|
666
|
+
dataSeriesName: seriesConfig.name
|
|
667
|
+
});
|
|
668
|
+
this.dataSeries.set(seriesConfig.name, dataSeries);
|
|
669
|
+
const color = seriesConfig.color ?? colorPalette[index % colorPalette.length] ?? "#6366f1";
|
|
670
|
+
const columnSeries = new FastColumnRenderableSeries(wasmContext);
|
|
671
|
+
columnSeries.dataSeries = dataSeries;
|
|
672
|
+
columnSeries.fill = color;
|
|
673
|
+
columnSeries.stroke = color;
|
|
674
|
+
columnSeries.strokeThickness = 0;
|
|
675
|
+
columnSeries.dataPointWidth = this.config.stacked ? dataPointWidth : dataPointWidth / seriesCount;
|
|
676
|
+
columnSeries.cornerRadius = this.config.borderRadius ?? 0;
|
|
677
|
+
if (this.config.animation !== false) {
|
|
678
|
+
columnSeries.animation = new WaveAnimation({
|
|
679
|
+
duration: typeof this.config.animation === "object" ? this.config.animation.duration ?? 500 : 500
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
columnSeries.fillLinearGradient = new GradientParams(
|
|
683
|
+
new Point(0, 0),
|
|
684
|
+
new Point(0, 1),
|
|
685
|
+
[
|
|
686
|
+
{ color, offset: 0 },
|
|
687
|
+
{ color: hexToRgba(color, 0.7), offset: 1 }
|
|
688
|
+
]
|
|
689
|
+
);
|
|
690
|
+
this.renderableSeries.push(columnSeries);
|
|
691
|
+
this.surface.renderableSeries.add(columnSeries);
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Set new data for the chart
|
|
696
|
+
*/
|
|
697
|
+
setData(data) {
|
|
698
|
+
if (!this.surface) {
|
|
699
|
+
this.config.series = data;
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
this.clearSeries();
|
|
703
|
+
this.config.series = data;
|
|
704
|
+
this.addSeries(data);
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Update specific series data
|
|
708
|
+
*/
|
|
709
|
+
updateSeriesData(seriesName, data) {
|
|
710
|
+
const dataSeries = this.dataSeries.get(seriesName);
|
|
711
|
+
if (!dataSeries) {
|
|
712
|
+
console.warn(`Series "${seriesName}" not found`);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
const normalized = normalizeDataPoints(data);
|
|
716
|
+
const xValues = extractXValues(normalized);
|
|
717
|
+
const yValues = extractYValues(normalized);
|
|
718
|
+
dataSeries.clear();
|
|
719
|
+
dataSeries.appendRange(xValues, yValues);
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* Clear all series
|
|
723
|
+
*/
|
|
724
|
+
clearSeries() {
|
|
725
|
+
if (!this.surface) return;
|
|
726
|
+
this.renderableSeries.forEach((series) => {
|
|
727
|
+
this.surface.renderableSeries.remove(series);
|
|
728
|
+
series.delete();
|
|
729
|
+
});
|
|
730
|
+
this.renderableSeries = [];
|
|
731
|
+
this.dataSeries.forEach((ds) => ds.delete());
|
|
732
|
+
this.dataSeries.clear();
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Update chart
|
|
736
|
+
*/
|
|
737
|
+
update() {
|
|
738
|
+
if (!this.surface) return;
|
|
739
|
+
this.applyTheme();
|
|
740
|
+
this.surface.invalidateElement();
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Destroy and clean up
|
|
744
|
+
*/
|
|
745
|
+
destroy() {
|
|
746
|
+
this.clearSeries();
|
|
747
|
+
super.destroy();
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
async function createBarChart(container, config) {
|
|
751
|
+
const chart = new BarChart(config);
|
|
752
|
+
await chart.init(container);
|
|
753
|
+
return chart;
|
|
754
|
+
}
|
|
755
|
+
function getSciChartTheme3(themeName) {
|
|
756
|
+
switch (themeName) {
|
|
757
|
+
case "light":
|
|
758
|
+
return new SciChartJSLightTheme();
|
|
759
|
+
case "dark":
|
|
760
|
+
case "modern":
|
|
761
|
+
case "midnight":
|
|
762
|
+
default:
|
|
763
|
+
return new SciChartJSDarkTheme();
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
var AreaChart = class extends BaseChart {
|
|
767
|
+
constructor(config) {
|
|
768
|
+
super(config);
|
|
769
|
+
this.dataSeries = /* @__PURE__ */ new Map();
|
|
770
|
+
this.renderableSeries = [];
|
|
771
|
+
this.wasmContext = null;
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Create the SciChart surface for area chart
|
|
775
|
+
*/
|
|
776
|
+
async createSurface() {
|
|
777
|
+
if (!this.container) {
|
|
778
|
+
throw new Error("Container not set");
|
|
779
|
+
}
|
|
780
|
+
const sciChartTheme = getSciChartTheme3(this.config.theme);
|
|
781
|
+
if (!this.container.id) {
|
|
782
|
+
this.container.id = this.id;
|
|
783
|
+
}
|
|
784
|
+
const { sciChartSurface, wasmContext } = await SciChartSurface.create(
|
|
785
|
+
this.container,
|
|
786
|
+
{
|
|
787
|
+
theme: sciChartTheme
|
|
788
|
+
}
|
|
789
|
+
);
|
|
790
|
+
this.surface = sciChartSurface;
|
|
791
|
+
this.wasmContext = wasmContext;
|
|
792
|
+
const xAxis = new NumericAxis(wasmContext, {
|
|
793
|
+
axisTitle: this.config.xAxis?.title,
|
|
794
|
+
drawMajorGridLines: this.config.xAxis?.gridLines?.show ?? true,
|
|
795
|
+
drawMinorGridLines: false,
|
|
796
|
+
axisTitleStyle: {
|
|
797
|
+
fontSize: 14,
|
|
798
|
+
fontFamily: this.theme.fontFamily,
|
|
799
|
+
color: this.theme.axis?.titleColor
|
|
800
|
+
},
|
|
801
|
+
labelStyle: {
|
|
802
|
+
fontSize: 12,
|
|
803
|
+
fontFamily: this.theme.fontFamily,
|
|
804
|
+
color: this.theme.axis?.labelColor
|
|
805
|
+
},
|
|
806
|
+
autoRange: EAutoRange.Always
|
|
807
|
+
});
|
|
808
|
+
const yAxis = new NumericAxis(wasmContext, {
|
|
809
|
+
axisTitle: this.config.yAxis?.title,
|
|
810
|
+
drawMajorGridLines: this.config.yAxis?.gridLines?.show ?? true,
|
|
811
|
+
drawMinorGridLines: false,
|
|
812
|
+
axisTitleStyle: {
|
|
813
|
+
fontSize: 14,
|
|
814
|
+
fontFamily: this.theme.fontFamily,
|
|
815
|
+
color: this.theme.axis?.titleColor
|
|
816
|
+
},
|
|
817
|
+
labelStyle: {
|
|
818
|
+
fontSize: 12,
|
|
819
|
+
fontFamily: this.theme.fontFamily,
|
|
820
|
+
color: this.theme.axis?.labelColor
|
|
821
|
+
},
|
|
822
|
+
autoRange: EAutoRange.Always,
|
|
823
|
+
growBy: new NumberRange(0, 0.1)
|
|
824
|
+
});
|
|
825
|
+
if (this.config.xAxis?.min !== void 0 && this.config.xAxis?.max !== void 0) {
|
|
826
|
+
xAxis.visibleRange = new NumberRange(this.config.xAxis.min, this.config.xAxis.max);
|
|
827
|
+
xAxis.autoRange = EAutoRange.Never;
|
|
828
|
+
}
|
|
829
|
+
if (this.config.yAxis?.min !== void 0 && this.config.yAxis?.max !== void 0) {
|
|
830
|
+
yAxis.visibleRange = new NumberRange(this.config.yAxis.min, this.config.yAxis.max);
|
|
831
|
+
yAxis.autoRange = EAutoRange.Never;
|
|
832
|
+
}
|
|
833
|
+
sciChartSurface.xAxes.add(xAxis);
|
|
834
|
+
sciChartSurface.yAxes.add(yAxis);
|
|
835
|
+
if (this.config.tooltip?.enabled !== false) {
|
|
836
|
+
sciChartSurface.chartModifiers.add(
|
|
837
|
+
new RolloverModifier({
|
|
838
|
+
showTooltip: true,
|
|
839
|
+
showAxisLabel: true
|
|
840
|
+
})
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
sciChartSurface.chartModifiers.add(new ZoomPanModifier());
|
|
844
|
+
sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());
|
|
845
|
+
this.addSeries(this.config.series);
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Add series to the chart
|
|
849
|
+
*/
|
|
850
|
+
addSeries(seriesConfigs) {
|
|
851
|
+
if (!this.surface || !this.wasmContext) return;
|
|
852
|
+
const wasmContext = this.wasmContext;
|
|
853
|
+
const colorPalette = this.theme.colorPalette ?? [];
|
|
854
|
+
const fillOpacity = this.config.fillOpacity ?? 0.5;
|
|
855
|
+
seriesConfigs.forEach((seriesConfig, index) => {
|
|
856
|
+
const data = normalizeDataPoints(seriesConfig.data);
|
|
857
|
+
const xValues = extractXValues(data);
|
|
858
|
+
const yValues = extractYValues(data);
|
|
859
|
+
const dataSeries = new XyDataSeries(wasmContext, {
|
|
860
|
+
xValues,
|
|
861
|
+
yValues,
|
|
862
|
+
dataSeriesName: seriesConfig.name
|
|
863
|
+
});
|
|
864
|
+
this.dataSeries.set(seriesConfig.name, dataSeries);
|
|
865
|
+
const color = seriesConfig.color ?? colorPalette[index % colorPalette.length] ?? "#6366f1";
|
|
866
|
+
const areaSeries = new FastMountainRenderableSeries(wasmContext, {
|
|
867
|
+
dataSeries,
|
|
868
|
+
stroke: color,
|
|
869
|
+
strokeThickness: this.config.lineWidth ?? 2,
|
|
870
|
+
fill: hexToRgba(color, fillOpacity),
|
|
871
|
+
...this.config.animation !== false && {
|
|
872
|
+
animation: new SweepAnimation({
|
|
873
|
+
duration: typeof this.config.animation === "object" ? this.config.animation.duration ?? 500 : 500
|
|
874
|
+
})
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
areaSeries.fillLinearGradient = new GradientParams(
|
|
878
|
+
new Point(0, 0),
|
|
879
|
+
new Point(0, 1),
|
|
880
|
+
[
|
|
881
|
+
{ color: hexToRgba(color, fillOpacity), offset: 0 },
|
|
882
|
+
{ color: hexToRgba(color, 0.05), offset: 1 }
|
|
883
|
+
]
|
|
884
|
+
);
|
|
885
|
+
this.renderableSeries.push(areaSeries);
|
|
886
|
+
this.surface.renderableSeries.add(areaSeries);
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Set new data for the chart
|
|
891
|
+
*/
|
|
892
|
+
setData(data) {
|
|
893
|
+
if (!this.surface) {
|
|
894
|
+
this.config.series = data;
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
this.clearSeries();
|
|
898
|
+
this.config.series = data;
|
|
899
|
+
this.addSeries(data);
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Update specific series data
|
|
903
|
+
*/
|
|
904
|
+
updateSeriesData(seriesName, data) {
|
|
905
|
+
const dataSeries = this.dataSeries.get(seriesName);
|
|
906
|
+
if (!dataSeries) {
|
|
907
|
+
console.warn(`Series "${seriesName}" not found`);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
const normalized = normalizeDataPoints(data);
|
|
911
|
+
const xValues = extractXValues(normalized);
|
|
912
|
+
const yValues = extractYValues(normalized);
|
|
913
|
+
dataSeries.clear();
|
|
914
|
+
dataSeries.appendRange(xValues, yValues);
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Clear all series
|
|
918
|
+
*/
|
|
919
|
+
clearSeries() {
|
|
920
|
+
if (!this.surface) return;
|
|
921
|
+
this.renderableSeries.forEach((series) => {
|
|
922
|
+
this.surface.renderableSeries.remove(series);
|
|
923
|
+
series.delete();
|
|
924
|
+
});
|
|
925
|
+
this.renderableSeries = [];
|
|
926
|
+
this.dataSeries.forEach((ds) => ds.delete());
|
|
927
|
+
this.dataSeries.clear();
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Update chart
|
|
931
|
+
*/
|
|
932
|
+
update() {
|
|
933
|
+
if (!this.surface) return;
|
|
934
|
+
this.applyTheme();
|
|
935
|
+
this.surface.invalidateElement();
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Destroy and clean up
|
|
939
|
+
*/
|
|
940
|
+
destroy() {
|
|
941
|
+
this.clearSeries();
|
|
942
|
+
super.destroy();
|
|
943
|
+
}
|
|
944
|
+
};
|
|
945
|
+
async function createAreaChart(container, config) {
|
|
946
|
+
const chart = new AreaChart(config);
|
|
947
|
+
await chart.init(container);
|
|
948
|
+
return chart;
|
|
949
|
+
}
|
|
950
|
+
function getSciChartTheme4(themeName) {
|
|
951
|
+
switch (themeName) {
|
|
952
|
+
case "light":
|
|
953
|
+
return new SciChartJSLightTheme();
|
|
954
|
+
case "dark":
|
|
955
|
+
case "modern":
|
|
956
|
+
case "midnight":
|
|
957
|
+
default:
|
|
958
|
+
return new SciChartJSDarkTheme();
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
var defaultColorStops = [
|
|
962
|
+
{ offset: 0, color: "#000080" },
|
|
963
|
+
// Dark blue
|
|
964
|
+
{ offset: 0.2, color: "#0000ff" },
|
|
965
|
+
// Blue
|
|
966
|
+
{ offset: 0.4, color: "#00ffff" },
|
|
967
|
+
// Cyan
|
|
968
|
+
{ offset: 0.6, color: "#00ff00" },
|
|
969
|
+
// Green
|
|
970
|
+
{ offset: 0.8, color: "#ffff00" },
|
|
971
|
+
// Yellow
|
|
972
|
+
{ offset: 1, color: "#ff0000" }
|
|
973
|
+
// Red
|
|
974
|
+
];
|
|
975
|
+
var HeatmapChart = class extends BaseChart {
|
|
976
|
+
constructor(config) {
|
|
977
|
+
super(config);
|
|
978
|
+
this.heatmapDataSeries = null;
|
|
979
|
+
this.heatmapSeries = null;
|
|
980
|
+
this.wasmContext = null;
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* Create the SciChart surface for heatmap chart
|
|
984
|
+
*/
|
|
985
|
+
async createSurface() {
|
|
986
|
+
if (!this.container) {
|
|
987
|
+
throw new Error("Container not set");
|
|
988
|
+
}
|
|
989
|
+
const sciChartTheme = getSciChartTheme4(this.config.theme);
|
|
990
|
+
if (!this.container.id) {
|
|
991
|
+
this.container.id = this.id;
|
|
992
|
+
}
|
|
993
|
+
const { sciChartSurface, wasmContext } = await SciChartSurface.create(
|
|
994
|
+
this.container,
|
|
995
|
+
{
|
|
996
|
+
theme: sciChartTheme
|
|
997
|
+
}
|
|
998
|
+
);
|
|
999
|
+
this.surface = sciChartSurface;
|
|
1000
|
+
this.wasmContext = wasmContext;
|
|
1001
|
+
const xAxis = new NumericAxis(wasmContext, {
|
|
1002
|
+
axisTitle: this.config.xAxis?.title,
|
|
1003
|
+
drawMajorGridLines: this.config.xAxis?.gridLines?.show ?? false,
|
|
1004
|
+
drawMinorGridLines: false,
|
|
1005
|
+
axisTitleStyle: {
|
|
1006
|
+
fontSize: 14,
|
|
1007
|
+
fontFamily: this.theme.fontFamily,
|
|
1008
|
+
color: this.theme.axis?.titleColor
|
|
1009
|
+
},
|
|
1010
|
+
labelStyle: {
|
|
1011
|
+
fontSize: 12,
|
|
1012
|
+
fontFamily: this.theme.fontFamily,
|
|
1013
|
+
color: this.theme.axis?.labelColor
|
|
1014
|
+
},
|
|
1015
|
+
autoRange: EAutoRange.Always
|
|
1016
|
+
});
|
|
1017
|
+
const yAxis = new NumericAxis(wasmContext, {
|
|
1018
|
+
axisTitle: this.config.yAxis?.title,
|
|
1019
|
+
drawMajorGridLines: this.config.yAxis?.gridLines?.show ?? false,
|
|
1020
|
+
drawMinorGridLines: false,
|
|
1021
|
+
axisTitleStyle: {
|
|
1022
|
+
fontSize: 14,
|
|
1023
|
+
fontFamily: this.theme.fontFamily,
|
|
1024
|
+
color: this.theme.axis?.titleColor
|
|
1025
|
+
},
|
|
1026
|
+
labelStyle: {
|
|
1027
|
+
fontSize: 12,
|
|
1028
|
+
fontFamily: this.theme.fontFamily,
|
|
1029
|
+
color: this.theme.axis?.labelColor
|
|
1030
|
+
},
|
|
1031
|
+
autoRange: EAutoRange.Always
|
|
1032
|
+
});
|
|
1033
|
+
if (this.config.xAxis?.min !== void 0 && this.config.xAxis?.max !== void 0) {
|
|
1034
|
+
xAxis.visibleRange = new NumberRange(this.config.xAxis.min, this.config.xAxis.max);
|
|
1035
|
+
xAxis.autoRange = EAutoRange.Never;
|
|
1036
|
+
}
|
|
1037
|
+
if (this.config.yAxis?.min !== void 0 && this.config.yAxis?.max !== void 0) {
|
|
1038
|
+
yAxis.visibleRange = new NumberRange(this.config.yAxis.min, this.config.yAxis.max);
|
|
1039
|
+
yAxis.autoRange = EAutoRange.Never;
|
|
1040
|
+
}
|
|
1041
|
+
sciChartSurface.xAxes.add(xAxis);
|
|
1042
|
+
sciChartSurface.yAxes.add(yAxis);
|
|
1043
|
+
if (this.config.tooltip?.enabled !== false) {
|
|
1044
|
+
sciChartSurface.chartModifiers.add(
|
|
1045
|
+
new RolloverModifier({
|
|
1046
|
+
showTooltip: true,
|
|
1047
|
+
showAxisLabel: true
|
|
1048
|
+
})
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
sciChartSurface.chartModifiers.add(new ZoomPanModifier());
|
|
1052
|
+
sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());
|
|
1053
|
+
this.addHeatmapData(this.config.zValues);
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Add heatmap data to the chart
|
|
1057
|
+
*/
|
|
1058
|
+
addHeatmapData(zValues) {
|
|
1059
|
+
if (!this.surface || !this.wasmContext) return;
|
|
1060
|
+
const wasmContext = this.wasmContext;
|
|
1061
|
+
let min = this.config.colorMin;
|
|
1062
|
+
let max = this.config.colorMax;
|
|
1063
|
+
if (min === void 0 || max === void 0) {
|
|
1064
|
+
const flatValues = zValues.flat();
|
|
1065
|
+
min = min ?? Math.min(...flatValues);
|
|
1066
|
+
max = max ?? Math.max(...flatValues);
|
|
1067
|
+
}
|
|
1068
|
+
this.heatmapDataSeries = new UniformHeatmapDataSeries(wasmContext, {
|
|
1069
|
+
zValues,
|
|
1070
|
+
xStart: this.config.xStart ?? 0,
|
|
1071
|
+
xStep: this.config.xStep ?? 1,
|
|
1072
|
+
yStart: this.config.yStart ?? 0,
|
|
1073
|
+
yStep: this.config.yStep ?? 1
|
|
1074
|
+
});
|
|
1075
|
+
const colorStops = this.config.colorStops ?? defaultColorStops;
|
|
1076
|
+
this.heatmapSeries = new UniformHeatmapRenderableSeries(wasmContext, {
|
|
1077
|
+
dataSeries: this.heatmapDataSeries,
|
|
1078
|
+
colorMap: new HeatmapColorMap({
|
|
1079
|
+
minimum: min,
|
|
1080
|
+
maximum: max,
|
|
1081
|
+
gradientStops: colorStops
|
|
1082
|
+
})
|
|
1083
|
+
});
|
|
1084
|
+
this.surface.renderableSeries.add(this.heatmapSeries);
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Set new data for the chart (for heatmap, this updates zValues)
|
|
1088
|
+
*/
|
|
1089
|
+
setData(_data) {
|
|
1090
|
+
console.warn("HeatmapChart.setData() - use setZValues() for updating heatmap data");
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Set new z-values for the heatmap
|
|
1094
|
+
*/
|
|
1095
|
+
setZValues(zValues) {
|
|
1096
|
+
if (!this.surface) {
|
|
1097
|
+
this.config.zValues = zValues;
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
this.clearHeatmap();
|
|
1101
|
+
this.config.zValues = zValues;
|
|
1102
|
+
this.addHeatmapData(zValues);
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Update specific cell values
|
|
1106
|
+
*/
|
|
1107
|
+
updateCell(x, y, value) {
|
|
1108
|
+
if (this.heatmapDataSeries) {
|
|
1109
|
+
this.heatmapDataSeries.setZValue(x, y, value);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Clear heatmap data
|
|
1114
|
+
*/
|
|
1115
|
+
clearHeatmap() {
|
|
1116
|
+
if (!this.surface) return;
|
|
1117
|
+
if (this.heatmapSeries) {
|
|
1118
|
+
this.surface.renderableSeries.remove(this.heatmapSeries);
|
|
1119
|
+
this.heatmapSeries.delete();
|
|
1120
|
+
this.heatmapSeries = null;
|
|
1121
|
+
}
|
|
1122
|
+
if (this.heatmapDataSeries) {
|
|
1123
|
+
this.heatmapDataSeries.delete();
|
|
1124
|
+
this.heatmapDataSeries = null;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* Update chart
|
|
1129
|
+
*/
|
|
1130
|
+
update() {
|
|
1131
|
+
if (!this.surface) return;
|
|
1132
|
+
this.applyTheme();
|
|
1133
|
+
this.surface.invalidateElement();
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Destroy and clean up
|
|
1137
|
+
*/
|
|
1138
|
+
destroy() {
|
|
1139
|
+
this.clearHeatmap();
|
|
1140
|
+
super.destroy();
|
|
1141
|
+
}
|
|
1142
|
+
};
|
|
1143
|
+
async function createHeatmapChart(container, config) {
|
|
1144
|
+
const chart = new HeatmapChart(config);
|
|
1145
|
+
await chart.init(container);
|
|
1146
|
+
return chart;
|
|
1147
|
+
}
|
|
1148
|
+
var defaultColorStops2 = [
|
|
1149
|
+
{ offset: 0, color: "#1e3a8a" },
|
|
1150
|
+
// Dark blue
|
|
1151
|
+
{ offset: 0.25, color: "#3b82f6" },
|
|
1152
|
+
// Blue
|
|
1153
|
+
{ offset: 0.5, color: "#22c55e" },
|
|
1154
|
+
// Green
|
|
1155
|
+
{ offset: 0.75, color: "#eab308" },
|
|
1156
|
+
// Yellow
|
|
1157
|
+
{ offset: 1, color: "#ef4444" }
|
|
1158
|
+
// Red
|
|
1159
|
+
];
|
|
1160
|
+
var Surface3DChart = class {
|
|
1161
|
+
constructor(config) {
|
|
1162
|
+
this.container = null;
|
|
1163
|
+
this.surface = null;
|
|
1164
|
+
this.wasmContext = null;
|
|
1165
|
+
this.dataSeries = null;
|
|
1166
|
+
this.meshSeries = null;
|
|
1167
|
+
this.isDestroyed = false;
|
|
1168
|
+
this.id = config.id ?? generateId("chart3d");
|
|
1169
|
+
this.config = config;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Initialize the chart in the given container
|
|
1173
|
+
*/
|
|
1174
|
+
async init(container) {
|
|
1175
|
+
if (this.isDestroyed) {
|
|
1176
|
+
throw new Error("Cannot initialize a destroyed chart");
|
|
1177
|
+
}
|
|
1178
|
+
if (typeof container === "string") {
|
|
1179
|
+
const el = document.getElementById(container);
|
|
1180
|
+
if (!el) {
|
|
1181
|
+
throw new Error(`Container element "${container}" not found`);
|
|
1182
|
+
}
|
|
1183
|
+
this.container = el;
|
|
1184
|
+
} else {
|
|
1185
|
+
this.container = container;
|
|
1186
|
+
}
|
|
1187
|
+
if (!this.container.id) {
|
|
1188
|
+
this.container.id = this.id;
|
|
1189
|
+
}
|
|
1190
|
+
await this.createSurface();
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Create the SciChart 3D surface
|
|
1194
|
+
*/
|
|
1195
|
+
async createSurface() {
|
|
1196
|
+
if (!this.container) {
|
|
1197
|
+
throw new Error("Container not set");
|
|
1198
|
+
}
|
|
1199
|
+
const { sciChart3DSurface, wasmContext } = await SciChart3DSurface.create(
|
|
1200
|
+
this.container.id
|
|
1201
|
+
);
|
|
1202
|
+
this.surface = sciChart3DSurface;
|
|
1203
|
+
this.wasmContext = wasmContext;
|
|
1204
|
+
sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, {
|
|
1205
|
+
axisTitle: "X"
|
|
1206
|
+
});
|
|
1207
|
+
sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, {
|
|
1208
|
+
axisTitle: "Y"
|
|
1209
|
+
});
|
|
1210
|
+
sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, {
|
|
1211
|
+
axisTitle: "Z"
|
|
1212
|
+
});
|
|
1213
|
+
sciChart3DSurface.chartModifiers.add(new MouseWheelZoomModifier3D());
|
|
1214
|
+
sciChart3DSurface.chartModifiers.add(new OrbitModifier3D());
|
|
1215
|
+
const cameraPos = this.config.cameraPosition ?? { x: 300, y: 300, z: 300 };
|
|
1216
|
+
sciChart3DSurface.camera = new CameraController(wasmContext, {
|
|
1217
|
+
position: new Vector3(cameraPos.x, cameraPos.y, cameraPos.z),
|
|
1218
|
+
target: new Vector3(0, 0, 0)
|
|
1219
|
+
});
|
|
1220
|
+
this.addSurfaceData(this.config.yValues);
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Add surface data to the chart
|
|
1224
|
+
*/
|
|
1225
|
+
addSurfaceData(yValues) {
|
|
1226
|
+
if (!this.surface || !this.wasmContext) return;
|
|
1227
|
+
const wasmContext = this.wasmContext;
|
|
1228
|
+
const zSize = yValues.length;
|
|
1229
|
+
const xSize = yValues[0]?.length ?? 0;
|
|
1230
|
+
let min = Infinity;
|
|
1231
|
+
let max = -Infinity;
|
|
1232
|
+
for (let z = 0; z < zSize; z++) {
|
|
1233
|
+
for (let x = 0; x < xSize; x++) {
|
|
1234
|
+
const y = yValues[z][x];
|
|
1235
|
+
min = Math.min(min, y);
|
|
1236
|
+
max = Math.max(max, y);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
this.dataSeries = new UniformGridDataSeries3D(wasmContext, {
|
|
1240
|
+
yValues,
|
|
1241
|
+
xStep: this.config.xStep ?? 1,
|
|
1242
|
+
zStep: this.config.zStep ?? 1
|
|
1243
|
+
});
|
|
1244
|
+
const colorStops = this.config.colorStops ?? defaultColorStops2;
|
|
1245
|
+
const colorPalette = new GradientColorPalette(wasmContext, {
|
|
1246
|
+
gradientStops: colorStops
|
|
1247
|
+
});
|
|
1248
|
+
this.meshSeries = new SurfaceMeshRenderableSeries3D(wasmContext, {
|
|
1249
|
+
dataSeries: this.dataSeries,
|
|
1250
|
+
minimum: this.config.colorMin ?? min,
|
|
1251
|
+
maximum: this.config.colorMax ?? max,
|
|
1252
|
+
opacity: this.config.opacity ?? 1,
|
|
1253
|
+
cellHardnessFactor: 0,
|
|
1254
|
+
// Smooth interpolation between cells
|
|
1255
|
+
stroke: "transparent",
|
|
1256
|
+
// No wireframe stroke
|
|
1257
|
+
strokeThickness: 0,
|
|
1258
|
+
contourStroke: "transparent",
|
|
1259
|
+
// No contour lines
|
|
1260
|
+
contourStrokeThickness: 0,
|
|
1261
|
+
drawSkirt: true,
|
|
1262
|
+
// Draw skirt for solid appearance
|
|
1263
|
+
drawMeshAs: EDrawMeshAs.SOLID_MESH,
|
|
1264
|
+
// Solid filled surface
|
|
1265
|
+
lightingFactor: 0.8,
|
|
1266
|
+
meshColorPalette: colorPalette,
|
|
1267
|
+
shininess: 10
|
|
1268
|
+
});
|
|
1269
|
+
this.surface.renderableSeries.add(this.meshSeries);
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Set new Y values for the surface
|
|
1273
|
+
*/
|
|
1274
|
+
setYValues(yValues) {
|
|
1275
|
+
if (!this.surface) {
|
|
1276
|
+
this.config.yValues = yValues;
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
this.clearSurface();
|
|
1280
|
+
this.config.yValues = yValues;
|
|
1281
|
+
this.addSurfaceData(yValues);
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Set new data (alias for setYValues for consistency)
|
|
1285
|
+
*/
|
|
1286
|
+
setData(_data) {
|
|
1287
|
+
console.warn("Surface3DChart.setData() - use setYValues() for updating surface data");
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Update chart options
|
|
1291
|
+
*/
|
|
1292
|
+
setOptions(options) {
|
|
1293
|
+
this.config = { ...this.config, ...options };
|
|
1294
|
+
if (options.cameraPosition && this.surface && this.wasmContext) {
|
|
1295
|
+
const pos = options.cameraPosition;
|
|
1296
|
+
this.surface.camera = new CameraController(this.wasmContext, {
|
|
1297
|
+
position: new Vector3(pos.x, pos.y, pos.z),
|
|
1298
|
+
target: new Vector3(0, 0, 0)
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
/**
|
|
1303
|
+
* Clear surface data
|
|
1304
|
+
*/
|
|
1305
|
+
clearSurface() {
|
|
1306
|
+
if (!this.surface) return;
|
|
1307
|
+
if (this.meshSeries) {
|
|
1308
|
+
this.surface.renderableSeries.remove(this.meshSeries);
|
|
1309
|
+
this.meshSeries.delete();
|
|
1310
|
+
this.meshSeries = null;
|
|
1311
|
+
}
|
|
1312
|
+
if (this.dataSeries) {
|
|
1313
|
+
this.dataSeries.delete();
|
|
1314
|
+
this.dataSeries = null;
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* Destroy and clean up
|
|
1319
|
+
*/
|
|
1320
|
+
destroy() {
|
|
1321
|
+
if (this.isDestroyed) return;
|
|
1322
|
+
this.clearSurface();
|
|
1323
|
+
if (this.surface) {
|
|
1324
|
+
this.surface.delete();
|
|
1325
|
+
this.surface = null;
|
|
1326
|
+
}
|
|
1327
|
+
this.isDestroyed = true;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Get current configuration
|
|
1331
|
+
*/
|
|
1332
|
+
getConfig() {
|
|
1333
|
+
return { ...this.config };
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Check if chart is ready (initialized and not destroyed)
|
|
1337
|
+
*/
|
|
1338
|
+
isReady() {
|
|
1339
|
+
return this.surface !== null && !this.isDestroyed;
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
async function createSurface3DChart(container, config) {
|
|
1343
|
+
const chart = new Surface3DChart(config);
|
|
1344
|
+
await chart.init(container);
|
|
1345
|
+
return chart;
|
|
1346
|
+
}
|
|
1347
|
+
var Column3DChart = class {
|
|
1348
|
+
constructor(config) {
|
|
1349
|
+
this.container = null;
|
|
1350
|
+
this.surface = null;
|
|
1351
|
+
this.wasmContext = null;
|
|
1352
|
+
this.dataSeries = null;
|
|
1353
|
+
this.columnSeries = null;
|
|
1354
|
+
this.isDestroyed = false;
|
|
1355
|
+
this.id = config.id ?? generateId("column3d");
|
|
1356
|
+
this.config = config;
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Initialize the chart in the given container
|
|
1360
|
+
*/
|
|
1361
|
+
async init(container) {
|
|
1362
|
+
if (this.isDestroyed) {
|
|
1363
|
+
throw new Error("Cannot initialize a destroyed chart");
|
|
1364
|
+
}
|
|
1365
|
+
if (typeof container === "string") {
|
|
1366
|
+
const el = document.getElementById(container);
|
|
1367
|
+
if (!el) {
|
|
1368
|
+
throw new Error(`Container element "${container}" not found`);
|
|
1369
|
+
}
|
|
1370
|
+
this.container = el;
|
|
1371
|
+
} else {
|
|
1372
|
+
this.container = container;
|
|
1373
|
+
}
|
|
1374
|
+
if (!this.container.id) {
|
|
1375
|
+
this.container.id = this.id;
|
|
1376
|
+
}
|
|
1377
|
+
await this.createSurface();
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* Create the SciChart 3D surface
|
|
1381
|
+
*/
|
|
1382
|
+
async createSurface() {
|
|
1383
|
+
if (!this.container) {
|
|
1384
|
+
throw new Error("Container not set");
|
|
1385
|
+
}
|
|
1386
|
+
const { sciChart3DSurface, wasmContext } = await SciChart3DSurface.create(
|
|
1387
|
+
this.container.id,
|
|
1388
|
+
{
|
|
1389
|
+
isZYPlaneVisible: false
|
|
1390
|
+
}
|
|
1391
|
+
);
|
|
1392
|
+
this.surface = sciChart3DSurface;
|
|
1393
|
+
this.wasmContext = wasmContext;
|
|
1394
|
+
const cameraPos = this.config.cameraPosition ?? { x: -250, y: 450, z: 280 };
|
|
1395
|
+
const cameraTarget = this.config.cameraTarget ?? { x: 0, y: 0, z: 0 };
|
|
1396
|
+
sciChart3DSurface.camera = new CameraController(wasmContext, {
|
|
1397
|
+
position: new Vector3(cameraPos.x, cameraPos.y, cameraPos.z),
|
|
1398
|
+
target: new Vector3(cameraTarget.x, cameraTarget.y, cameraTarget.z)
|
|
1399
|
+
});
|
|
1400
|
+
sciChart3DSurface.chartModifiers.add(
|
|
1401
|
+
new OrbitModifier3D(),
|
|
1402
|
+
new MouseWheelZoomModifier3D()
|
|
1403
|
+
);
|
|
1404
|
+
const xRange = this.config.xRange ?? { min: 0, max: 360 };
|
|
1405
|
+
const yRange = this.config.yRange ?? { min: 0, max: 5e3 };
|
|
1406
|
+
const zRange = this.config.zRange ?? { min: 0, max: 50 };
|
|
1407
|
+
const baseAxisOptions = {
|
|
1408
|
+
drawMinorGridLines: false,
|
|
1409
|
+
majorGridLineStyle: { color: "#7e7e7e" },
|
|
1410
|
+
planeBorderThickness: 3
|
|
1411
|
+
};
|
|
1412
|
+
sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, {
|
|
1413
|
+
...baseAxisOptions,
|
|
1414
|
+
axisTitle: this.config.xAxisTitle ?? "Phase Angle (\xB0)",
|
|
1415
|
+
autoTicks: false,
|
|
1416
|
+
visibleRange: new NumberRange(xRange.min, xRange.max),
|
|
1417
|
+
majorDelta: 45,
|
|
1418
|
+
minorDelta: 15,
|
|
1419
|
+
flippedCoordinates: true,
|
|
1420
|
+
axisBandsFill: "#d2d2d2"
|
|
1421
|
+
});
|
|
1422
|
+
sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, {
|
|
1423
|
+
...baseAxisOptions,
|
|
1424
|
+
axisTitle: this.config.yAxisTitle ?? "Amplitude (mVp)",
|
|
1425
|
+
visibleRange: new NumberRange(yRange.min, yRange.max),
|
|
1426
|
+
axisBandsFill: "#b1b1b1"
|
|
1427
|
+
});
|
|
1428
|
+
sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, {
|
|
1429
|
+
...baseAxisOptions,
|
|
1430
|
+
axisTitle: this.config.zAxisTitle ?? "Cycle",
|
|
1431
|
+
majorDelta: 10,
|
|
1432
|
+
minorDelta: 5,
|
|
1433
|
+
visibleRange: new NumberRange(zRange.min, zRange.max),
|
|
1434
|
+
axisBandsFill: "#d0d0d0",
|
|
1435
|
+
labelPrecision: 0
|
|
1436
|
+
});
|
|
1437
|
+
this.addColumnData(this.config.data);
|
|
1438
|
+
if (this.config.showSineWave !== false) {
|
|
1439
|
+
this.addSineWave();
|
|
1440
|
+
}
|
|
1441
|
+
this.addTooltip();
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Add column data to the chart
|
|
1445
|
+
*/
|
|
1446
|
+
addColumnData(data) {
|
|
1447
|
+
if (!this.surface || !this.wasmContext) return;
|
|
1448
|
+
const wasmContext = this.wasmContext;
|
|
1449
|
+
this.dataSeries = new XyzDataSeries3D(wasmContext);
|
|
1450
|
+
data.forEach(([x, y, z]) => {
|
|
1451
|
+
this.dataSeries.append(x, y, z);
|
|
1452
|
+
});
|
|
1453
|
+
this.columnSeries = new ColumnRenderableSeries3D(wasmContext, {
|
|
1454
|
+
dataSeries: this.dataSeries,
|
|
1455
|
+
fill: this.config.barFill ?? "#52aaf2",
|
|
1456
|
+
stroke: this.config.barStroke ?? "#52aaf2",
|
|
1457
|
+
opacity: this.config.barOpacity ?? 0.95,
|
|
1458
|
+
dataPointWidthX: this.config.barWidthX ?? 8,
|
|
1459
|
+
dataPointWidthZ: this.config.barWidthZ ?? 8
|
|
1460
|
+
});
|
|
1461
|
+
this.surface.renderableSeries.add(this.columnSeries);
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Add sine wave reference line on back plane
|
|
1465
|
+
*/
|
|
1466
|
+
addSineWave() {
|
|
1467
|
+
if (!this.surface || !this.wasmContext) return;
|
|
1468
|
+
const wasmContext = this.wasmContext;
|
|
1469
|
+
const sineData = new XyzDataSeries3D(wasmContext);
|
|
1470
|
+
const backPlaneZ = 0;
|
|
1471
|
+
const center = this.config.sineWaveCenter ?? 2e3;
|
|
1472
|
+
const amplitude = this.config.sineWaveAmplitude ?? 2e3;
|
|
1473
|
+
for (let deg = 0; deg <= 360; deg += 5) {
|
|
1474
|
+
const rad = deg * Math.PI / 180;
|
|
1475
|
+
const y = center + amplitude * Math.sin(rad);
|
|
1476
|
+
sineData.append(deg, y, backPlaneZ);
|
|
1477
|
+
}
|
|
1478
|
+
const sineSeries = new PointLineRenderableSeries3D(wasmContext, {
|
|
1479
|
+
dataSeries: sineData,
|
|
1480
|
+
stroke: "black",
|
|
1481
|
+
strokeThickness: 3,
|
|
1482
|
+
opacity: 1
|
|
1483
|
+
});
|
|
1484
|
+
this.surface.renderableSeries.add(sineSeries);
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Add tooltip modifier
|
|
1488
|
+
*/
|
|
1489
|
+
addTooltip() {
|
|
1490
|
+
if (!this.surface) return;
|
|
1491
|
+
const xTitle = this.config.xAxisTitle ?? "Phase Angle";
|
|
1492
|
+
const yTitle = this.config.yAxisTitle ?? "Amplitude";
|
|
1493
|
+
const zTitle = this.config.zAxisTitle ?? "Cycle";
|
|
1494
|
+
const tooltipModifier = new TooltipModifier3D({
|
|
1495
|
+
tooltipDataTemplate: (seriesInfo) => {
|
|
1496
|
+
const valuesWithLabels = [];
|
|
1497
|
+
if (seriesInfo && seriesInfo.isHit) {
|
|
1498
|
+
valuesWithLabels.push(`${xTitle}: ${seriesInfo.xValue}`);
|
|
1499
|
+
valuesWithLabels.push(`${yTitle}: ${seriesInfo.yValue}`);
|
|
1500
|
+
valuesWithLabels.push(`${zTitle}: ${seriesInfo.zValue}`);
|
|
1501
|
+
}
|
|
1502
|
+
return valuesWithLabels;
|
|
1503
|
+
}
|
|
1504
|
+
});
|
|
1505
|
+
this.surface.chartModifiers.add(tooltipModifier);
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Set new data for the chart
|
|
1509
|
+
*/
|
|
1510
|
+
setData(data) {
|
|
1511
|
+
if (!this.dataSeries) {
|
|
1512
|
+
this.config.data = data;
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
this.dataSeries.clear();
|
|
1516
|
+
data.forEach(([x, y, z]) => {
|
|
1517
|
+
this.dataSeries.append(x, y, z);
|
|
1518
|
+
});
|
|
1519
|
+
if (this.surface) {
|
|
1520
|
+
this.surface.invalidateElement();
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* Update camera position
|
|
1525
|
+
*/
|
|
1526
|
+
setCameraPosition(position, target) {
|
|
1527
|
+
if (!this.surface || !this.wasmContext) return;
|
|
1528
|
+
this.surface.camera.position = new Vector3(position.x, position.y, position.z);
|
|
1529
|
+
if (target) {
|
|
1530
|
+
this.surface.camera.target = new Vector3(target.x, target.y, target.z);
|
|
1531
|
+
}
|
|
1532
|
+
this.surface.invalidateElement();
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* Update chart options
|
|
1536
|
+
*/
|
|
1537
|
+
setOptions(options) {
|
|
1538
|
+
this.config = { ...this.config, ...options };
|
|
1539
|
+
if (options.cameraPosition && this.surface && this.wasmContext) {
|
|
1540
|
+
const pos = options.cameraPosition;
|
|
1541
|
+
const target = options.cameraTarget ?? { x: 0, y: 0, z: 0 };
|
|
1542
|
+
this.setCameraPosition(pos, target);
|
|
1543
|
+
}
|
|
1544
|
+
if (options.barFill || options.barStroke || options.barOpacity) {
|
|
1545
|
+
if (this.columnSeries) {
|
|
1546
|
+
if (options.barFill) this.columnSeries.fill = options.barFill;
|
|
1547
|
+
if (options.barStroke) this.columnSeries.stroke = options.barStroke;
|
|
1548
|
+
if (options.barOpacity !== void 0) this.columnSeries.opacity = options.barOpacity;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
/**
|
|
1553
|
+
* Get the SciChart surface for advanced operations
|
|
1554
|
+
*/
|
|
1555
|
+
getSurface() {
|
|
1556
|
+
return this.surface;
|
|
1557
|
+
}
|
|
1558
|
+
/**
|
|
1559
|
+
* Destroy and clean up
|
|
1560
|
+
*/
|
|
1561
|
+
destroy() {
|
|
1562
|
+
if (this.isDestroyed) return;
|
|
1563
|
+
if (this.surface) {
|
|
1564
|
+
this.surface.delete();
|
|
1565
|
+
this.surface = null;
|
|
1566
|
+
}
|
|
1567
|
+
this.isDestroyed = true;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Get current configuration
|
|
1571
|
+
*/
|
|
1572
|
+
getConfig() {
|
|
1573
|
+
return { ...this.config };
|
|
1574
|
+
}
|
|
1575
|
+
/**
|
|
1576
|
+
* Check if chart is ready (initialized and not destroyed)
|
|
1577
|
+
*/
|
|
1578
|
+
isReady() {
|
|
1579
|
+
return this.surface !== null && !this.isDestroyed;
|
|
1580
|
+
}
|
|
1581
|
+
};
|
|
1582
|
+
async function createColumn3DChart(container, config) {
|
|
1583
|
+
const chart = new Column3DChart(config);
|
|
1584
|
+
await chart.init(container);
|
|
1585
|
+
return chart;
|
|
1586
|
+
}
|
|
1587
|
+
var VERSION = "0.1.0";
|
|
1588
|
+
function configureSciChart(options) {
|
|
1589
|
+
if (options.wasmUrl || options.dataUrl) {
|
|
1590
|
+
const { SciChartSurface: SciChartSurface6 } = __require("scichart");
|
|
1591
|
+
SciChartSurface6.configure({
|
|
1592
|
+
wasmUrl: options.wasmUrl,
|
|
1593
|
+
dataUrl: options.dataUrl
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
export { AreaChart, BarChart, BaseChart, Column3DChart, HeatmapChart, LineChart, Surface3DChart, VERSION, calculateDataRange, clamp, configureSciChart, createAreaChart, createBarChart, createColumn3DChart, createHeatmapChart, createLineChart, createSurface3DChart, debounce, deepMerge, extractXValues, extractYValues, formatNumber, generateId, hexToRgba, lerp, normalizeDataPoints, parseSize, throttle };
|
|
1599
|
+
//# sourceMappingURL=index.mjs.map
|
|
1600
|
+
//# sourceMappingURL=index.mjs.map
|