@opendata-ai/openchart-vue 2.0.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 +98 -0
- package/dist/index.d.ts +521 -0
- package/dist/index.js +715 -0
- package/dist/index.js.map +1 -0
- package/package.json +60 -0
- package/src/Chart.ts +187 -0
- package/src/DataTable.ts +194 -0
- package/src/Graph.ts +179 -0
- package/src/ThemeProvider.ts +41 -0
- package/src/Visualization.ts +61 -0
- package/src/__tests__/Chart.test.ts +139 -0
- package/src/__tests__/DataTable.test.ts +131 -0
- package/src/__tests__/Graph.test.ts +133 -0
- package/src/__tests__/ThemeContext.test.ts +266 -0
- package/src/__tests__/composables.test.ts +158 -0
- package/src/__tests__/useTableState.test.ts +256 -0
- package/src/composables/useChart.ts +95 -0
- package/src/composables/useDarkMode.ts +71 -0
- package/src/composables/useGraph.ts +89 -0
- package/src/composables/useTable.ts +88 -0
- package/src/composables/useTableState.ts +80 -0
- package/src/context.ts +33 -0
- package/src/index.ts +41 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
// src/Chart.ts
|
|
2
|
+
import { createChart } from "@opendata-ai/openchart-vanilla";
|
|
3
|
+
import {
|
|
4
|
+
defineComponent,
|
|
5
|
+
getCurrentInstance,
|
|
6
|
+
h,
|
|
7
|
+
inject as inject2,
|
|
8
|
+
onMounted,
|
|
9
|
+
onUnmounted,
|
|
10
|
+
ref,
|
|
11
|
+
watch
|
|
12
|
+
} from "vue";
|
|
13
|
+
|
|
14
|
+
// src/context.ts
|
|
15
|
+
import { computed, inject } from "vue";
|
|
16
|
+
var VizThemeKey = /* @__PURE__ */ Symbol("VizTheme");
|
|
17
|
+
var VizDarkModeKey = /* @__PURE__ */ Symbol("VizDarkMode");
|
|
18
|
+
function useVizTheme() {
|
|
19
|
+
const theme = inject(VizThemeKey, void 0);
|
|
20
|
+
return computed(() => theme?.value);
|
|
21
|
+
}
|
|
22
|
+
function useVizDarkMode() {
|
|
23
|
+
const darkMode = inject(VizDarkModeKey, void 0);
|
|
24
|
+
return computed(() => darkMode?.value);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// src/Chart.ts
|
|
28
|
+
var Chart = defineComponent({
|
|
29
|
+
name: "Chart",
|
|
30
|
+
props: {
|
|
31
|
+
spec: {
|
|
32
|
+
type: Object,
|
|
33
|
+
required: true
|
|
34
|
+
},
|
|
35
|
+
theme: {
|
|
36
|
+
type: Object,
|
|
37
|
+
default: void 0
|
|
38
|
+
},
|
|
39
|
+
darkMode: {
|
|
40
|
+
type: String,
|
|
41
|
+
default: void 0
|
|
42
|
+
},
|
|
43
|
+
class: {
|
|
44
|
+
type: String,
|
|
45
|
+
default: void 0
|
|
46
|
+
},
|
|
47
|
+
style: {
|
|
48
|
+
type: [String, Object],
|
|
49
|
+
default: void 0
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
emits: {
|
|
53
|
+
"mark-click": (_event) => true,
|
|
54
|
+
"mark-hover": (_event) => true,
|
|
55
|
+
"mark-leave": () => true,
|
|
56
|
+
"legend-toggle": (_series, _visible) => true,
|
|
57
|
+
"annotation-click": (_annotation, _event) => true,
|
|
58
|
+
"annotation-edit": (_annotation, _updatedOffset) => true,
|
|
59
|
+
edit: (_edit) => true,
|
|
60
|
+
"data-point-click": (_data) => true
|
|
61
|
+
},
|
|
62
|
+
setup(props, { emit }) {
|
|
63
|
+
const containerRef = ref(null);
|
|
64
|
+
let instance = null;
|
|
65
|
+
let prevSpec = "";
|
|
66
|
+
const contextTheme = inject2(VizThemeKey, void 0);
|
|
67
|
+
const contextDarkMode = inject2(VizDarkModeKey, void 0);
|
|
68
|
+
const vm = getCurrentInstance();
|
|
69
|
+
const vnodeProps = vm?.vnode.props ?? {};
|
|
70
|
+
const hasAnnotationEditListener = "onAnnotation-edit" in vnodeProps || "onAnnotationEdit" in vnodeProps;
|
|
71
|
+
const hasEditListener = "onEdit" in vnodeProps;
|
|
72
|
+
function resolveTheme() {
|
|
73
|
+
return props.theme ?? contextTheme?.value;
|
|
74
|
+
}
|
|
75
|
+
function resolveDarkMode() {
|
|
76
|
+
return props.darkMode ?? contextDarkMode?.value;
|
|
77
|
+
}
|
|
78
|
+
function mountChart() {
|
|
79
|
+
const container = containerRef.value;
|
|
80
|
+
if (!container) return;
|
|
81
|
+
const options = {
|
|
82
|
+
theme: resolveTheme(),
|
|
83
|
+
darkMode: resolveDarkMode(),
|
|
84
|
+
onDataPointClick: (data) => emit("data-point-click", data),
|
|
85
|
+
onMarkClick: (event) => emit("mark-click", event),
|
|
86
|
+
onMarkHover: (event) => emit("mark-hover", event),
|
|
87
|
+
onMarkLeave: () => emit("mark-leave"),
|
|
88
|
+
onLegendToggle: (series, visible) => emit("legend-toggle", series, visible),
|
|
89
|
+
onAnnotationClick: (annotation, event) => emit("annotation-click", annotation, event),
|
|
90
|
+
// Only include editing callbacks when the parent binds a listener.
|
|
91
|
+
// Without this gate, every chart gets drag editing wired up.
|
|
92
|
+
...hasAnnotationEditListener ? {
|
|
93
|
+
onAnnotationEdit: (annotation, updatedOffset) => emit("annotation-edit", annotation, updatedOffset)
|
|
94
|
+
} : {},
|
|
95
|
+
...hasEditListener ? { onEdit: (edit) => emit("edit", edit) } : {},
|
|
96
|
+
responsive: true
|
|
97
|
+
};
|
|
98
|
+
instance = createChart(container, props.spec, options);
|
|
99
|
+
prevSpec = JSON.stringify(props.spec);
|
|
100
|
+
}
|
|
101
|
+
function destroyChart() {
|
|
102
|
+
instance?.destroy();
|
|
103
|
+
instance = null;
|
|
104
|
+
prevSpec = "";
|
|
105
|
+
}
|
|
106
|
+
onMounted(() => {
|
|
107
|
+
mountChart();
|
|
108
|
+
});
|
|
109
|
+
onUnmounted(() => {
|
|
110
|
+
destroyChart();
|
|
111
|
+
});
|
|
112
|
+
watch(
|
|
113
|
+
() => JSON.stringify(props.spec),
|
|
114
|
+
(newVal) => {
|
|
115
|
+
if (!instance) return;
|
|
116
|
+
if (newVal !== prevSpec) {
|
|
117
|
+
prevSpec = newVal;
|
|
118
|
+
instance.update(props.spec);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
);
|
|
122
|
+
watch(
|
|
123
|
+
[
|
|
124
|
+
() => props.theme,
|
|
125
|
+
() => props.darkMode,
|
|
126
|
+
() => contextTheme?.value,
|
|
127
|
+
() => contextDarkMode?.value
|
|
128
|
+
],
|
|
129
|
+
() => {
|
|
130
|
+
if (!containerRef.value) return;
|
|
131
|
+
destroyChart();
|
|
132
|
+
mountChart();
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
const rootClass = () => {
|
|
136
|
+
const base = "viz-chart-root";
|
|
137
|
+
return props.class ? `${base} ${props.class}` : base;
|
|
138
|
+
};
|
|
139
|
+
return () => h("div", {
|
|
140
|
+
ref: containerRef,
|
|
141
|
+
class: rootClass(),
|
|
142
|
+
style: props.style
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// src/composables/useChart.ts
|
|
148
|
+
import { createChart as createChart2 } from "@opendata-ai/openchart-vanilla";
|
|
149
|
+
import { onMounted as onMounted2, onUnmounted as onUnmounted2, ref as ref2, shallowRef, watch as watch2 } from "vue";
|
|
150
|
+
function useChart(spec, options) {
|
|
151
|
+
const containerRef = ref2(null);
|
|
152
|
+
const chart = shallowRef(null);
|
|
153
|
+
const layout = shallowRef(null);
|
|
154
|
+
function mount() {
|
|
155
|
+
const container = containerRef.value;
|
|
156
|
+
if (!container) return;
|
|
157
|
+
const mountOpts = {
|
|
158
|
+
theme: options?.theme,
|
|
159
|
+
darkMode: options?.darkMode,
|
|
160
|
+
onDataPointClick: options?.onDataPointClick,
|
|
161
|
+
responsive: options?.responsive
|
|
162
|
+
};
|
|
163
|
+
const instance = createChart2(container, spec.value, mountOpts);
|
|
164
|
+
chart.value = instance;
|
|
165
|
+
layout.value = instance.layout;
|
|
166
|
+
}
|
|
167
|
+
function destroy() {
|
|
168
|
+
chart.value?.destroy();
|
|
169
|
+
chart.value = null;
|
|
170
|
+
layout.value = null;
|
|
171
|
+
}
|
|
172
|
+
onMounted2(() => {
|
|
173
|
+
mount();
|
|
174
|
+
});
|
|
175
|
+
onUnmounted2(() => {
|
|
176
|
+
destroy();
|
|
177
|
+
});
|
|
178
|
+
watch2(spec, (newSpec) => {
|
|
179
|
+
const instance = chart.value;
|
|
180
|
+
if (!instance) return;
|
|
181
|
+
instance.update(newSpec);
|
|
182
|
+
layout.value = instance.layout;
|
|
183
|
+
});
|
|
184
|
+
return {
|
|
185
|
+
containerRef,
|
|
186
|
+
chart,
|
|
187
|
+
layout
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/composables/useDarkMode.ts
|
|
192
|
+
import { onUnmounted as onUnmounted3, ref as ref3, watch as watch3 } from "vue";
|
|
193
|
+
function useDarkMode(mode) {
|
|
194
|
+
const isDark = ref3(resolveInitial(mode.value));
|
|
195
|
+
let cleanup = null;
|
|
196
|
+
function setup(currentMode) {
|
|
197
|
+
cleanup?.();
|
|
198
|
+
cleanup = null;
|
|
199
|
+
if (currentMode !== "auto") {
|
|
200
|
+
isDark.value = currentMode === "force";
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (typeof window === "undefined" || !window.matchMedia) {
|
|
204
|
+
isDark.value = false;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
208
|
+
isDark.value = mq.matches;
|
|
209
|
+
const handler = (e) => {
|
|
210
|
+
isDark.value = e.matches;
|
|
211
|
+
};
|
|
212
|
+
mq.addEventListener("change", handler);
|
|
213
|
+
cleanup = () => mq.removeEventListener("change", handler);
|
|
214
|
+
}
|
|
215
|
+
setup(mode.value);
|
|
216
|
+
watch3(mode, (newMode) => {
|
|
217
|
+
setup(newMode);
|
|
218
|
+
});
|
|
219
|
+
onUnmounted3(() => {
|
|
220
|
+
cleanup?.();
|
|
221
|
+
cleanup = null;
|
|
222
|
+
});
|
|
223
|
+
return isDark;
|
|
224
|
+
}
|
|
225
|
+
function resolveInitial(mode) {
|
|
226
|
+
if (mode === "force") return true;
|
|
227
|
+
if (mode === "off" || mode === void 0) return false;
|
|
228
|
+
if (typeof window !== "undefined" && window.matchMedia) {
|
|
229
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
230
|
+
}
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// src/composables/useGraph.ts
|
|
235
|
+
import { ref as ref4 } from "vue";
|
|
236
|
+
function useGraph() {
|
|
237
|
+
const graphRef = ref4(null);
|
|
238
|
+
function search(query) {
|
|
239
|
+
graphRef.value?.search(query);
|
|
240
|
+
}
|
|
241
|
+
function clearSearch() {
|
|
242
|
+
graphRef.value?.clearSearch();
|
|
243
|
+
}
|
|
244
|
+
function zoomToFit() {
|
|
245
|
+
graphRef.value?.zoomToFit();
|
|
246
|
+
}
|
|
247
|
+
function zoomToNode(nodeId) {
|
|
248
|
+
graphRef.value?.zoomToNode(nodeId);
|
|
249
|
+
}
|
|
250
|
+
function selectNode(nodeId) {
|
|
251
|
+
graphRef.value?.selectNode(nodeId);
|
|
252
|
+
}
|
|
253
|
+
function getSelectedNodes() {
|
|
254
|
+
return graphRef.value?.getSelectedNodes() ?? [];
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
graphRef,
|
|
258
|
+
search,
|
|
259
|
+
clearSearch,
|
|
260
|
+
zoomToFit,
|
|
261
|
+
zoomToNode,
|
|
262
|
+
selectNode,
|
|
263
|
+
getSelectedNodes
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// src/composables/useTable.ts
|
|
268
|
+
import {
|
|
269
|
+
createTable
|
|
270
|
+
} from "@opendata-ai/openchart-vanilla";
|
|
271
|
+
import { onMounted as onMounted3, onUnmounted as onUnmounted4, ref as ref5, shallowRef as shallowRef2, watch as watch4 } from "vue";
|
|
272
|
+
function useTable(spec, options) {
|
|
273
|
+
const containerRef = ref5(null);
|
|
274
|
+
const table = shallowRef2(null);
|
|
275
|
+
const state = ref5({
|
|
276
|
+
sort: null,
|
|
277
|
+
search: "",
|
|
278
|
+
page: 0
|
|
279
|
+
});
|
|
280
|
+
const originalOnStateChange = options?.onStateChange;
|
|
281
|
+
function handleStateChange(newState) {
|
|
282
|
+
state.value = newState;
|
|
283
|
+
originalOnStateChange?.(newState);
|
|
284
|
+
}
|
|
285
|
+
function mount() {
|
|
286
|
+
const container = containerRef.value;
|
|
287
|
+
if (!container) return;
|
|
288
|
+
const mountOpts = {
|
|
289
|
+
...options,
|
|
290
|
+
onStateChange: handleStateChange
|
|
291
|
+
};
|
|
292
|
+
const instance = createTable(container, spec.value, mountOpts);
|
|
293
|
+
table.value = instance;
|
|
294
|
+
state.value = instance.getState();
|
|
295
|
+
}
|
|
296
|
+
function destroy() {
|
|
297
|
+
table.value?.destroy();
|
|
298
|
+
table.value = null;
|
|
299
|
+
}
|
|
300
|
+
onMounted3(() => {
|
|
301
|
+
mount();
|
|
302
|
+
});
|
|
303
|
+
onUnmounted4(() => {
|
|
304
|
+
destroy();
|
|
305
|
+
});
|
|
306
|
+
watch4(spec, (newSpec) => {
|
|
307
|
+
const instance = table.value;
|
|
308
|
+
if (!instance) return;
|
|
309
|
+
instance.update(newSpec);
|
|
310
|
+
state.value = instance.getState();
|
|
311
|
+
});
|
|
312
|
+
return {
|
|
313
|
+
containerRef,
|
|
314
|
+
table,
|
|
315
|
+
state
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// src/composables/useTableState.ts
|
|
320
|
+
import { ref as ref6 } from "vue";
|
|
321
|
+
function useTableState(initialState) {
|
|
322
|
+
const sort = ref6(initialState?.sort ?? null);
|
|
323
|
+
const search = ref6(initialState?.search ?? "");
|
|
324
|
+
const page = ref6(initialState?.page ?? 0);
|
|
325
|
+
function setSort(newSort) {
|
|
326
|
+
sort.value = newSort;
|
|
327
|
+
}
|
|
328
|
+
function setSearch(query) {
|
|
329
|
+
search.value = query;
|
|
330
|
+
}
|
|
331
|
+
function setPage(newPage) {
|
|
332
|
+
page.value = newPage;
|
|
333
|
+
}
|
|
334
|
+
function resetState() {
|
|
335
|
+
sort.value = initialState?.sort ?? null;
|
|
336
|
+
search.value = initialState?.search ?? "";
|
|
337
|
+
page.value = initialState?.page ?? 0;
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
sort,
|
|
341
|
+
setSort,
|
|
342
|
+
search,
|
|
343
|
+
setSearch,
|
|
344
|
+
page,
|
|
345
|
+
setPage,
|
|
346
|
+
resetState
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/DataTable.ts
|
|
351
|
+
import {
|
|
352
|
+
createTable as createTable2
|
|
353
|
+
} from "@opendata-ai/openchart-vanilla";
|
|
354
|
+
import {
|
|
355
|
+
defineComponent as defineComponent2,
|
|
356
|
+
h as h2,
|
|
357
|
+
inject as inject3,
|
|
358
|
+
onMounted as onMounted4,
|
|
359
|
+
onUnmounted as onUnmounted5,
|
|
360
|
+
ref as ref7,
|
|
361
|
+
watch as watch5
|
|
362
|
+
} from "vue";
|
|
363
|
+
var DataTable = defineComponent2({
|
|
364
|
+
name: "DataTable",
|
|
365
|
+
props: {
|
|
366
|
+
spec: {
|
|
367
|
+
type: Object,
|
|
368
|
+
required: true
|
|
369
|
+
},
|
|
370
|
+
theme: {
|
|
371
|
+
type: Object,
|
|
372
|
+
default: void 0
|
|
373
|
+
},
|
|
374
|
+
darkMode: {
|
|
375
|
+
type: String,
|
|
376
|
+
default: void 0
|
|
377
|
+
},
|
|
378
|
+
class: {
|
|
379
|
+
type: String,
|
|
380
|
+
default: void 0
|
|
381
|
+
},
|
|
382
|
+
style: {
|
|
383
|
+
type: [String, Object],
|
|
384
|
+
default: void 0
|
|
385
|
+
},
|
|
386
|
+
sort: {
|
|
387
|
+
type: [Object, null],
|
|
388
|
+
default: void 0
|
|
389
|
+
},
|
|
390
|
+
search: {
|
|
391
|
+
type: String,
|
|
392
|
+
default: void 0
|
|
393
|
+
},
|
|
394
|
+
page: {
|
|
395
|
+
type: Number,
|
|
396
|
+
default: void 0
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
emits: {
|
|
400
|
+
"row-click": (_row) => true,
|
|
401
|
+
"update:sort": (_sort) => true,
|
|
402
|
+
"update:search": (_query) => true,
|
|
403
|
+
"update:page": (_page) => true
|
|
404
|
+
},
|
|
405
|
+
setup(props, { emit }) {
|
|
406
|
+
const containerRef = ref7(null);
|
|
407
|
+
let instance = null;
|
|
408
|
+
const contextTheme = inject3(VizThemeKey, void 0);
|
|
409
|
+
const contextDarkMode = inject3(VizDarkModeKey, void 0);
|
|
410
|
+
function resolveTheme() {
|
|
411
|
+
return props.theme ?? contextTheme?.value;
|
|
412
|
+
}
|
|
413
|
+
function resolveDarkMode() {
|
|
414
|
+
return props.darkMode ?? contextDarkMode?.value;
|
|
415
|
+
}
|
|
416
|
+
function isControlled() {
|
|
417
|
+
return props.sort !== void 0 || props.search !== void 0 || props.page !== void 0;
|
|
418
|
+
}
|
|
419
|
+
let prevSpec = "";
|
|
420
|
+
function mountTable() {
|
|
421
|
+
const container = containerRef.value;
|
|
422
|
+
if (!container) return;
|
|
423
|
+
const mountOptions = {
|
|
424
|
+
theme: resolveTheme(),
|
|
425
|
+
darkMode: resolveDarkMode(),
|
|
426
|
+
onRowClick: (row) => emit("row-click", row),
|
|
427
|
+
responsive: true,
|
|
428
|
+
onStateChange: (state) => {
|
|
429
|
+
if (state.sort !== void 0) emit("update:sort", state.sort);
|
|
430
|
+
if (state.search !== void 0) emit("update:search", state.search);
|
|
431
|
+
if (state.page !== void 0) emit("update:page", state.page);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
if (isControlled()) {
|
|
435
|
+
mountOptions.externalState = {
|
|
436
|
+
sort: props.sort ?? null,
|
|
437
|
+
search: props.search ?? "",
|
|
438
|
+
page: props.page ?? 0
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
instance = createTable2(container, props.spec, mountOptions);
|
|
442
|
+
prevSpec = JSON.stringify(props.spec);
|
|
443
|
+
}
|
|
444
|
+
function destroyTable() {
|
|
445
|
+
instance?.destroy();
|
|
446
|
+
instance = null;
|
|
447
|
+
prevSpec = "";
|
|
448
|
+
}
|
|
449
|
+
onMounted4(() => {
|
|
450
|
+
mountTable();
|
|
451
|
+
});
|
|
452
|
+
onUnmounted5(() => {
|
|
453
|
+
destroyTable();
|
|
454
|
+
});
|
|
455
|
+
watch5(
|
|
456
|
+
() => JSON.stringify(props.spec),
|
|
457
|
+
(newVal) => {
|
|
458
|
+
if (!instance) return;
|
|
459
|
+
if (newVal !== prevSpec) {
|
|
460
|
+
prevSpec = newVal;
|
|
461
|
+
instance.update(props.spec);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
);
|
|
465
|
+
watch5(
|
|
466
|
+
[
|
|
467
|
+
() => props.theme,
|
|
468
|
+
() => props.darkMode,
|
|
469
|
+
() => contextTheme?.value,
|
|
470
|
+
() => contextDarkMode?.value
|
|
471
|
+
],
|
|
472
|
+
() => {
|
|
473
|
+
if (!containerRef.value) return;
|
|
474
|
+
destroyTable();
|
|
475
|
+
mountTable();
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
watch5([() => props.sort, () => props.search, () => props.page], () => {
|
|
479
|
+
if (!instance || !isControlled()) return;
|
|
480
|
+
instance.setState({
|
|
481
|
+
sort: props.sort ?? null,
|
|
482
|
+
search: props.search ?? "",
|
|
483
|
+
page: props.page ?? 0
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
const rootClass = () => {
|
|
487
|
+
const base = "viz-table-root";
|
|
488
|
+
return props.class ? `${base} ${props.class}` : base;
|
|
489
|
+
};
|
|
490
|
+
return () => h2("div", {
|
|
491
|
+
ref: containerRef,
|
|
492
|
+
class: rootClass(),
|
|
493
|
+
style: props.style
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// src/Graph.ts
|
|
499
|
+
import {
|
|
500
|
+
createGraph
|
|
501
|
+
} from "@opendata-ai/openchart-vanilla";
|
|
502
|
+
import {
|
|
503
|
+
defineComponent as defineComponent3,
|
|
504
|
+
h as h3,
|
|
505
|
+
inject as inject4,
|
|
506
|
+
onMounted as onMounted5,
|
|
507
|
+
onUnmounted as onUnmounted6,
|
|
508
|
+
ref as ref8,
|
|
509
|
+
watch as watch6
|
|
510
|
+
} from "vue";
|
|
511
|
+
var Graph = defineComponent3({
|
|
512
|
+
name: "Graph",
|
|
513
|
+
props: {
|
|
514
|
+
spec: {
|
|
515
|
+
type: Object,
|
|
516
|
+
required: true
|
|
517
|
+
},
|
|
518
|
+
theme: {
|
|
519
|
+
type: Object,
|
|
520
|
+
default: void 0
|
|
521
|
+
},
|
|
522
|
+
darkMode: {
|
|
523
|
+
type: String,
|
|
524
|
+
default: void 0
|
|
525
|
+
},
|
|
526
|
+
class: {
|
|
527
|
+
type: String,
|
|
528
|
+
default: void 0
|
|
529
|
+
},
|
|
530
|
+
style: {
|
|
531
|
+
type: [String, Object],
|
|
532
|
+
default: void 0
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
emits: {
|
|
536
|
+
"node-click": (_node) => true,
|
|
537
|
+
"node-double-click": (_node) => true,
|
|
538
|
+
"selection-change": (_nodeIds) => true
|
|
539
|
+
},
|
|
540
|
+
setup(props, { emit, expose }) {
|
|
541
|
+
const containerRef = ref8(null);
|
|
542
|
+
let instance = null;
|
|
543
|
+
let prevSpec = "";
|
|
544
|
+
const contextTheme = inject4(VizThemeKey, void 0);
|
|
545
|
+
const contextDarkMode = inject4(VizDarkModeKey, void 0);
|
|
546
|
+
function resolveTheme() {
|
|
547
|
+
return props.theme ?? contextTheme?.value;
|
|
548
|
+
}
|
|
549
|
+
function resolveDarkMode() {
|
|
550
|
+
return props.darkMode ?? contextDarkMode?.value;
|
|
551
|
+
}
|
|
552
|
+
function mountGraph() {
|
|
553
|
+
const container = containerRef.value;
|
|
554
|
+
if (!container) return;
|
|
555
|
+
const options = {
|
|
556
|
+
theme: resolveTheme(),
|
|
557
|
+
darkMode: resolveDarkMode(),
|
|
558
|
+
onNodeClick: (node) => emit("node-click", node),
|
|
559
|
+
onNodeDoubleClick: (node) => emit("node-double-click", node),
|
|
560
|
+
onSelectionChange: (nodeIds) => emit("selection-change", nodeIds),
|
|
561
|
+
responsive: true
|
|
562
|
+
};
|
|
563
|
+
instance = createGraph(container, props.spec, options);
|
|
564
|
+
prevSpec = JSON.stringify(props.spec);
|
|
565
|
+
}
|
|
566
|
+
function destroyGraph() {
|
|
567
|
+
instance?.destroy();
|
|
568
|
+
instance = null;
|
|
569
|
+
prevSpec = "";
|
|
570
|
+
}
|
|
571
|
+
expose({
|
|
572
|
+
search(query) {
|
|
573
|
+
instance?.search(query);
|
|
574
|
+
},
|
|
575
|
+
clearSearch() {
|
|
576
|
+
instance?.clearSearch();
|
|
577
|
+
},
|
|
578
|
+
zoomToFit() {
|
|
579
|
+
instance?.zoomToFit();
|
|
580
|
+
},
|
|
581
|
+
zoomToNode(nodeId) {
|
|
582
|
+
instance?.zoomToNode(nodeId);
|
|
583
|
+
},
|
|
584
|
+
selectNode(nodeId) {
|
|
585
|
+
instance?.selectNode(nodeId);
|
|
586
|
+
},
|
|
587
|
+
getSelectedNodes() {
|
|
588
|
+
return instance?.getSelectedNodes() ?? [];
|
|
589
|
+
},
|
|
590
|
+
get instance() {
|
|
591
|
+
return instance;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
onMounted5(() => {
|
|
595
|
+
mountGraph();
|
|
596
|
+
});
|
|
597
|
+
onUnmounted6(() => {
|
|
598
|
+
destroyGraph();
|
|
599
|
+
});
|
|
600
|
+
watch6(
|
|
601
|
+
() => JSON.stringify(props.spec),
|
|
602
|
+
(newVal) => {
|
|
603
|
+
if (!instance) return;
|
|
604
|
+
if (newVal !== prevSpec) {
|
|
605
|
+
prevSpec = newVal;
|
|
606
|
+
instance.update(props.spec);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
);
|
|
610
|
+
watch6(
|
|
611
|
+
[
|
|
612
|
+
() => props.theme,
|
|
613
|
+
() => props.darkMode,
|
|
614
|
+
() => contextTheme?.value,
|
|
615
|
+
() => contextDarkMode?.value
|
|
616
|
+
],
|
|
617
|
+
() => {
|
|
618
|
+
if (!containerRef.value) return;
|
|
619
|
+
destroyGraph();
|
|
620
|
+
mountGraph();
|
|
621
|
+
}
|
|
622
|
+
);
|
|
623
|
+
const rootClass = () => {
|
|
624
|
+
const base = "viz-graph-root";
|
|
625
|
+
return props.class ? `${base} ${props.class}` : base;
|
|
626
|
+
};
|
|
627
|
+
return () => h3("div", {
|
|
628
|
+
ref: containerRef,
|
|
629
|
+
class: rootClass(),
|
|
630
|
+
style: props.style
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
// src/ThemeProvider.ts
|
|
636
|
+
import { computed as computed2, defineComponent as defineComponent4, provide } from "vue";
|
|
637
|
+
var VizThemeProvider = defineComponent4({
|
|
638
|
+
name: "VizThemeProvider",
|
|
639
|
+
props: {
|
|
640
|
+
theme: {
|
|
641
|
+
type: Object,
|
|
642
|
+
default: void 0
|
|
643
|
+
},
|
|
644
|
+
darkMode: {
|
|
645
|
+
type: String,
|
|
646
|
+
default: void 0
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
setup(props, { slots }) {
|
|
650
|
+
const themeRef = computed2(() => props.theme);
|
|
651
|
+
const darkModeRef = computed2(() => props.darkMode);
|
|
652
|
+
provide(VizThemeKey, themeRef);
|
|
653
|
+
provide(VizDarkModeKey, darkModeRef);
|
|
654
|
+
return () => slots.default?.();
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
// src/Visualization.ts
|
|
659
|
+
import { isGraphSpec, isTableSpec } from "@opendata-ai/openchart-core";
|
|
660
|
+
import { defineComponent as defineComponent5, h as h4 } from "vue";
|
|
661
|
+
var Visualization = defineComponent5({
|
|
662
|
+
name: "Visualization",
|
|
663
|
+
props: {
|
|
664
|
+
spec: {
|
|
665
|
+
type: Object,
|
|
666
|
+
required: true
|
|
667
|
+
},
|
|
668
|
+
theme: {
|
|
669
|
+
type: Object,
|
|
670
|
+
default: void 0
|
|
671
|
+
},
|
|
672
|
+
darkMode: {
|
|
673
|
+
type: String,
|
|
674
|
+
default: void 0
|
|
675
|
+
},
|
|
676
|
+
class: {
|
|
677
|
+
type: String,
|
|
678
|
+
default: void 0
|
|
679
|
+
},
|
|
680
|
+
style: {
|
|
681
|
+
type: [String, Object],
|
|
682
|
+
default: void 0
|
|
683
|
+
}
|
|
684
|
+
},
|
|
685
|
+
setup(props) {
|
|
686
|
+
return () => {
|
|
687
|
+
const { spec, theme, darkMode, class: className, style } = props;
|
|
688
|
+
const sharedProps = { theme, darkMode, class: className, style };
|
|
689
|
+
if (isTableSpec(spec)) {
|
|
690
|
+
return h4(DataTable, { ...sharedProps, spec });
|
|
691
|
+
}
|
|
692
|
+
if (isGraphSpec(spec)) {
|
|
693
|
+
return h4(Graph, { ...sharedProps, spec });
|
|
694
|
+
}
|
|
695
|
+
return h4(Chart, { ...sharedProps, spec });
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
export {
|
|
700
|
+
Chart,
|
|
701
|
+
DataTable,
|
|
702
|
+
Graph,
|
|
703
|
+
Visualization,
|
|
704
|
+
VizDarkModeKey,
|
|
705
|
+
VizThemeKey,
|
|
706
|
+
VizThemeProvider,
|
|
707
|
+
useChart,
|
|
708
|
+
useDarkMode,
|
|
709
|
+
useGraph,
|
|
710
|
+
useTable,
|
|
711
|
+
useTableState,
|
|
712
|
+
useVizDarkMode,
|
|
713
|
+
useVizTheme
|
|
714
|
+
};
|
|
715
|
+
//# sourceMappingURL=index.js.map
|