@vanduo-oss/vd3-cbun 1.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE +22 -0
  3. package/README.md +160 -0
  4. package/SKILL.md +119 -0
  5. package/dist/charts/core.d.ts +273 -0
  6. package/dist/charts/index.cjs +1828 -0
  7. package/dist/charts/index.cjs.map +7 -0
  8. package/dist/charts/index.d.ts +65 -0
  9. package/dist/charts/index.js +1805 -0
  10. package/dist/charts/index.js.map +7 -0
  11. package/dist/charts/vd3-charts.css +51 -0
  12. package/dist/charts/vue.d.ts +86 -0
  13. package/dist/flowchart/core.d.ts +288 -0
  14. package/dist/flowchart/index.cjs +3447 -0
  15. package/dist/flowchart/index.cjs.map +7 -0
  16. package/dist/flowchart/index.d.ts +54 -0
  17. package/dist/flowchart/index.js +3424 -0
  18. package/dist/flowchart/index.js.map +7 -0
  19. package/dist/flowchart/vd3-flowchart.css +600 -0
  20. package/dist/flowchart/vue.d.ts +66 -0
  21. package/dist/hex-grid/core.d.ts +200 -0
  22. package/dist/hex-grid/hex-math.cjs +162 -0
  23. package/dist/hex-grid/hex-math.cjs.map +7 -0
  24. package/dist/hex-grid/hex-math.d.ts +119 -0
  25. package/dist/hex-grid/hex-math.js +141 -0
  26. package/dist/hex-grid/hex-math.js.map +7 -0
  27. package/dist/hex-grid/index.cjs +915 -0
  28. package/dist/hex-grid/index.cjs.map +7 -0
  29. package/dist/hex-grid/index.d.ts +15 -0
  30. package/dist/hex-grid/index.js +894 -0
  31. package/dist/hex-grid/index.js.map +7 -0
  32. package/dist/hex-grid/vue.d.ts +14 -0
  33. package/dist/index.d.ts +13 -0
  34. package/dist/index.js +11 -0
  35. package/dist/index.js.map +7 -0
  36. package/dist/meta.json +551 -0
  37. package/dist/music-player/core.d.ts +88 -0
  38. package/dist/music-player/index.cjs +1227 -0
  39. package/dist/music-player/index.cjs.map +7 -0
  40. package/dist/music-player/index.d.ts +12 -0
  41. package/dist/music-player/index.js +1204 -0
  42. package/dist/music-player/index.js.map +7 -0
  43. package/dist/music-player/vd3-music-player.css +829 -0
  44. package/dist/music-player/vue.d.ts +32 -0
  45. package/package.json +105 -0
@@ -0,0 +1,1828 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/charts/index.js
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AreaChart: () => AreaChart,
24
+ BarChart: () => BarChart,
25
+ DonutChart: () => DonutChart,
26
+ LineChart: () => LineChart,
27
+ PieChart: () => PieChart,
28
+ ScatterChart: () => ScatterChart,
29
+ VD_CHARTS_VERSION: () => VD_CHARTS_VERSION,
30
+ VdAreaChart: () => VdAreaChart,
31
+ VdBarChart: () => VdBarChart,
32
+ VdChart: () => VdChart,
33
+ VdDonutChart: () => VdDonutChart,
34
+ VdLineChart: () => VdLineChart,
35
+ VdPieChart: () => VdPieChart,
36
+ VdScatterChart: () => VdScatterChart,
37
+ arcPath: () => arcPath,
38
+ areaPath: () => areaPath,
39
+ createAccessor: () => createAccessor,
40
+ linePath: () => linePath,
41
+ niceDomain: () => niceDomain,
42
+ resolveTheme: () => resolveTheme,
43
+ scaleBand: () => scaleBand,
44
+ scaleLinear: () => scaleLinear,
45
+ scaleOrdinal: () => scaleOrdinal,
46
+ scalePoint: () => scalePoint,
47
+ scaleTime: () => scaleTime,
48
+ ticks: () => ticks
49
+ });
50
+ module.exports = __toCommonJS(index_exports);
51
+
52
+ // src/charts/vue.js
53
+ var import_vue = require("vue");
54
+
55
+ // src/charts/core.js
56
+ var SVG_NS = "http://www.w3.org/2000/svg";
57
+ var TAU = Math.PI * 2;
58
+ var ARC_EPSILON = 1e-4;
59
+ var DEFAULT_WIDTH = 640;
60
+ var DEFAULT_HEIGHT = 360;
61
+ var DEFAULT_MARGIN = { top: 28, right: 24, bottom: 46, left: 56 };
62
+ var POLAR_MARGIN = { top: 32, right: 24, bottom: 28, left: 24 };
63
+ var DEFAULT_COLORS = [
64
+ "#5c7cfa",
65
+ "#228be6",
66
+ "#40c057",
67
+ "#fab005",
68
+ "#fa5252",
69
+ "#12b886",
70
+ "#be4bdb",
71
+ "#fd7e14"
72
+ ];
73
+ var VD_CHARTS_VERSION = "1.0.0";
74
+ var chartId = 0;
75
+ function nextId(prefix) {
76
+ chartId += 1;
77
+ return `${prefix}-${chartId}`;
78
+ }
79
+ function hasWindow() {
80
+ return typeof window !== "undefined" && typeof document !== "undefined";
81
+ }
82
+ function isElement(value) {
83
+ return hasWindow() && value instanceof Element;
84
+ }
85
+ function resolveTarget(target) {
86
+ if (!hasWindow()) {
87
+ throw new Error("Vanduo Charts requires a browser DOM target.");
88
+ }
89
+ if (typeof target === "string") {
90
+ const el = document.querySelector(target);
91
+ if (!el) throw new Error(`Chart target not found: ${target}`);
92
+ return el;
93
+ }
94
+ if (isElement(target)) return target;
95
+ throw new Error("Chart target must be an Element or selector string.");
96
+ }
97
+ function svgEl(name, attrs = {}) {
98
+ const el = document.createElementNS(SVG_NS, name);
99
+ Object.entries(attrs).forEach(([key, value]) => {
100
+ if (value !== null && typeof value !== "undefined") {
101
+ el.setAttribute(key, String(value));
102
+ }
103
+ });
104
+ return el;
105
+ }
106
+ function append(parent, child) {
107
+ parent.appendChild(child);
108
+ return child;
109
+ }
110
+ function setText(parent, text) {
111
+ parent.textContent = text == null ? "" : String(text);
112
+ return parent;
113
+ }
114
+ function toArray(value) {
115
+ return Array.isArray(value) ? value : [];
116
+ }
117
+ function unique(values) {
118
+ const seen = /* @__PURE__ */ new Set();
119
+ const result = [];
120
+ values.forEach((value) => {
121
+ const key = String(value);
122
+ if (seen.has(key)) return;
123
+ seen.add(key);
124
+ result.push(value);
125
+ });
126
+ return result;
127
+ }
128
+ function isFiniteNumber(value) {
129
+ return typeof value === "number" && Number.isFinite(value);
130
+ }
131
+ function toNumber(value) {
132
+ if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : null;
133
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
134
+ if (typeof value === "string" && value.trim() !== "") {
135
+ const parsed = Number(value);
136
+ return Number.isFinite(parsed) ? parsed : null;
137
+ }
138
+ return null;
139
+ }
140
+ function toTime(value) {
141
+ if (value instanceof Date) return Number.isFinite(value.getTime()) ? value.getTime() : null;
142
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
143
+ if (typeof value === "string" && value.trim() !== "") {
144
+ const parsed = Date.parse(value);
145
+ return Number.isFinite(parsed) ? parsed : null;
146
+ }
147
+ return null;
148
+ }
149
+ function isDateLike(value) {
150
+ if (value instanceof Date) return Number.isFinite(value.getTime());
151
+ if (typeof value !== "string") return false;
152
+ const trimmed = value.trim();
153
+ if (!trimmed || /^-?\d+(\.\d+)?$/.test(trimmed)) return false;
154
+ return Number.isFinite(Date.parse(trimmed));
155
+ }
156
+ function readPathValue(source, path) {
157
+ if (source == null) return void 0;
158
+ if (!String(path).includes(".")) return source[path];
159
+ return String(path).split(".").reduce((value, key) => {
160
+ if (value == null) return void 0;
161
+ return value[key];
162
+ }, source);
163
+ }
164
+ function createAccessor(accessor, fallback) {
165
+ const resolved = accessor == null ? fallback : accessor;
166
+ if (typeof resolved === "function") return resolved;
167
+ if (typeof resolved === "string" && resolved.length) {
168
+ return (datum) => readPathValue(datum, resolved);
169
+ }
170
+ return (datum) => datum;
171
+ }
172
+ function normalizeMargin(value, fallback = DEFAULT_MARGIN) {
173
+ if (typeof value === "number") {
174
+ return { top: value, right: value, bottom: value, left: value };
175
+ }
176
+ return {
177
+ top: Number(value?.top ?? fallback.top),
178
+ right: Number(value?.right ?? fallback.right),
179
+ bottom: Number(value?.bottom ?? fallback.bottom),
180
+ left: Number(value?.left ?? fallback.left)
181
+ };
182
+ }
183
+ function measureTarget(target, options) {
184
+ const width = Number(options.width) || Math.round(target.clientWidth) || DEFAULT_WIDTH;
185
+ const height = Number(options.height) || Math.round(target.clientHeight) || DEFAULT_HEIGHT;
186
+ return {
187
+ width: Math.max(160, width),
188
+ height: Math.max(140, height)
189
+ };
190
+ }
191
+ function getPlotBox(width, height, margin) {
192
+ return {
193
+ left: margin.left,
194
+ top: margin.top,
195
+ right: Math.max(margin.left + 1, width - margin.right),
196
+ bottom: Math.max(margin.top + 1, height - margin.bottom)
197
+ };
198
+ }
199
+ function readToken(style, names, fallback) {
200
+ for (const name of names) {
201
+ const value = style.getPropertyValue(name).trim();
202
+ if (value) return value;
203
+ }
204
+ return fallback;
205
+ }
206
+ function resolveTheme(target, overrides = {}) {
207
+ if (!hasWindow()) {
208
+ return {
209
+ fontFamily: "inherit",
210
+ textColor: "#1a1d20",
211
+ mutedTextColor: "#868e96",
212
+ gridColor: "#e9ecef",
213
+ axisColor: "#ced4da",
214
+ backgroundColor: "#ffffff",
215
+ colors: DEFAULT_COLORS.slice(),
216
+ ...overrides
217
+ };
218
+ }
219
+ const styleTarget = isElement(target) ? target : document.documentElement;
220
+ const style = getComputedStyle(styleTarget);
221
+ const rootStyle = getComputedStyle(document.documentElement);
222
+ const tokenStyle = {
223
+ getPropertyValue(name) {
224
+ return style.getPropertyValue(name) || rootStyle.getPropertyValue(name);
225
+ }
226
+ };
227
+ const colors = DEFAULT_COLORS.map(
228
+ (fallback, index) => readToken(
229
+ tokenStyle,
230
+ [
231
+ `--vd-chart-${index + 1}`,
232
+ index === 0 ? "--vd-color-primary" : "",
233
+ index === 1 ? "--vd-color-info" : "",
234
+ index === 2 ? "--vd-color-success" : "",
235
+ index === 3 ? "--vd-color-warning" : "",
236
+ index === 4 ? "--vd-color-error" : "",
237
+ index === 0 ? "--color-primary" : "",
238
+ index === 1 ? "--color-info" : "",
239
+ index === 2 ? "--color-success" : ""
240
+ ].filter(Boolean),
241
+ fallback
242
+ )
243
+ );
244
+ return {
245
+ fontFamily: readToken(tokenStyle, ["--vd-font-family-base"], "inherit"),
246
+ textColor: readToken(tokenStyle, ["--vd-text-primary", "--text-primary"], "#1a1d20"),
247
+ mutedTextColor: readToken(tokenStyle, ["--vd-text-muted", "--text-muted"], "#868e96"),
248
+ gridColor: readToken(
249
+ tokenStyle,
250
+ ["--vd-border-color-light", "--border-color-light", "--vd-border-color"],
251
+ "#e9ecef"
252
+ ),
253
+ axisColor: readToken(tokenStyle, ["--vd-border-color", "--border-color"], "#ced4da"),
254
+ backgroundColor: readToken(tokenStyle, ["--vd-bg-primary", "--bg-primary"], "#ffffff"),
255
+ ...overrides,
256
+ colors: overrides.colors || colors
257
+ };
258
+ }
259
+ function tickStep(min, max, count) {
260
+ const span = Math.abs(max - min);
261
+ if (!span || !Number.isFinite(span)) return 1;
262
+ const raw = span / Math.max(1, count);
263
+ const power = Math.pow(10, Math.floor(Math.log10(raw)));
264
+ const error = raw / power;
265
+ const factor = error >= 7.5 ? 10 : error >= 3.5 ? 5 : error >= 1.5 ? 2 : 1;
266
+ return factor * power;
267
+ }
268
+ function ticks(min, max, count = 5) {
269
+ if (!Number.isFinite(min) || !Number.isFinite(max)) return [];
270
+ if (min === max) return [min];
271
+ const reverse = max < min;
272
+ const start = reverse ? max : min;
273
+ const stop = reverse ? min : max;
274
+ const step = tickStep(start, stop, count);
275
+ const first = Math.ceil(start / step) * step;
276
+ const values = [];
277
+ for (let value = first; value <= stop + step / 2; value += step) {
278
+ values.push(Number(value.toFixed(12)));
279
+ }
280
+ return reverse ? values.reverse() : values;
281
+ }
282
+ function niceDomain(values, options = false) {
283
+ const opts = typeof options === "boolean" ? { includeZero: options } : options || {};
284
+ const nums = values.map(toNumber).filter(isFiniteNumber);
285
+ if (!nums.length) {
286
+ return [isFiniteNumber(opts.min) ? opts.min : 0, isFiniteNumber(opts.max) ? opts.max : 1];
287
+ }
288
+ let min = Math.min(...nums);
289
+ let max = Math.max(...nums);
290
+ if (opts.includeZero) {
291
+ min = Math.min(0, min);
292
+ max = Math.max(0, max);
293
+ }
294
+ if (isFiniteNumber(opts.min)) min = opts.min;
295
+ if (isFiniteNumber(opts.max)) max = opts.max;
296
+ if (min === max) {
297
+ const pad = Math.abs(min || 1) * 0.1;
298
+ min -= pad;
299
+ max += pad;
300
+ }
301
+ const step = tickStep(min, max, opts.tickCount || 5);
302
+ return [
303
+ isFiniteNumber(opts.min) ? opts.min : Math.floor(min / step) * step,
304
+ isFiniteNumber(opts.max) ? opts.max : Math.ceil(max / step) * step
305
+ ];
306
+ }
307
+ function scaleLinear(config = {}) {
308
+ const domain = config.domain || [0, 1];
309
+ const range = config.range || [0, 1];
310
+ let d0 = Number(domain[0]);
311
+ let d1 = Number(domain[1]);
312
+ const r0 = Number(range[0]);
313
+ const r1 = Number(range[1]);
314
+ if (!Number.isFinite(d0)) d0 = 0;
315
+ if (!Number.isFinite(d1)) d1 = 1;
316
+ if (d0 === d1) {
317
+ d0 -= 0.5;
318
+ d1 += 0.5;
319
+ }
320
+ const scale = (value) => {
321
+ const n = Number(value);
322
+ if (!Number.isFinite(n)) return null;
323
+ return r0 + (n - d0) / (d1 - d0) * (r1 - r0);
324
+ };
325
+ scale.domain = () => [d0, d1];
326
+ scale.range = () => [r0, r1];
327
+ scale.ticks = (count = 5) => ticks(d0, d1, count);
328
+ return scale;
329
+ }
330
+ function scaleTime(config = {}) {
331
+ const domain = (config.domain || [/* @__PURE__ */ new Date(0), /* @__PURE__ */ new Date(1)]).map(toTime);
332
+ const linear = scaleLinear({
333
+ domain: [domain[0] ?? 0, domain[1] ?? 1],
334
+ range: config.range || [0, 1]
335
+ });
336
+ const scale = (value) => linear(toTime(value));
337
+ scale.domain = () => linear.domain().map((value) => new Date(value));
338
+ scale.range = linear.range;
339
+ scale.ticks = (count = 5) => linear.ticks(count).map((value) => new Date(value));
340
+ return scale;
341
+ }
342
+ function scaleBand(config = {}) {
343
+ const domain = unique(config.domain || []).map(String);
344
+ const range = config.range || [0, 1];
345
+ const paddingInner = Number(config.paddingInner ?? config.padding ?? 0.16);
346
+ const paddingOuter = Number(config.paddingOuter ?? config.padding ?? 0.16);
347
+ const r0 = Number(range[0]);
348
+ const r1 = Number(range[1]);
349
+ const span = r1 - r0;
350
+ const denominator = Math.max(1, domain.length - paddingInner + paddingOuter * 2);
351
+ const step = span / denominator;
352
+ const bandwidth = Math.abs(step * Math.max(0, 1 - paddingInner));
353
+ const scale = (value) => {
354
+ const index = domain.indexOf(String(value));
355
+ if (index < 0) return null;
356
+ return r0 + (paddingOuter + index) * step;
357
+ };
358
+ scale.domain = () => domain.slice();
359
+ scale.range = () => [r0, r1];
360
+ scale.bandwidth = () => bandwidth;
361
+ scale.step = () => Math.abs(step);
362
+ return scale;
363
+ }
364
+ function scalePoint(config = {}) {
365
+ const domain = unique(config.domain || []).map(String);
366
+ const range = config.range || [0, 1];
367
+ const padding = Number(config.padding ?? 0.5);
368
+ const r0 = Number(range[0]);
369
+ const r1 = Number(range[1]);
370
+ const span = r1 - r0;
371
+ const step = domain.length <= 1 ? 0 : span / Math.max(1, domain.length - 1 + padding * 2);
372
+ const start = domain.length <= 1 ? r0 + span / 2 : r0 + padding * step;
373
+ const scale = (value) => {
374
+ const index = domain.indexOf(String(value));
375
+ if (index < 0) return null;
376
+ return start + index * step;
377
+ };
378
+ scale.domain = () => domain.slice();
379
+ scale.range = () => [r0, r1];
380
+ scale.step = () => Math.abs(step);
381
+ scale.bandwidth = () => 0;
382
+ return scale;
383
+ }
384
+ function scaleOrdinal(config = {}) {
385
+ const domain = unique(config.domain || []).map(String);
386
+ const range = config.range || DEFAULT_COLORS;
387
+ const scale = (value) => {
388
+ const key = String(value);
389
+ let index = domain.indexOf(key);
390
+ if (index < 0) {
391
+ domain.push(key);
392
+ index = domain.length - 1;
393
+ }
394
+ return range[index % range.length];
395
+ };
396
+ scale.domain = () => domain.slice();
397
+ scale.range = () => range.slice();
398
+ return scale;
399
+ }
400
+ function linePath(points) {
401
+ const clean = points.filter((point) => isFiniteNumber(point.x) && isFiniteNumber(point.y));
402
+ if (!clean.length) return "";
403
+ return clean.map((point, index) => `${index === 0 ? "M" : "L"}${point.x},${point.y}`).join(" ");
404
+ }
405
+ function areaPath(points, baselineY) {
406
+ const clean = points.filter((point) => isFiniteNumber(point.x) && isFiniteNumber(point.y));
407
+ if (!clean.length || !isFiniteNumber(baselineY)) return "";
408
+ const line = linePath(clean);
409
+ const last = clean[clean.length - 1];
410
+ const first = clean[0];
411
+ return `${line} L${last.x},${baselineY} L${first.x},${baselineY} Z`;
412
+ }
413
+ function polarPoint(cx, cy, radius, angle) {
414
+ return {
415
+ x: cx + radius * Math.cos(angle),
416
+ y: cy + radius * Math.sin(angle)
417
+ };
418
+ }
419
+ function arcPath(cx, cy, outerRadius, innerRadius, startAngle, endAngle) {
420
+ if (!isFiniteNumber(outerRadius) || outerRadius <= 0 || endAngle <= startAngle) return "";
421
+ const safeEnd = endAngle - startAngle >= TAU ? startAngle + TAU - ARC_EPSILON : endAngle;
422
+ const largeArc = safeEnd - startAngle > Math.PI ? 1 : 0;
423
+ const outerStart = polarPoint(cx, cy, outerRadius, startAngle);
424
+ const outerEnd = polarPoint(cx, cy, outerRadius, safeEnd);
425
+ const inner = Math.max(0, Number(innerRadius) || 0);
426
+ if (inner <= 0) {
427
+ return [
428
+ `M${cx},${cy}`,
429
+ `L${outerStart.x},${outerStart.y}`,
430
+ `A${outerRadius},${outerRadius} 0 ${largeArc} 1 ${outerEnd.x},${outerEnd.y}`,
431
+ "Z"
432
+ ].join(" ");
433
+ }
434
+ const innerEnd = polarPoint(cx, cy, inner, safeEnd);
435
+ const innerStart = polarPoint(cx, cy, inner, startAngle);
436
+ return [
437
+ `M${outerStart.x},${outerStart.y}`,
438
+ `A${outerRadius},${outerRadius} 0 ${largeArc} 1 ${outerEnd.x},${outerEnd.y}`,
439
+ `L${innerEnd.x},${innerEnd.y}`,
440
+ `A${inner},${inner} 0 ${largeArc} 0 ${innerStart.x},${innerStart.y}`,
441
+ "Z"
442
+ ].join(" ");
443
+ }
444
+ function formatNumber(value) {
445
+ if (!Number.isFinite(value)) return "";
446
+ return Math.abs(value) >= 1e3 ? value.toLocaleString() : String(Number(value.toFixed(3)));
447
+ }
448
+ function formatTick(value, formatter) {
449
+ if (typeof formatter === "function") return formatter(value);
450
+ if (value instanceof Date) {
451
+ return new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric" }).format(value);
452
+ }
453
+ return formatNumber(Number(value));
454
+ }
455
+ function formatCategory(value) {
456
+ return value == null ? "" : String(value);
457
+ }
458
+ function attachTooltip(instance, mark, options, context, fallback) {
459
+ const tooltip = options.tooltip;
460
+ if (tooltip === false) return;
461
+ const getContent = () => {
462
+ if (typeof tooltip === "function") {
463
+ const result = tooltip(context.datum, context);
464
+ return result === false ? null : result;
465
+ }
466
+ if (typeof tooltip === "string") return tooltip;
467
+ return fallback;
468
+ };
469
+ const show = (event) => {
470
+ const content = getContent();
471
+ if (content == null || content === "") return;
472
+ instance.showTooltip(content, event);
473
+ };
474
+ const hide = () => instance.hideTooltip();
475
+ mark.addEventListener("pointerenter", show);
476
+ mark.addEventListener("pointermove", show);
477
+ mark.addEventListener("pointerleave", hide);
478
+ mark.addEventListener("focus", show);
479
+ mark.addEventListener("blur", hide);
480
+ }
481
+ function attachClick(mark, callback, datum, index) {
482
+ if (typeof callback !== "function") return;
483
+ const fire = (event) => callback({ event, datum, index });
484
+ mark.addEventListener("click", fire);
485
+ mark.addEventListener("keydown", (event) => {
486
+ if (event.key === "Enter" || event.key === " ") {
487
+ event.preventDefault();
488
+ fire(event);
489
+ }
490
+ });
491
+ }
492
+ function makeInteractive(mark, hasClick, hasTooltip) {
493
+ if (hasClick || hasTooltip) {
494
+ mark.setAttribute("tabindex", "0");
495
+ mark.setAttribute("focusable", "true");
496
+ }
497
+ }
498
+ function createSvgShell(instance) {
499
+ const { target, options } = instance;
500
+ const size = measureTarget(target, options);
501
+ const theme = resolveTheme(target, options.theme);
502
+ const margin = normalizeMargin(options.margin, options.polar ? POLAR_MARGIN : DEFAULT_MARGIN);
503
+ const plot = getPlotBox(size.width, size.height, margin);
504
+ target.innerHTML = "";
505
+ target.classList.add("vd-chart-root", `vd-chart-${instance.kind}`);
506
+ if (getComputedStyle(target).position === "static") {
507
+ target.style.position = "relative";
508
+ }
509
+ const svg = svgEl("svg", {
510
+ class: "vd-chart-svg",
511
+ width: size.width,
512
+ height: size.height,
513
+ viewBox: `0 0 ${size.width} ${size.height}`,
514
+ role: "img"
515
+ });
516
+ const titleId = nextId("vd-chart-title");
517
+ const descId = nextId("vd-chart-desc");
518
+ const labelledBy = [];
519
+ if (options.title) {
520
+ labelledBy.push(titleId);
521
+ append(svg, setText(svgEl("title", { id: titleId }), options.title));
522
+ }
523
+ if (options.description) {
524
+ labelledBy.push(descId);
525
+ append(svg, setText(svgEl("desc", { id: descId }), options.description));
526
+ }
527
+ if (labelledBy.length) {
528
+ svg.setAttribute("aria-labelledby", labelledBy.join(" "));
529
+ } else {
530
+ svg.setAttribute("aria-label", options.ariaLabel || `${instance.kind} chart`);
531
+ }
532
+ if (options.title) {
533
+ append(
534
+ svg,
535
+ setText(
536
+ svgEl("text", {
537
+ x: margin.left,
538
+ y: 18,
539
+ fill: theme.textColor,
540
+ "font-size": 14,
541
+ "font-weight": 600
542
+ }),
543
+ options.title
544
+ )
545
+ );
546
+ }
547
+ target.appendChild(svg);
548
+ instance.theme = theme;
549
+ instance.size = size;
550
+ instance.plot = plot;
551
+ instance.tooltipEl = null;
552
+ return { svg, size, theme, plot, margin };
553
+ }
554
+ function renderEmpty(svg, size, theme, message = "No data") {
555
+ append(
556
+ svg,
557
+ setText(
558
+ svgEl("text", {
559
+ class: "vd-chart-empty",
560
+ x: size.width / 2,
561
+ y: size.height / 2,
562
+ fill: theme.mutedTextColor,
563
+ "text-anchor": "middle"
564
+ }),
565
+ message
566
+ )
567
+ );
568
+ }
569
+ function drawAxisLine(svg, x1, y1, x2, y2, theme) {
570
+ append(
571
+ svg,
572
+ svgEl("line", {
573
+ x1,
574
+ y1,
575
+ x2,
576
+ y2,
577
+ stroke: theme.axisColor,
578
+ "stroke-width": 1,
579
+ "shape-rendering": "crispEdges"
580
+ })
581
+ );
582
+ }
583
+ function drawCartesianAxes(svg, config) {
584
+ const { plot, xScale, yScale, xTicks, yTicks, theme, options, categoricalX } = config;
585
+ const axisGroup = append(svg, svgEl("g", { class: "vd-chart-axes" }));
586
+ yTicks.forEach((tick) => {
587
+ const y = yScale(tick);
588
+ if (!isFiniteNumber(y)) return;
589
+ append(
590
+ axisGroup,
591
+ svgEl("line", {
592
+ x1: plot.left,
593
+ y1: y,
594
+ x2: plot.right,
595
+ y2: y,
596
+ stroke: theme.gridColor,
597
+ "stroke-width": 1,
598
+ "shape-rendering": "crispEdges"
599
+ })
600
+ );
601
+ append(
602
+ axisGroup,
603
+ setText(
604
+ svgEl("text", {
605
+ x: plot.left - 10,
606
+ y: y + 4,
607
+ fill: theme.mutedTextColor,
608
+ "font-size": 11,
609
+ "text-anchor": "end"
610
+ }),
611
+ formatTick(tick, options.yFormat)
612
+ )
613
+ );
614
+ });
615
+ drawAxisLine(axisGroup, plot.left, plot.bottom, plot.right, plot.bottom, theme);
616
+ drawAxisLine(axisGroup, plot.left, plot.top, plot.left, plot.bottom, theme);
617
+ xTicks.forEach((tick) => {
618
+ let x = xScale(tick);
619
+ if (categoricalX && typeof xScale.bandwidth === "function") {
620
+ x += xScale.bandwidth() / 2;
621
+ }
622
+ if (!isFiniteNumber(x)) return;
623
+ append(
624
+ axisGroup,
625
+ svgEl("line", {
626
+ x1: x,
627
+ y1: plot.bottom,
628
+ x2: x,
629
+ y2: plot.bottom + 5,
630
+ stroke: theme.axisColor,
631
+ "stroke-width": 1
632
+ })
633
+ );
634
+ append(
635
+ axisGroup,
636
+ setText(
637
+ svgEl("text", {
638
+ x,
639
+ y: plot.bottom + 20,
640
+ fill: theme.mutedTextColor,
641
+ "font-size": 11,
642
+ "text-anchor": "middle"
643
+ }),
644
+ categoricalX ? formatCategory(tick) : formatTick(tick, options.xFormat)
645
+ )
646
+ );
647
+ });
648
+ if (options.xAxis?.label) {
649
+ append(
650
+ axisGroup,
651
+ setText(
652
+ svgEl("text", {
653
+ x: (plot.left + plot.right) / 2,
654
+ y: plot.bottom + 40,
655
+ fill: theme.mutedTextColor,
656
+ "font-size": 12,
657
+ "text-anchor": "middle"
658
+ }),
659
+ options.xAxis.label
660
+ )
661
+ );
662
+ }
663
+ if (options.yAxis?.label) {
664
+ append(
665
+ axisGroup,
666
+ setText(
667
+ svgEl("text", {
668
+ x: -((plot.top + plot.bottom) / 2),
669
+ y: 15,
670
+ fill: theme.mutedTextColor,
671
+ "font-size": 12,
672
+ "text-anchor": "middle",
673
+ transform: "rotate(-90)"
674
+ }),
675
+ options.yAxis.label
676
+ )
677
+ );
678
+ }
679
+ }
680
+ function inferXScale(rows, plot, options) {
681
+ const values = rows.map((row) => row.x);
682
+ const explicitType = options.xScale;
683
+ const allNumeric = values.every((value) => toNumber(value) !== null);
684
+ const allDates = values.every(isDateLike);
685
+ if (explicitType === "time" || !explicitType && allDates) {
686
+ const times = values.map(toTime).filter(isFiniteNumber);
687
+ return {
688
+ scale: scaleTime({ domain: niceDomain(times), range: [plot.left, plot.right] }),
689
+ values: times,
690
+ ticks: scaleLinear({ domain: niceDomain(times), range: [plot.left, plot.right] }).ticks(5).map((value) => new Date(value)),
691
+ type: "time",
692
+ mapValue: toTime
693
+ };
694
+ }
695
+ if (explicitType === "linear" || !explicitType && allNumeric) {
696
+ const nums = values.map(toNumber).filter(isFiniteNumber);
697
+ const domain2 = niceDomain(nums, { min: options.xMin, max: options.xMax });
698
+ const scale = scaleLinear({ domain: domain2, range: [plot.left, plot.right] });
699
+ return {
700
+ scale,
701
+ values: nums,
702
+ ticks: scale.ticks(5),
703
+ type: "linear",
704
+ mapValue: toNumber
705
+ };
706
+ }
707
+ const domain = unique(values).map(String);
708
+ return {
709
+ scale: scalePoint({ domain, range: [plot.left, plot.right], padding: 0.5 }),
710
+ values: domain,
711
+ ticks: domain,
712
+ type: "point",
713
+ mapValue: (value) => String(value)
714
+ };
715
+ }
716
+ function getColorScale(rows, colorOption, theme) {
717
+ if (colorOption == null) return null;
718
+ if (typeof colorOption === "function") {
719
+ return { direct: colorOption };
720
+ }
721
+ const colorAccessor = createAccessor(colorOption);
722
+ const domain = unique(rows.map((row) => colorAccessor(row.raw))).map(String);
723
+ return {
724
+ accessor: colorAccessor,
725
+ scale: scaleOrdinal({ domain, range: theme.colors })
726
+ };
727
+ }
728
+ function colorForRow(color, row, theme) {
729
+ if (color) {
730
+ if (typeof color.direct === "function") return color.direct(row.raw);
731
+ if (color.scale) return color.scale(color.accessor(row.raw));
732
+ }
733
+ return theme.colors[row.index % theme.colors.length];
734
+ }
735
+ function buildSeriesList(options) {
736
+ const xAccessor = createAccessor(options.x, "x");
737
+ const sharedData = toArray(options.data);
738
+ const buildRows = (data, yAccessor) => data.map((datum, index) => ({
739
+ raw: datum,
740
+ index,
741
+ x: xAccessor(datum),
742
+ y: toNumber(yAccessor(datum))
743
+ })).filter((row) => row.x != null && isFiniteNumber(row.y));
744
+ if (Array.isArray(options.series) && options.series.length) {
745
+ return options.series.map((series, seriesIndex) => {
746
+ const data = Array.isArray(series.data) && series.data.length ? series.data : sharedData;
747
+ const yAccessor = createAccessor(series.y ?? options.y, "y");
748
+ return {
749
+ name: series.name ?? `Series ${seriesIndex + 1}`,
750
+ color: series.color,
751
+ seriesIndex,
752
+ rows: buildRows(data, yAccessor)
753
+ };
754
+ });
755
+ }
756
+ return [
757
+ {
758
+ name: options.name ?? null,
759
+ color: options.stroke,
760
+ seriesIndex: 0,
761
+ rows: buildRows(sharedData, createAccessor(options.y, "y"))
762
+ }
763
+ ];
764
+ }
765
+ function seriesColor(series, theme) {
766
+ return series.color || theme.colors[series.seriesIndex % theme.colors.length];
767
+ }
768
+ function renderTopLegend(svg, items, theme, plot) {
769
+ if (!items.length) return;
770
+ const shown = items.slice(0, 8);
771
+ const widths = shown.map((item) => 14 + String(item.label).length * 6.5 + 14);
772
+ const total = widths.reduce((sum, w) => sum + w, 0);
773
+ let x = Math.max(plot.left, plot.right - total);
774
+ const y = 14;
775
+ const legend = append(svg, svgEl("g", { class: "vd-chart-legend" }));
776
+ shown.forEach((item, index) => {
777
+ append(
778
+ legend,
779
+ svgEl("rect", {
780
+ x,
781
+ y: y - 8,
782
+ width: 10,
783
+ height: 10,
784
+ rx: 2,
785
+ fill: item.color
786
+ })
787
+ );
788
+ append(
789
+ legend,
790
+ setText(
791
+ svgEl("text", {
792
+ x: x + 14,
793
+ y,
794
+ fill: theme.mutedTextColor,
795
+ "font-size": 11
796
+ }),
797
+ formatCategory(item.label)
798
+ )
799
+ );
800
+ x += widths[index];
801
+ });
802
+ }
803
+ function dataLabelConfig(options) {
804
+ const dl = options.dataLabels;
805
+ if (!dl) return null;
806
+ return typeof dl === "object" ? dl : {};
807
+ }
808
+ function drawDataLabel(svg, x, y, value, cfg, theme, anchor = "middle") {
809
+ if (!isFiniteNumber(x) || !isFiniteNumber(y)) return;
810
+ append(
811
+ svg,
812
+ setText(
813
+ svgEl("text", {
814
+ class: "vd-chart-data-label",
815
+ x,
816
+ y,
817
+ fill: cfg.color || theme.textColor,
818
+ "font-size": 10,
819
+ "text-anchor": anchor
820
+ }),
821
+ typeof cfg.format === "function" ? cfg.format(value) : formatNumber(value)
822
+ )
823
+ );
824
+ }
825
+ function drawAnnotations(svg, options, plot, xScale, yScale, theme) {
826
+ const annotations = toArray(options.annotations);
827
+ if (!annotations.length) return;
828
+ const group = append(svg, svgEl("g", { class: "vd-chart-annotations" }));
829
+ annotations.forEach((ann) => {
830
+ const color = ann.color || theme.mutedTextColor;
831
+ const dash = ann.dash === false ? null : "4 3";
832
+ if (isFiniteNumber(ann.y) && yScale) {
833
+ const y = yScale(ann.y);
834
+ if (!isFiniteNumber(y)) return;
835
+ append(
836
+ group,
837
+ svgEl("line", {
838
+ class: "vd-chart-annotation-line",
839
+ x1: plot.left,
840
+ y1: y,
841
+ x2: plot.right,
842
+ y2: y,
843
+ stroke: color,
844
+ "stroke-width": 1,
845
+ "stroke-dasharray": dash
846
+ })
847
+ );
848
+ if (ann.label) {
849
+ append(
850
+ group,
851
+ setText(
852
+ svgEl("text", {
853
+ x: plot.right - 4,
854
+ y: y - 4,
855
+ fill: color,
856
+ "font-size": 10,
857
+ "text-anchor": "end"
858
+ }),
859
+ ann.label
860
+ )
861
+ );
862
+ }
863
+ }
864
+ if (ann.x != null && xScale) {
865
+ let x = xScale(ann.x);
866
+ if (typeof xScale.bandwidth === "function" && isFiniteNumber(x)) {
867
+ x += xScale.bandwidth() / 2;
868
+ }
869
+ if (!isFiniteNumber(x)) return;
870
+ append(
871
+ group,
872
+ svgEl("line", {
873
+ class: "vd-chart-annotation-line",
874
+ x1: x,
875
+ y1: plot.top,
876
+ x2: x,
877
+ y2: plot.bottom,
878
+ stroke: color,
879
+ "stroke-width": 1,
880
+ "stroke-dasharray": dash
881
+ })
882
+ );
883
+ if (ann.label) {
884
+ append(
885
+ group,
886
+ setText(
887
+ svgEl("text", {
888
+ x: x + 4,
889
+ y: plot.top + 10,
890
+ fill: color,
891
+ "font-size": 10
892
+ }),
893
+ ann.label
894
+ )
895
+ );
896
+ }
897
+ }
898
+ });
899
+ }
900
+ function renderBarChart(instance) {
901
+ if (instance.options.series?.length) return renderMultiBarChart(instance);
902
+ const shell = createSvgShell(instance);
903
+ const { svg, size, theme, plot } = shell;
904
+ const options = instance.options;
905
+ const data = toArray(options.data);
906
+ const xAccessor = createAccessor(options.x, "x");
907
+ const yAccessor = createAccessor(options.y, "y");
908
+ const rows = data.map((datum, index) => ({
909
+ raw: datum,
910
+ index,
911
+ x: xAccessor(datum),
912
+ y: toNumber(yAccessor(datum))
913
+ })).filter((row) => row.x != null && isFiniteNumber(row.y));
914
+ if (!rows.length) {
915
+ renderEmpty(svg, size, theme);
916
+ return;
917
+ }
918
+ const categories = unique(rows.map((row) => row.x)).map(String);
919
+ const xScale = scaleBand({
920
+ domain: categories,
921
+ range: [plot.left, plot.right],
922
+ padding: options.barPadding ?? 0.18
923
+ });
924
+ const yDomain = niceDomain(
925
+ rows.map((row) => row.y),
926
+ {
927
+ includeZero: true,
928
+ min: options.yMin,
929
+ max: options.yMax,
930
+ tickCount: options.yTickCount
931
+ }
932
+ );
933
+ const yScale = scaleLinear({ domain: yDomain, range: [plot.bottom, plot.top] });
934
+ const yTicks = yScale.ticks(options.yTickCount ?? 5);
935
+ const color = getColorScale(rows, options.color, theme);
936
+ drawCartesianAxes(svg, {
937
+ plot,
938
+ xScale,
939
+ yScale,
940
+ xTicks: categories,
941
+ yTicks,
942
+ theme,
943
+ options,
944
+ categoricalX: true
945
+ });
946
+ drawAnnotations(svg, options, plot, xScale, yScale, theme);
947
+ const labels = dataLabelConfig(options);
948
+ const markGroup = append(svg, svgEl("g", { class: "vd-chart-marks vd-chart-bars" }));
949
+ const baseline = yScale(0);
950
+ rows.forEach((row) => {
951
+ const x = xScale(row.x);
952
+ const y = yScale(row.y);
953
+ if (!isFiniteNumber(x) || !isFiniteNumber(y) || !isFiniteNumber(baseline)) return;
954
+ const rectY = Math.min(y, baseline);
955
+ const rectHeight = Math.max(1, Math.abs(baseline - y));
956
+ const fill = colorForRow(color, row, theme);
957
+ const rect = svgEl("rect", {
958
+ class: "vd-chart-bar",
959
+ x,
960
+ y: rectY,
961
+ width: xScale.bandwidth(),
962
+ height: rectHeight,
963
+ rx: 3,
964
+ fill,
965
+ role: "graphics-symbol",
966
+ "aria-label": `${formatCategory(row.x)}: ${formatNumber(row.y)}`
967
+ });
968
+ makeInteractive(rect, typeof options.onBarClick === "function", options.tooltip !== false);
969
+ attachTooltip(
970
+ instance,
971
+ rect,
972
+ options,
973
+ {
974
+ datum: row.raw,
975
+ x: row.x,
976
+ y: row.y,
977
+ value: row.y,
978
+ label: row.x,
979
+ index: row.index
980
+ },
981
+ `${formatCategory(row.x)}: ${formatNumber(row.y)}`
982
+ );
983
+ attachClick(rect, options.onBarClick, row.raw, row.index);
984
+ if (labels) drawDataLabel(svg, x + xScale.bandwidth() / 2, rectY - 4, row.y, labels, theme);
985
+ append(markGroup, rect);
986
+ });
987
+ if (options.legend && color && color.scale) {
988
+ renderTopLegend(
989
+ svg,
990
+ color.scale.domain().map((cat) => ({ label: cat, color: color.scale(cat) })),
991
+ theme,
992
+ plot
993
+ );
994
+ }
995
+ }
996
+ function renderMultiBarChart(instance) {
997
+ const shell = createSvgShell(instance);
998
+ const { svg, size, theme, plot } = shell;
999
+ const options = instance.options;
1000
+ const seriesList = buildSeriesList(options);
1001
+ const allRows = seriesList.flatMap((series) => series.rows);
1002
+ if (!allRows.length) {
1003
+ renderEmpty(svg, size, theme);
1004
+ return;
1005
+ }
1006
+ const categories = unique(allRows.map((row) => String(row.x)));
1007
+ const xScale = scaleBand({
1008
+ domain: categories,
1009
+ range: [plot.left, plot.right],
1010
+ padding: options.barPadding ?? 0.18
1011
+ });
1012
+ const innerScale = scaleBand({
1013
+ domain: seriesList.map((series) => series.name),
1014
+ range: [0, xScale.bandwidth()],
1015
+ padding: 0.08
1016
+ });
1017
+ const yDomain = niceDomain(
1018
+ allRows.map((row) => row.y),
1019
+ {
1020
+ includeZero: true,
1021
+ min: options.yMin,
1022
+ max: options.yMax,
1023
+ tickCount: options.yTickCount
1024
+ }
1025
+ );
1026
+ const yScale = scaleLinear({ domain: yDomain, range: [plot.bottom, plot.top] });
1027
+ const yTicks = yScale.ticks(options.yTickCount ?? 5);
1028
+ drawCartesianAxes(svg, {
1029
+ plot,
1030
+ xScale,
1031
+ yScale,
1032
+ xTicks: categories,
1033
+ yTicks,
1034
+ theme,
1035
+ options,
1036
+ categoricalX: true
1037
+ });
1038
+ drawAnnotations(svg, options, plot, xScale, yScale, theme);
1039
+ const labels = dataLabelConfig(options);
1040
+ const markGroup = append(svg, svgEl("g", { class: "vd-chart-marks vd-chart-bars" }));
1041
+ const baseline = yScale(0);
1042
+ seriesList.forEach((series) => {
1043
+ const fill = seriesColor(series, theme);
1044
+ series.rows.forEach((row) => {
1045
+ const groupX = xScale(String(row.x));
1046
+ const offset = innerScale(series.name);
1047
+ const y = yScale(row.y);
1048
+ if (![groupX, offset, y, baseline].every(isFiniteNumber)) return;
1049
+ const rectY = Math.min(y, baseline);
1050
+ const rectHeight = Math.max(1, Math.abs(baseline - y));
1051
+ const rect = svgEl("rect", {
1052
+ class: "vd-chart-bar",
1053
+ x: groupX + offset,
1054
+ y: rectY,
1055
+ width: innerScale.bandwidth(),
1056
+ height: rectHeight,
1057
+ rx: 3,
1058
+ fill,
1059
+ role: "graphics-symbol",
1060
+ "aria-label": `${series.name} \u2014 ${formatCategory(row.x)}: ${formatNumber(row.y)}`
1061
+ });
1062
+ makeInteractive(rect, typeof options.onBarClick === "function", options.tooltip !== false);
1063
+ attachTooltip(
1064
+ instance,
1065
+ rect,
1066
+ options,
1067
+ {
1068
+ datum: row.raw,
1069
+ x: row.x,
1070
+ y: row.y,
1071
+ value: row.y,
1072
+ label: row.x,
1073
+ index: row.index,
1074
+ seriesIndex: series.seriesIndex,
1075
+ seriesName: series.name
1076
+ },
1077
+ `${series.name} \u2014 ${formatCategory(row.x)}: ${formatNumber(row.y)}`
1078
+ );
1079
+ attachClick(rect, options.onBarClick, row.raw, row.index);
1080
+ if (labels)
1081
+ drawDataLabel(
1082
+ svg,
1083
+ groupX + offset + innerScale.bandwidth() / 2,
1084
+ rectY - 4,
1085
+ row.y,
1086
+ labels,
1087
+ theme
1088
+ );
1089
+ append(markGroup, rect);
1090
+ });
1091
+ });
1092
+ if (options.legend !== false) {
1093
+ renderTopLegend(
1094
+ svg,
1095
+ seriesList.map((series) => ({ label: series.name, color: seriesColor(series, theme) })),
1096
+ theme,
1097
+ plot
1098
+ );
1099
+ }
1100
+ }
1101
+ function renderLineLikeChart(instance, mode) {
1102
+ if (instance.options.series?.length) return renderMultiLineChart(instance, mode);
1103
+ const shell = createSvgShell(instance);
1104
+ const { svg, size, theme, plot } = shell;
1105
+ const options = instance.options;
1106
+ const data = toArray(options.data);
1107
+ const xAccessor = createAccessor(options.x, "x");
1108
+ const yAccessor = createAccessor(options.y, "y");
1109
+ const rows = data.map((datum, index) => ({
1110
+ raw: datum,
1111
+ index,
1112
+ x: xAccessor(datum),
1113
+ y: toNumber(yAccessor(datum))
1114
+ })).filter((row) => row.x != null && isFiniteNumber(row.y));
1115
+ if (!rows.length) {
1116
+ renderEmpty(svg, size, theme);
1117
+ return;
1118
+ }
1119
+ const xInfo = inferXScale(rows, plot, options);
1120
+ const yDomain = niceDomain(
1121
+ rows.map((row) => row.y),
1122
+ {
1123
+ includeZero: mode === "area" || options.yIncludeZero === true,
1124
+ min: options.yMin,
1125
+ max: options.yMax,
1126
+ tickCount: options.yTickCount
1127
+ }
1128
+ );
1129
+ const yScale = scaleLinear({ domain: yDomain, range: [plot.bottom, plot.top] });
1130
+ const yTicks = yScale.ticks(options.yTickCount ?? 5);
1131
+ const color = options.stroke || theme.colors[0];
1132
+ const points = rows.map((row) => ({
1133
+ raw: row.raw,
1134
+ index: row.index,
1135
+ xValue: row.x,
1136
+ yValue: row.y,
1137
+ x: xInfo.scale(xInfo.mapValue(row.x)),
1138
+ y: yScale(row.y)
1139
+ })).filter((point) => isFiniteNumber(point.x) && isFiniteNumber(point.y));
1140
+ drawCartesianAxes(svg, {
1141
+ plot,
1142
+ xScale: xInfo.scale,
1143
+ yScale,
1144
+ xTicks: xInfo.ticks,
1145
+ yTicks,
1146
+ theme,
1147
+ options,
1148
+ categoricalX: xInfo.type === "point"
1149
+ });
1150
+ drawAnnotations(svg, options, plot, xInfo.scale, yScale, theme);
1151
+ const labels = dataLabelConfig(options);
1152
+ const markGroup = append(svg, svgEl("g", { class: `vd-chart-marks vd-chart-${mode}` }));
1153
+ if (mode === "area") {
1154
+ const baseline = yScale(Math.max(0, yDomain[0]));
1155
+ append(
1156
+ markGroup,
1157
+ svgEl("path", {
1158
+ class: "vd-chart-area-path",
1159
+ d: areaPath(points, baseline),
1160
+ fill: options.fill || color,
1161
+ opacity: options.fillOpacity ?? 0.18,
1162
+ stroke: "none"
1163
+ })
1164
+ );
1165
+ }
1166
+ append(
1167
+ markGroup,
1168
+ svgEl("path", {
1169
+ class: "vd-chart-line-path",
1170
+ d: linePath(points),
1171
+ fill: "none",
1172
+ stroke: color,
1173
+ "stroke-width": options.strokeWidth || 2,
1174
+ "stroke-linecap": "round",
1175
+ "stroke-linejoin": "round"
1176
+ })
1177
+ );
1178
+ if (options.points !== false) {
1179
+ points.forEach((point) => {
1180
+ const circle = svgEl("circle", {
1181
+ class: "vd-chart-point",
1182
+ cx: point.x,
1183
+ cy: point.y,
1184
+ r: options.pointRadius || 3.5,
1185
+ fill: options.pointFill || theme.backgroundColor,
1186
+ stroke: color,
1187
+ "stroke-width": 2,
1188
+ role: "graphics-symbol",
1189
+ "aria-label": `${formatCategory(point.xValue)}: ${formatNumber(point.yValue)}`
1190
+ });
1191
+ makeInteractive(
1192
+ circle,
1193
+ typeof options.onPointClick === "function",
1194
+ options.tooltip !== false
1195
+ );
1196
+ attachTooltip(
1197
+ instance,
1198
+ circle,
1199
+ options,
1200
+ {
1201
+ datum: point.raw,
1202
+ x: point.xValue,
1203
+ y: point.yValue,
1204
+ value: point.yValue,
1205
+ index: point.index
1206
+ },
1207
+ `${formatCategory(point.xValue)}: ${formatNumber(point.yValue)}`
1208
+ );
1209
+ attachClick(circle, options.onPointClick, point.raw, point.index);
1210
+ append(markGroup, circle);
1211
+ });
1212
+ }
1213
+ if (labels) {
1214
+ points.forEach(
1215
+ (point) => drawDataLabel(svg, point.x, point.y - 8, point.yValue, labels, theme)
1216
+ );
1217
+ }
1218
+ }
1219
+ function renderMultiLineChart(instance, mode) {
1220
+ const shell = createSvgShell(instance);
1221
+ const { svg, size, theme, plot } = shell;
1222
+ const options = instance.options;
1223
+ const seriesList = buildSeriesList(options);
1224
+ const allRows = seriesList.flatMap((series) => series.rows);
1225
+ if (!allRows.length) {
1226
+ renderEmpty(svg, size, theme);
1227
+ return;
1228
+ }
1229
+ const xInfo = inferXScale(allRows, plot, options);
1230
+ const yDomain = niceDomain(
1231
+ allRows.map((row) => row.y),
1232
+ {
1233
+ includeZero: mode === "area" || options.yIncludeZero === true,
1234
+ min: options.yMin,
1235
+ max: options.yMax,
1236
+ tickCount: options.yTickCount
1237
+ }
1238
+ );
1239
+ const yScale = scaleLinear({ domain: yDomain, range: [plot.bottom, plot.top] });
1240
+ const yTicks = yScale.ticks(options.yTickCount ?? 5);
1241
+ drawCartesianAxes(svg, {
1242
+ plot,
1243
+ xScale: xInfo.scale,
1244
+ yScale,
1245
+ xTicks: xInfo.ticks,
1246
+ yTicks,
1247
+ theme,
1248
+ options,
1249
+ categoricalX: xInfo.type === "point"
1250
+ });
1251
+ drawAnnotations(svg, options, plot, xInfo.scale, yScale, theme);
1252
+ const labels = dataLabelConfig(options);
1253
+ const markGroup = append(svg, svgEl("g", { class: `vd-chart-marks vd-chart-${mode}` }));
1254
+ const baseline = yScale(Math.max(0, yDomain[0]));
1255
+ seriesList.forEach((series) => {
1256
+ const stroke = seriesColor(series, theme);
1257
+ const points = series.rows.map((row) => ({
1258
+ raw: row.raw,
1259
+ index: row.index,
1260
+ xValue: row.x,
1261
+ yValue: row.y,
1262
+ x: xInfo.scale(xInfo.mapValue(row.x)),
1263
+ y: yScale(row.y)
1264
+ })).filter((point) => isFiniteNumber(point.x) && isFiniteNumber(point.y));
1265
+ if (mode === "area") {
1266
+ append(
1267
+ markGroup,
1268
+ svgEl("path", {
1269
+ class: "vd-chart-area-path",
1270
+ d: areaPath(points, baseline),
1271
+ fill: series.color || stroke,
1272
+ opacity: options.fillOpacity ?? 0.18,
1273
+ stroke: "none"
1274
+ })
1275
+ );
1276
+ }
1277
+ append(
1278
+ markGroup,
1279
+ svgEl("path", {
1280
+ class: "vd-chart-line-path",
1281
+ d: linePath(points),
1282
+ fill: "none",
1283
+ stroke,
1284
+ "stroke-width": options.strokeWidth || 2,
1285
+ "stroke-linecap": "round",
1286
+ "stroke-linejoin": "round"
1287
+ })
1288
+ );
1289
+ if (options.points !== false) {
1290
+ points.forEach((point) => {
1291
+ const circle = svgEl("circle", {
1292
+ class: "vd-chart-point",
1293
+ cx: point.x,
1294
+ cy: point.y,
1295
+ r: options.pointRadius || 3.5,
1296
+ fill: options.pointFill || theme.backgroundColor,
1297
+ stroke,
1298
+ "stroke-width": 2,
1299
+ role: "graphics-symbol",
1300
+ "aria-label": `${series.name} ${formatCategory(point.xValue)}: ${formatNumber(point.yValue)}`
1301
+ });
1302
+ makeInteractive(
1303
+ circle,
1304
+ typeof options.onPointClick === "function",
1305
+ options.tooltip !== false
1306
+ );
1307
+ attachTooltip(
1308
+ instance,
1309
+ circle,
1310
+ options,
1311
+ {
1312
+ datum: point.raw,
1313
+ x: point.xValue,
1314
+ y: point.yValue,
1315
+ value: point.yValue,
1316
+ index: point.index,
1317
+ seriesIndex: series.seriesIndex,
1318
+ seriesName: series.name
1319
+ },
1320
+ `${series.name} \u2014 ${formatCategory(point.xValue)}: ${formatNumber(point.yValue)}`
1321
+ );
1322
+ attachClick(circle, options.onPointClick, point.raw, point.index);
1323
+ append(markGroup, circle);
1324
+ });
1325
+ }
1326
+ if (labels) {
1327
+ points.forEach(
1328
+ (point) => drawDataLabel(svg, point.x, point.y - 8, point.yValue, labels, theme)
1329
+ );
1330
+ }
1331
+ });
1332
+ if (options.legend !== false) {
1333
+ renderTopLegend(
1334
+ svg,
1335
+ seriesList.map((series) => ({ label: series.name, color: seriesColor(series, theme) })),
1336
+ theme,
1337
+ plot
1338
+ );
1339
+ }
1340
+ }
1341
+ function renderScatterChart(instance) {
1342
+ const shell = createSvgShell(instance);
1343
+ const { svg, size, theme, plot } = shell;
1344
+ const options = instance.options;
1345
+ const data = toArray(options.data);
1346
+ const xAccessor = createAccessor(options.x, "x");
1347
+ const yAccessor = createAccessor(options.y, "y");
1348
+ const rows = data.map((datum, index) => ({
1349
+ raw: datum,
1350
+ index,
1351
+ x: xAccessor(datum),
1352
+ y: toNumber(yAccessor(datum))
1353
+ })).filter((row) => row.x != null && isFiniteNumber(row.y));
1354
+ if (!rows.length) {
1355
+ renderEmpty(svg, size, theme);
1356
+ return;
1357
+ }
1358
+ const xInfo = inferXScale(rows, plot, options);
1359
+ const yDomain = niceDomain(
1360
+ rows.map((row) => row.y),
1361
+ {
1362
+ includeZero: options.yIncludeZero === true,
1363
+ min: options.yMin,
1364
+ max: options.yMax,
1365
+ tickCount: options.yTickCount
1366
+ }
1367
+ );
1368
+ const yScale = scaleLinear({ domain: yDomain, range: [plot.bottom, plot.top] });
1369
+ const yTicks = yScale.ticks(options.yTickCount ?? 5);
1370
+ const color = getColorScale(rows, options.color, theme);
1371
+ drawCartesianAxes(svg, {
1372
+ plot,
1373
+ xScale: xInfo.scale,
1374
+ yScale,
1375
+ xTicks: xInfo.ticks,
1376
+ yTicks,
1377
+ theme,
1378
+ options,
1379
+ categoricalX: xInfo.type === "point"
1380
+ });
1381
+ drawAnnotations(svg, options, plot, xInfo.scale, yScale, theme);
1382
+ const labels = dataLabelConfig(options);
1383
+ const markGroup = append(svg, svgEl("g", { class: "vd-chart-marks vd-chart-scatter" }));
1384
+ rows.forEach((row) => {
1385
+ const cx = xInfo.scale(xInfo.mapValue(row.x));
1386
+ const cy = yScale(row.y);
1387
+ if (!isFiniteNumber(cx) || !isFiniteNumber(cy)) return;
1388
+ const fill = colorForRow(color, row, theme);
1389
+ const circle = svgEl("circle", {
1390
+ class: "vd-chart-scatter-point",
1391
+ cx,
1392
+ cy,
1393
+ r: options.pointRadius || 4,
1394
+ fill,
1395
+ opacity: options.pointOpacity ?? 0.88,
1396
+ role: "graphics-symbol",
1397
+ "aria-label": `${formatCategory(row.x)}: ${formatNumber(row.y)}`
1398
+ });
1399
+ makeInteractive(circle, typeof options.onPointClick === "function", options.tooltip !== false);
1400
+ attachTooltip(
1401
+ instance,
1402
+ circle,
1403
+ options,
1404
+ {
1405
+ datum: row.raw,
1406
+ x: row.x,
1407
+ y: row.y,
1408
+ value: row.y,
1409
+ index: row.index
1410
+ },
1411
+ `${formatCategory(row.x)}: ${formatNumber(row.y)}`
1412
+ );
1413
+ attachClick(circle, options.onPointClick, row.raw, row.index);
1414
+ if (labels) drawDataLabel(svg, cx, cy - 8, row.y, labels, theme);
1415
+ append(markGroup, circle);
1416
+ });
1417
+ if (options.legend && color && color.scale) {
1418
+ renderTopLegend(
1419
+ svg,
1420
+ color.scale.domain().map((cat) => ({ label: cat, color: color.scale(cat) })),
1421
+ theme,
1422
+ plot
1423
+ );
1424
+ }
1425
+ }
1426
+ function renderLegend(svg, rows, colorScale, theme, x, y) {
1427
+ const legend = append(svg, svgEl("g", { class: "vd-chart-legend" }));
1428
+ rows.slice(0, 8).forEach((row, index) => {
1429
+ const itemY = y + index * 20;
1430
+ append(
1431
+ legend,
1432
+ svgEl("rect", {
1433
+ x,
1434
+ y: itemY - 9,
1435
+ width: 10,
1436
+ height: 10,
1437
+ rx: 2,
1438
+ fill: colorScale(row.label)
1439
+ })
1440
+ );
1441
+ append(
1442
+ legend,
1443
+ setText(
1444
+ svgEl("text", {
1445
+ x: x + 16,
1446
+ y: itemY,
1447
+ fill: theme.mutedTextColor,
1448
+ "font-size": 11
1449
+ }),
1450
+ formatCategory(row.label)
1451
+ )
1452
+ );
1453
+ });
1454
+ }
1455
+ function renderDonutChart(instance) {
1456
+ instance.options.polar = true;
1457
+ const shell = createSvgShell(instance);
1458
+ const { svg, size, theme, plot } = shell;
1459
+ const options = instance.options;
1460
+ const data = toArray(options.data);
1461
+ const labelAccessor = createAccessor(options.label, "label");
1462
+ const valueAccessor = createAccessor(options.value, "value");
1463
+ const rows = data.map((datum, index) => ({
1464
+ raw: datum,
1465
+ index,
1466
+ label: labelAccessor(datum),
1467
+ value: toNumber(valueAccessor(datum))
1468
+ })).filter((row) => row.label != null && isFiniteNumber(row.value) && row.value > 0);
1469
+ const total = rows.reduce((sum, row) => sum + row.value, 0);
1470
+ if (!rows.length || total <= 0) {
1471
+ renderEmpty(svg, size, theme);
1472
+ return;
1473
+ }
1474
+ const legendSpace = options.legend === false || size.width < 520 ? 0 : 128;
1475
+ const cx = (plot.left + plot.right - legendSpace) / 2;
1476
+ const cy = (plot.top + plot.bottom) / 2 + 5;
1477
+ const outerRadius = Math.max(
1478
+ 28,
1479
+ Math.min(plot.right - plot.left - legendSpace, plot.bottom - plot.top) / 2
1480
+ );
1481
+ const ratio = Math.max(0, Math.min(0.9, Number(options.innerRadiusRatio ?? 0.62)));
1482
+ const innerRadius = outerRadius * ratio;
1483
+ const colorScale = scaleOrdinal({ domain: rows.map((row) => row.label), range: theme.colors });
1484
+ const labels = dataLabelConfig(options);
1485
+ const markGroup = append(svg, svgEl("g", { class: "vd-chart-marks vd-chart-slices" }));
1486
+ let cursor = -Math.PI / 2;
1487
+ rows.forEach((row) => {
1488
+ const angle = row.value / total * TAU;
1489
+ const start = cursor;
1490
+ const end = cursor + angle;
1491
+ cursor = end;
1492
+ const path = svgEl("path", {
1493
+ class: "vd-chart-slice",
1494
+ d: arcPath(cx, cy, outerRadius, innerRadius, start, end),
1495
+ fill: colorScale(row.label),
1496
+ stroke: theme.backgroundColor,
1497
+ "stroke-width": 2,
1498
+ role: "graphics-symbol",
1499
+ "aria-label": `${formatCategory(row.label)}: ${formatNumber(row.value)}`
1500
+ });
1501
+ makeInteractive(path, typeof options.onSliceClick === "function", options.tooltip !== false);
1502
+ attachTooltip(
1503
+ instance,
1504
+ path,
1505
+ options,
1506
+ {
1507
+ datum: row.raw,
1508
+ label: row.label,
1509
+ value: row.value,
1510
+ y: row.value,
1511
+ index: row.index
1512
+ },
1513
+ `${formatCategory(row.label)}: ${formatNumber(row.value)}`
1514
+ );
1515
+ attachClick(path, options.onSliceClick, row.raw, row.index);
1516
+ if (labels) {
1517
+ const mid = (start + end) / 2;
1518
+ const point = polarPoint(cx, cy, (innerRadius + outerRadius) / 2, mid);
1519
+ drawDataLabel(svg, point.x, point.y, row.value, labels, theme);
1520
+ }
1521
+ append(markGroup, path);
1522
+ });
1523
+ if (innerRadius > 16 && options.centerLabel !== false) {
1524
+ append(
1525
+ svg,
1526
+ setText(
1527
+ svgEl("text", {
1528
+ x: cx,
1529
+ y: cy - 2,
1530
+ fill: theme.textColor,
1531
+ "font-size": 18,
1532
+ "font-weight": 700,
1533
+ "text-anchor": "middle"
1534
+ }),
1535
+ options.centerLabel || formatNumber(total)
1536
+ )
1537
+ );
1538
+ append(
1539
+ svg,
1540
+ setText(
1541
+ svgEl("text", {
1542
+ x: cx,
1543
+ y: cy + 16,
1544
+ fill: theme.mutedTextColor,
1545
+ "font-size": 11,
1546
+ "text-anchor": "middle"
1547
+ }),
1548
+ options.centerSubLabel || "total"
1549
+ )
1550
+ );
1551
+ }
1552
+ if (legendSpace) {
1553
+ renderLegend(svg, rows, colorScale, theme, plot.right - legendSpace + 8, plot.top + 28);
1554
+ }
1555
+ }
1556
+ var ChartInstance = class {
1557
+ constructor(kind, options, renderer) {
1558
+ this.kind = kind;
1559
+ this.options = { ...options };
1560
+ this.target = resolveTarget(options.target);
1561
+ this.renderer = renderer;
1562
+ this.resizeObserver = null;
1563
+ this.destroyed = false;
1564
+ this.theme = null;
1565
+ this.size = null;
1566
+ this.plot = null;
1567
+ this.tooltipEl = null;
1568
+ this.render();
1569
+ this.setupResizeObserver();
1570
+ }
1571
+ render() {
1572
+ if (this.destroyed) return this;
1573
+ this.renderer(this);
1574
+ return this;
1575
+ }
1576
+ update(nextOptions = {}) {
1577
+ if (this.destroyed) return this;
1578
+ this.options = { ...this.options, ...nextOptions };
1579
+ return this.render();
1580
+ }
1581
+ resize() {
1582
+ return this.render();
1583
+ }
1584
+ setupResizeObserver() {
1585
+ if (this.options.responsive === false || !hasWindow() || typeof ResizeObserver === "undefined")
1586
+ return;
1587
+ let lastWidth = this.target.clientWidth;
1588
+ let lastHeight = this.target.clientHeight;
1589
+ this.resizeObserver = new ResizeObserver(() => {
1590
+ const width = this.target.clientWidth;
1591
+ const height = this.target.clientHeight;
1592
+ if (width === lastWidth && height === lastHeight) return;
1593
+ lastWidth = width;
1594
+ lastHeight = height;
1595
+ this.resize();
1596
+ });
1597
+ this.resizeObserver.observe(this.target);
1598
+ }
1599
+ ensureTooltip() {
1600
+ if (this.tooltipEl && this.tooltipEl.isConnected) return this.tooltipEl;
1601
+ const tooltip = document.createElement("div");
1602
+ tooltip.className = "vd-chart-tooltip";
1603
+ tooltip.setAttribute("role", "status");
1604
+ tooltip.setAttribute("aria-live", "polite");
1605
+ this.target.appendChild(tooltip);
1606
+ this.tooltipEl = tooltip;
1607
+ return tooltip;
1608
+ }
1609
+ showTooltip(content, event) {
1610
+ const tooltip = this.ensureTooltip();
1611
+ tooltip.textContent = String(content);
1612
+ const rect = this.target.getBoundingClientRect();
1613
+ let x = rect.width / 2;
1614
+ let y = rect.height / 2;
1615
+ if (event && isFiniteNumber(event.clientX) && isFiniteNumber(event.clientY)) {
1616
+ x = event.clientX - rect.left;
1617
+ y = event.clientY - rect.top;
1618
+ } else if (event && event.target && typeof event.target.getBoundingClientRect === "function") {
1619
+ const markRect = event.target.getBoundingClientRect();
1620
+ x = markRect.left + markRect.width / 2 - rect.left;
1621
+ y = markRect.top - rect.top;
1622
+ }
1623
+ tooltip.style.left = `${Math.max(8, Math.min(rect.width - 8, x))}px`;
1624
+ tooltip.style.top = `${Math.max(18, Math.min(rect.height - 8, y))}px`;
1625
+ tooltip.classList.add("is-visible");
1626
+ }
1627
+ hideTooltip() {
1628
+ if (this.tooltipEl) {
1629
+ this.tooltipEl.classList.remove("is-visible");
1630
+ }
1631
+ }
1632
+ destroy() {
1633
+ if (this.destroyed) return;
1634
+ if (this.resizeObserver) {
1635
+ this.resizeObserver.disconnect();
1636
+ this.resizeObserver = null;
1637
+ }
1638
+ this.target.innerHTML = "";
1639
+ this.target.classList.remove("vd-chart-root", `vd-chart-${this.kind}`);
1640
+ this.destroyed = true;
1641
+ }
1642
+ };
1643
+ function createChartFactory(kind, renderer, defaults = {}) {
1644
+ return function chartFactory(options = {}) {
1645
+ return new ChartInstance(kind, { ...defaults, ...options }, renderer);
1646
+ };
1647
+ }
1648
+ var BarChart = createChartFactory("bar", renderBarChart);
1649
+ var LineChart = createChartFactory(
1650
+ "line",
1651
+ (instance) => renderLineLikeChart(instance, "line")
1652
+ );
1653
+ var AreaChart = createChartFactory(
1654
+ "area",
1655
+ (instance) => renderLineLikeChart(instance, "area")
1656
+ );
1657
+ var ScatterChart = createChartFactory("scatter", renderScatterChart);
1658
+ var DonutChart = createChartFactory("donut", renderDonutChart, { innerRadiusRatio: 0.62 });
1659
+ var PieChart = createChartFactory("pie", renderDonutChart, { innerRadiusRatio: 0 });
1660
+
1661
+ // src/charts/vue.js
1662
+ var FACTORIES = {
1663
+ bar: BarChart,
1664
+ line: LineChart,
1665
+ area: AreaChart,
1666
+ scatter: ScatterChart,
1667
+ donut: DonutChart,
1668
+ pie: PieChart
1669
+ };
1670
+ var CHART_PROPS = {
1671
+ type: { type: String, default: "bar" },
1672
+ data: { type: Array, default: () => [] },
1673
+ x: { type: [String, Function], default: void 0 },
1674
+ y: { type: [String, Function], default: void 0 },
1675
+ label: { type: [String, Function], default: void 0 },
1676
+ value: { type: [String, Function], default: void 0 },
1677
+ // CSS color, category-field name, or per-datum function `(row) => color`.
1678
+ color: { type: [String, Function], default: void 0 },
1679
+ title: { type: String, default: void 0 },
1680
+ description: { type: String, default: void 0 },
1681
+ width: { type: Number, default: void 0 },
1682
+ height: { type: Number, default: 300 },
1683
+ innerRadiusRatio: { type: Number, default: void 0 },
1684
+ theme: { type: Object, default: void 0 },
1685
+ tooltip: { type: [Function, String, Boolean], default: void 0 },
1686
+ responsive: { type: Boolean, default: true },
1687
+ // Multi-series (bar → grouped, line/area → one path each).
1688
+ series: { type: Array, default: void 0 },
1689
+ // `true` / `false` / `{ position }`.
1690
+ legend: { type: [Boolean, Object], default: void 0 },
1691
+ // Value labels on marks: `true` / `false` / `{ format, color }`.
1692
+ dataLabels: { type: [Boolean, Object], default: void 0 },
1693
+ // Reference lines: `[{ y?, x?, label?, color?, dash? }]`.
1694
+ annotations: { type: Array, default: void 0 },
1695
+ // Axis range + ticks.
1696
+ xMin: { type: Number, default: void 0 },
1697
+ xMax: { type: Number, default: void 0 },
1698
+ yMin: { type: Number, default: void 0 },
1699
+ yMax: { type: Number, default: void 0 },
1700
+ yTickCount: { type: Number, default: void 0 },
1701
+ yIncludeZero: { type: Boolean, default: void 0 },
1702
+ xFormat: { type: Function, default: void 0 },
1703
+ yFormat: { type: Function, default: void 0 },
1704
+ xAxis: { type: Object, default: void 0 },
1705
+ yAxis: { type: Object, default: void 0 }
1706
+ };
1707
+ function optionsFrom(target, props) {
1708
+ return {
1709
+ target,
1710
+ type: props.type,
1711
+ data: props.data,
1712
+ x: props.x,
1713
+ y: props.y,
1714
+ label: props.label,
1715
+ value: props.value,
1716
+ color: props.color,
1717
+ title: props.title,
1718
+ description: props.description,
1719
+ width: props.width,
1720
+ height: props.height,
1721
+ innerRadiusRatio: props.innerRadiusRatio,
1722
+ theme: props.theme,
1723
+ tooltip: props.tooltip,
1724
+ responsive: props.responsive,
1725
+ series: props.series,
1726
+ legend: props.legend,
1727
+ dataLabels: props.dataLabels,
1728
+ annotations: props.annotations,
1729
+ xMin: props.xMin,
1730
+ xMax: props.xMax,
1731
+ yMin: props.yMin,
1732
+ yMax: props.yMax,
1733
+ yTickCount: props.yTickCount,
1734
+ yIncludeZero: props.yIncludeZero,
1735
+ xFormat: props.xFormat,
1736
+ yFormat: props.yFormat,
1737
+ xAxis: props.xAxis,
1738
+ yAxis: props.yAxis
1739
+ };
1740
+ }
1741
+ var VdChart = (0, import_vue.defineComponent)({
1742
+ name: "VdChart",
1743
+ props: CHART_PROPS,
1744
+ setup(props) {
1745
+ const el = (0, import_vue.ref)(null);
1746
+ let instance = null;
1747
+ let currentType = props.type;
1748
+ const create = () => {
1749
+ const factory = FACTORIES[props.type] || BarChart;
1750
+ currentType = props.type;
1751
+ instance = factory(optionsFrom(el.value, props));
1752
+ };
1753
+ (0, import_vue.onMounted)(() => {
1754
+ if (typeof window === "undefined" || !el.value) return;
1755
+ create();
1756
+ });
1757
+ (0, import_vue.watch)(
1758
+ () => [
1759
+ props.type,
1760
+ props.data,
1761
+ props.x,
1762
+ props.y,
1763
+ props.label,
1764
+ props.value,
1765
+ props.color,
1766
+ props.title,
1767
+ props.description,
1768
+ props.width,
1769
+ props.height,
1770
+ props.innerRadiusRatio,
1771
+ props.theme,
1772
+ props.tooltip,
1773
+ props.responsive,
1774
+ props.series,
1775
+ props.legend,
1776
+ props.dataLabels,
1777
+ props.annotations,
1778
+ props.xMin,
1779
+ props.xMax,
1780
+ props.yMin,
1781
+ props.yMax,
1782
+ props.yTickCount,
1783
+ props.yIncludeZero,
1784
+ props.xFormat,
1785
+ props.yFormat,
1786
+ props.xAxis,
1787
+ props.yAxis
1788
+ ],
1789
+ () => {
1790
+ if (!instance) return;
1791
+ if (props.type !== currentType) {
1792
+ instance.destroy();
1793
+ create();
1794
+ } else {
1795
+ instance.update(optionsFrom(el.value, props));
1796
+ }
1797
+ },
1798
+ { deep: true }
1799
+ );
1800
+ (0, import_vue.onBeforeUnmount)(() => {
1801
+ if (instance) {
1802
+ instance.destroy();
1803
+ instance = null;
1804
+ }
1805
+ });
1806
+ return () => (0, import_vue.h)("div", {
1807
+ ref: el,
1808
+ class: "vd-chart",
1809
+ style: props.height ? { minHeight: `${props.height}px` } : void 0
1810
+ });
1811
+ }
1812
+ });
1813
+ function typed(name, type) {
1814
+ return (0, import_vue.defineComponent)({
1815
+ name,
1816
+ props: CHART_PROPS,
1817
+ setup(props) {
1818
+ return () => (0, import_vue.h)(VdChart, { ...props, type });
1819
+ }
1820
+ });
1821
+ }
1822
+ var VdBarChart = typed("VdBarChart", "bar");
1823
+ var VdLineChart = typed("VdLineChart", "line");
1824
+ var VdAreaChart = typed("VdAreaChart", "area");
1825
+ var VdScatterChart = typed("VdScatterChart", "scatter");
1826
+ var VdDonutChart = typed("VdDonutChart", "donut");
1827
+ var VdPieChart = typed("VdPieChart", "pie");
1828
+ //# sourceMappingURL=index.cjs.map