@wil-works/evoke-charts 0.6.0 → 0.7.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 +35 -1
- package/dist/3d.mjs +4992 -0
- package/dist/{ai-B5Fk3lBQ.js → ai-cRi95pS2.js} +383 -323
- package/dist/ai.mjs +2 -2
- package/dist/evoke-charts.css +192 -32
- package/dist/index.mjs +139 -162
- package/dist/palette-lwVAltky.js +117 -0
- package/dist/schema-CM4hKlpc.js +1102 -0
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as isMissingValue, A as vennHitTest, B as doughnutInnerRadius, C as windowToX, D as arcHitTest, E as ganttHitTest, F as squarifyTreemap, G as getToolboxBounds, H as scatterGroupColors, I as buildPieSlices, J as getHeatmapCategories, K as calendarHitTest, L as computeFacetGrids, M as computeSunburstGeometry, N as sunburstValue, O as chordHitTest, P as computeBins, Q as getTheme, R as computeMatrixCells, S as getSliderGeometry, T as zoomToSlice, U as scatterPointPositions, V as matrixFieldExtent, W as getLegendBounds, X as createAnimation, Y as xToCategoryIndex, Z as getPadding, _ as chartOptionsSchema, at as INTERACTION, b as createSvgRecorder, ct as resolveCursor, et as resolveTickExtendedRange, h as parseDataTable, it as minOf, j as boxplotHitTest, k as sankeyHitTest, l as generateChartSpec, n as buildChartPrompt, nt as waterfallSteps, ot as applyWheelZoom, q as funnelStepColor, rt as maxOf, st as pickTooltipRows, t as lintChartSpec, tt as updateAnimation, v as validateOptions, w as xToPercent, x as getDataZoomConfig, y as renderChart, z as computePieMaxRadius } from "./ai-cRi95pS2.js";
|
|
2
|
+
import { a as staggerProgress, i as prefersReducedMotion, n as clearSeriesPalette, r as _plugin_vue_export_helper_default, t as applySeriesPalette } from "./palette-lwVAltky.js";
|
|
3
|
+
import { S as DEFAULT_I18N_ZH, b as resolveChartPalette, y as CHART_PALETTES } from "./schema-CM4hKlpc.js";
|
|
2
4
|
import { Fragment, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, h, inject, nextTick, normalizeClass, normalizeStyle, onMounted, onUnmounted, openBlock, provide, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, watch, withCtx } from "vue";
|
|
3
5
|
//#region src/connect.js
|
|
4
6
|
var connectGroups = /* @__PURE__ */ new Map();
|
|
@@ -22,13 +24,6 @@ function broadcastConnect(group, source, apply) {
|
|
|
22
24
|
});
|
|
23
25
|
}
|
|
24
26
|
//#endregion
|
|
25
|
-
//#region \0plugin-vue:export-helper
|
|
26
|
-
var _plugin_vue_export_helper_default = (sfc, props) => {
|
|
27
|
-
const target = sfc.__vccOpts || sfc;
|
|
28
|
-
for (const [key, val] of props) target[key] = val;
|
|
29
|
-
return target;
|
|
30
|
-
};
|
|
31
|
-
//#endregion
|
|
32
27
|
//#region src/chart.vue
|
|
33
28
|
var _hoisted_1 = ["tabindex", "aria-label"];
|
|
34
29
|
var _hoisted_2 = {
|
|
@@ -434,10 +429,18 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
434
429
|
options: props.options
|
|
435
430
|
};
|
|
436
431
|
const animCfg = animOverride || props.options.animation;
|
|
437
|
-
const animEnabled = animate && animCfg?.enabled !== false;
|
|
432
|
+
const animEnabled = animate && animCfg?.enabled !== false && !prefersReducedMotion();
|
|
433
|
+
const stagger = staggerOf(effectiveOptions.value);
|
|
438
434
|
animationState = createAnimation(animCfg);
|
|
439
435
|
animationState.isAnimating = animEnabled;
|
|
440
|
-
if (animEnabled) {
|
|
436
|
+
if (animEnabled && stagger > 0 && hasInterpolatable(effectiveOptions.value)) {
|
|
437
|
+
isEnterAnimating = true;
|
|
438
|
+
runDataTween(zeroSnapshot(effectiveOptions.value), animCfg, stagger, () => {
|
|
439
|
+
isEnterAnimating = false;
|
|
440
|
+
emit("animation-end");
|
|
441
|
+
emit("ready");
|
|
442
|
+
});
|
|
443
|
+
} else if (animEnabled) {
|
|
441
444
|
isEnterAnimating = true;
|
|
442
445
|
animateFrame();
|
|
443
446
|
} else {
|
|
@@ -504,39 +507,68 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
504
507
|
}
|
|
505
508
|
}
|
|
506
509
|
function snapshotSeriesData(opt) {
|
|
507
|
-
const
|
|
508
|
-
(opt.series || []).forEach((s) =>
|
|
509
|
-
|
|
510
|
+
const series = /* @__PURE__ */ new Map();
|
|
511
|
+
(opt.series || []).forEach((s) => series.set(s.name, (s.data || []).map((v) => isMissingValue(v) ? 0 : v)));
|
|
512
|
+
const pieData = /* @__PURE__ */ new Map();
|
|
513
|
+
(opt.pieData || []).forEach((d) => pieData.set(d && d.name, Number.isFinite(Number(d && d.value)) ? Number(d.value) : 0));
|
|
514
|
+
return {
|
|
515
|
+
series,
|
|
516
|
+
pieData
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
/** 有没有可插值的数值面(series / pieData 任一),都没有就不该走数据级补间 */
|
|
520
|
+
function hasInterpolatable(opt) {
|
|
521
|
+
if ((opt.series || []).some((s) => Array.isArray(s.data) && s.data.length)) return true;
|
|
522
|
+
return (opt.pieData || []).length > 0;
|
|
510
523
|
}
|
|
511
524
|
function sameStructure(a, b) {
|
|
512
525
|
const la = a.labels || [];
|
|
513
526
|
const lb = b.labels || [];
|
|
514
527
|
if (la.length !== lb.length || la.some((v, i) => v !== lb[i])) return false;
|
|
515
|
-
|
|
528
|
+
if ((a.series || []).map((s) => s.name).join("|") !== (b.series || []).map((s) => s.name).join("|")) return false;
|
|
529
|
+
return (a.pieData || []).map((d) => d && d.name).join("|") === (b.pieData || []).map((d) => d && d.name).join("|");
|
|
516
530
|
}
|
|
517
|
-
function interpolateOptions(prev, next, t) {
|
|
531
|
+
function interpolateOptions(prev, next, t, stagger = 0) {
|
|
518
532
|
const offset = next.__sliceStart || 0;
|
|
533
|
+
const cols = Math.max(1, (next.labels || []).length);
|
|
519
534
|
const series = (next.series || []).map((s) => {
|
|
520
|
-
const old = prev.get(s.name);
|
|
535
|
+
const old = prev.series.get(s.name);
|
|
521
536
|
if (!old) return s;
|
|
522
537
|
const data = (s.data || []).map((v, i) => {
|
|
523
538
|
if (isMissingValue(v)) return v;
|
|
524
539
|
const from = old[i + offset] ?? 0;
|
|
525
|
-
|
|
540
|
+
const ti = staggerProgress(t, i, cols, stagger);
|
|
541
|
+
return from + (v - from) * ti;
|
|
526
542
|
});
|
|
527
543
|
return {
|
|
528
544
|
...s,
|
|
529
545
|
data
|
|
530
546
|
};
|
|
531
547
|
});
|
|
532
|
-
|
|
548
|
+
const out = {
|
|
533
549
|
...next,
|
|
534
550
|
series
|
|
535
551
|
};
|
|
552
|
+
if (Array.isArray(next.pieData)) {
|
|
553
|
+
const sliceCount = Math.max(1, next.pieData.length);
|
|
554
|
+
out.pieData = next.pieData.map((d, i) => {
|
|
555
|
+
const to = Number(d && d.value);
|
|
556
|
+
if (!Number.isFinite(to)) return d;
|
|
557
|
+
const from = prev.pieData.get(d && d.name) ?? 0;
|
|
558
|
+
const ti = staggerProgress(t, i, sliceCount, stagger);
|
|
559
|
+
return {
|
|
560
|
+
...d,
|
|
561
|
+
value: from + (to - from) * ti
|
|
562
|
+
};
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
return out;
|
|
536
566
|
}
|
|
537
567
|
function dataSignature(opt) {
|
|
538
|
-
const
|
|
539
|
-
|
|
568
|
+
const seriesTotal = (opt.series || []).reduce((sum, s) => sum + (s.data || []).reduce((acc, v) => acc + (isMissingValue(v) ? 0 : v), 0), 0);
|
|
569
|
+
const pieTotal = (opt.pieData || []).reduce((sum, d) => sum + (Number.isFinite(Number(d && d.value)) ? Math.abs(Number(d.value)) : 0), 0);
|
|
570
|
+
const pieCount = (opt.pieData || []).length;
|
|
571
|
+
return `${(opt.series || []).length}\u7CFB\u5217/${pieCount}\u997C\u9879/${(opt.labels || []).length}\u7C7B\u76EE/\u03A3${Math.round(seriesTotal + pieTotal)}`;
|
|
540
572
|
}
|
|
541
573
|
function stopTweenAnimation() {
|
|
542
574
|
if (tweenFrameId !== null) {
|
|
@@ -545,28 +577,32 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
545
577
|
}
|
|
546
578
|
tweenState = null;
|
|
547
579
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
580
|
+
/** 错峰占比(0 = 关闭,沿用统一 progress 的进场动画) */
|
|
581
|
+
function staggerOf(opt) {
|
|
582
|
+
const v = opt && opt.animation ? opt.animation.stagger : void 0;
|
|
583
|
+
return Number.isFinite(v) ? Math.max(0, Math.min(1, v)) : 0;
|
|
584
|
+
}
|
|
585
|
+
/** 全零数据快照 — 分段进场的起点(逐条长到目标值) */
|
|
586
|
+
function zeroSnapshot(opt) {
|
|
587
|
+
const series = /* @__PURE__ */ new Map();
|
|
588
|
+
(opt.series || []).forEach((s) => series.set(s.name, (s.data || []).map(() => 0)));
|
|
589
|
+
const pieData = /* @__PURE__ */ new Map();
|
|
590
|
+
(opt.pieData || []).forEach((d) => pieData.set(d && d.name, 0));
|
|
591
|
+
return {
|
|
592
|
+
series,
|
|
593
|
+
pieData
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
/** 数据补间主循环 — 更新补间与分段进场共用,按类目错峰插值后以 progress = 1 重绘 */
|
|
597
|
+
function runDataTween(fromSnapshot, cfg, stagger, onDone) {
|
|
558
598
|
stopAnimation();
|
|
559
599
|
stopHoverAnimation();
|
|
560
|
-
isEnterAnimating = false;
|
|
561
600
|
stopTweenAnimation();
|
|
562
|
-
|
|
563
|
-
tweenState = createAnimation(nextOptions.animation);
|
|
564
|
-
const fromSig = dataSignature(prevOptions);
|
|
565
|
-
const toSig = dataSignature(nextOptions);
|
|
601
|
+
tweenState = createAnimation(cfg);
|
|
566
602
|
function frame() {
|
|
567
603
|
if (!tweenState) return;
|
|
568
604
|
const isAnimating = updateAnimation(tweenState);
|
|
569
|
-
const tweened = interpolateOptions(
|
|
605
|
+
const tweened = interpolateOptions(fromSnapshot, effectiveOptions.value, tweenState.progress, stagger);
|
|
570
606
|
try {
|
|
571
607
|
renderChart(canvasRef.value, buildRenderParams(1, tweened));
|
|
572
608
|
} catch (err) {
|
|
@@ -577,16 +613,40 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
577
613
|
else {
|
|
578
614
|
tweenFrameId = null;
|
|
579
615
|
tweenState = null;
|
|
580
|
-
|
|
581
|
-
from: fromSig,
|
|
582
|
-
to: toSig
|
|
583
|
-
});
|
|
584
|
-
emit("animation-end");
|
|
616
|
+
if (onDone) onDone();
|
|
585
617
|
}
|
|
586
618
|
}
|
|
587
619
|
tweenFrameId = requestAnimationFrame(frame);
|
|
588
620
|
return true;
|
|
589
621
|
}
|
|
622
|
+
function startTweenIfNeeded(prevOptions) {
|
|
623
|
+
const nextOptions = props.options;
|
|
624
|
+
if (nextOptions.animation?.enabled === false) return false;
|
|
625
|
+
if (prefersReducedMotion()) return false;
|
|
626
|
+
if (!hasInterpolatable(nextOptions) || !sameStructure(prevOptions, nextOptions)) return false;
|
|
627
|
+
const prevSnapshot = snapshotSeriesData(prevOptions);
|
|
628
|
+
const seriesChanged = (nextOptions.series || []).some((s) => {
|
|
629
|
+
const old = prevSnapshot.series.get(s.name);
|
|
630
|
+
if (!old) return false;
|
|
631
|
+
return (s.data || []).some((v, i) => (isMissingValue(v) ? 0 : v) !== (old[i] ?? 0));
|
|
632
|
+
});
|
|
633
|
+
const pieChanged = (nextOptions.pieData || []).some((d) => {
|
|
634
|
+
const old = prevSnapshot.pieData.get(d && d.name);
|
|
635
|
+
const v = Number(d && d.value);
|
|
636
|
+
return old !== void 0 && Number.isFinite(v) && v !== old;
|
|
637
|
+
});
|
|
638
|
+
if (!seriesChanged && !pieChanged) return false;
|
|
639
|
+
isEnterAnimating = false;
|
|
640
|
+
const fromSig = dataSignature(prevOptions);
|
|
641
|
+
const toSig = dataSignature(nextOptions);
|
|
642
|
+
return runDataTween(prevSnapshot, nextOptions.animation, staggerOf(nextOptions), () => {
|
|
643
|
+
emit("data-update", {
|
|
644
|
+
from: fromSig,
|
|
645
|
+
to: toSig
|
|
646
|
+
});
|
|
647
|
+
emit("animation-end");
|
|
648
|
+
});
|
|
649
|
+
}
|
|
590
650
|
function handleRenderError(err) {
|
|
591
651
|
const msg = err instanceof Error ? err.message : "Chart render error";
|
|
592
652
|
internalError.value = msg;
|
|
@@ -901,9 +961,9 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
901
961
|
b.min,
|
|
902
962
|
b.max,
|
|
903
963
|
...showOutliers ? b.outliers || [] : []
|
|
904
|
-
]);
|
|
964
|
+
]).filter((v) => typeof v === "number" && Number.isFinite(v));
|
|
905
965
|
const axisCfg = options.boxHorizontal ? options.xAxis || {} : options.yAxis || {};
|
|
906
|
-
const ext = resolveTickExtendedRange(axisCfg.min ?? minOf(allValues), axisCfg.max ?? maxOf(allValues), axisCfg.ticks || 5);
|
|
966
|
+
const ext = resolveTickExtendedRange(axisCfg.min ?? (allValues.length ? minOf(allValues) : 0), axisCfg.max ?? (allValues.length ? maxOf(allValues) : 1), axisCfg.ticks || 5);
|
|
907
967
|
return boxplotHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value, {
|
|
908
968
|
min: ext.min,
|
|
909
969
|
max: ext.max
|
|
@@ -1204,7 +1264,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1204
1264
|
params: visibleSeries2.map((s, sIdx) => ({
|
|
1205
1265
|
seriesName: s.name,
|
|
1206
1266
|
name: labels2[i] || `Point ${i + 1}`,
|
|
1207
|
-
value: s.data[i],
|
|
1267
|
+
value: (s.data || [])[i],
|
|
1208
1268
|
color: s.color || theme.colors[options.series.indexOf(s) % theme.colors.length],
|
|
1209
1269
|
dataIndex: i,
|
|
1210
1270
|
seriesIndex: sIdx
|
|
@@ -1223,7 +1283,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1223
1283
|
params: visibleSeries2.map((s, sIdx) => ({
|
|
1224
1284
|
seriesName: s.name,
|
|
1225
1285
|
name: labels2[i],
|
|
1226
|
-
value: s.data[i],
|
|
1286
|
+
value: (s.data || [])[i],
|
|
1227
1287
|
color: s.color || theme.colors[options.series.indexOf(s) % theme.colors.length],
|
|
1228
1288
|
dataIndex: i,
|
|
1229
1289
|
seriesIndex: sIdx
|
|
@@ -1274,13 +1334,13 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1274
1334
|
if (visibleSeries.length === 0) return null;
|
|
1275
1335
|
const volume = (options.volumeData || [])[dataIndex];
|
|
1276
1336
|
if (props.options.tooltip?.showAllSeries !== false && visibleSeries.length > 1) {
|
|
1277
|
-
if (visibleSeries.every((s) => isMissingValue(s.data[dataIndex]))) return null;
|
|
1337
|
+
if (visibleSeries.every((s) => isMissingValue((s.data || [])[dataIndex]))) return null;
|
|
1278
1338
|
return {
|
|
1279
1339
|
index: dataIndex,
|
|
1280
1340
|
params: visibleSeries.map((s, sIdx) => ({
|
|
1281
1341
|
seriesName: s.name,
|
|
1282
1342
|
name: labels[dataIndex],
|
|
1283
|
-
value: s.data[dataIndex],
|
|
1343
|
+
value: (s.data || [])[dataIndex],
|
|
1284
1344
|
volume,
|
|
1285
1345
|
color: s.color || theme.colors[options.series.indexOf(s) % theme.colors.length],
|
|
1286
1346
|
dataIndex: dataIndex + sliceStartOffset(),
|
|
@@ -1289,14 +1349,14 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1289
1349
|
};
|
|
1290
1350
|
} else {
|
|
1291
1351
|
const series = visibleSeries[0];
|
|
1292
|
-
if (isMissingValue(series.data[dataIndex])) return null;
|
|
1352
|
+
if (isMissingValue((series.data || [])[dataIndex])) return null;
|
|
1293
1353
|
const color = series.color || theme.colors[0];
|
|
1294
1354
|
return {
|
|
1295
1355
|
index: dataIndex,
|
|
1296
1356
|
params: {
|
|
1297
1357
|
seriesName: series.name,
|
|
1298
1358
|
name: labels[dataIndex],
|
|
1299
|
-
value: series.data[dataIndex],
|
|
1359
|
+
value: (series.data || [])[dataIndex],
|
|
1300
1360
|
volume,
|
|
1301
1361
|
color,
|
|
1302
1362
|
dataIndex: dataIndex + sliceStartOffset(),
|
|
@@ -1598,7 +1658,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1598
1658
|
tooltipVisible.value = true;
|
|
1599
1659
|
redraw();
|
|
1600
1660
|
}
|
|
1601
|
-
function handlePointerMove(e) {
|
|
1661
|
+
function handlePointerMove(e, fromKeyboard = false) {
|
|
1602
1662
|
const canvas = canvasRef.value;
|
|
1603
1663
|
if (canvas) {
|
|
1604
1664
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -1664,9 +1724,9 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1664
1724
|
hoverAnimProgress = 1;
|
|
1665
1725
|
scheduleHoverRedraw();
|
|
1666
1726
|
} else scheduleHoverRedraw();
|
|
1667
|
-
if (prevIndex === -1) {
|
|
1727
|
+
if (prevIndex === -1 || fromKeyboard) {
|
|
1668
1728
|
const emitParams = Array.isArray(result.params) ? result.params[0] : result.params;
|
|
1669
|
-
emit("hover", {
|
|
1729
|
+
if (prevIndex === -1) emit("hover", {
|
|
1670
1730
|
seriesName: emitParams.seriesName,
|
|
1671
1731
|
dataIndex: emitParams.dataIndex,
|
|
1672
1732
|
value: emitParams.value,
|
|
@@ -1824,7 +1884,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1824
1884
|
function handleChartKeydown(e) {
|
|
1825
1885
|
const options = props.options;
|
|
1826
1886
|
if (!KEYNAV_TYPES.has(options.type)) return;
|
|
1827
|
-
const count = (
|
|
1887
|
+
const count = (effectiveOptions.value.labels || []).length;
|
|
1828
1888
|
if (count === 0) return;
|
|
1829
1889
|
if (e.key === "Enter" || e.key === " ") {
|
|
1830
1890
|
e.preventDefault();
|
|
@@ -1863,7 +1923,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1863
1923
|
clientX,
|
|
1864
1924
|
clientY,
|
|
1865
1925
|
pointerType: "mouse"
|
|
1866
|
-
});
|
|
1926
|
+
}, true);
|
|
1867
1927
|
}
|
|
1868
1928
|
function handleFocusOut() {
|
|
1869
1929
|
if (clearTransientState()) {
|
|
@@ -1927,10 +1987,18 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1927
1987
|
if (Array.isArray(value)) return value.map(cloneSpec);
|
|
1928
1988
|
const out = {};
|
|
1929
1989
|
Object.keys(value).forEach((k) => {
|
|
1990
|
+
if (k === "__proto__") return;
|
|
1930
1991
|
out[k] = cloneSpec(value[k]);
|
|
1931
1992
|
});
|
|
1932
1993
|
return out;
|
|
1933
1994
|
}
|
|
1995
|
+
function assignSpec(target, source) {
|
|
1996
|
+
Object.keys(source).forEach((k) => {
|
|
1997
|
+
if (k === "__proto__") return;
|
|
1998
|
+
target[k] = source[k];
|
|
1999
|
+
});
|
|
2000
|
+
return target;
|
|
2001
|
+
}
|
|
1934
2002
|
const IS_DEV = typeof import.meta !== "undefined" && false;
|
|
1935
2003
|
const devWarned = /* @__PURE__ */ new Set();
|
|
1936
2004
|
function runDevValidation() {
|
|
@@ -1945,13 +2013,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1945
2013
|
}
|
|
1946
2014
|
let prevOptionsSnapshot = null;
|
|
1947
2015
|
watch(() => props.options, (next) => {
|
|
1948
|
-
|
|
1949
|
-
cachedPlotArea = null;
|
|
1950
|
-
cachedPadding = null;
|
|
1951
|
-
scatterHitCache = null;
|
|
1952
|
-
legendBoundsCache = null;
|
|
1953
|
-
ganttLayoutCache = null;
|
|
1954
|
-
sankeyLayoutCache = null;
|
|
2016
|
+
invalidateHitCaches();
|
|
1955
2017
|
internalError.value = null;
|
|
1956
2018
|
runDevValidation();
|
|
1957
2019
|
if (focusSeries.value !== emphasisSeriesName.value) {
|
|
@@ -2127,16 +2189,20 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2127
2189
|
};
|
|
2128
2190
|
return layout;
|
|
2129
2191
|
}
|
|
2192
|
+
function invalidateHitCaches() {
|
|
2193
|
+
cachedDataExtent = null;
|
|
2194
|
+
cachedPlotArea = null;
|
|
2195
|
+
cachedPadding = null;
|
|
2196
|
+
scatterHitCache = null;
|
|
2197
|
+
legendBoundsCache = null;
|
|
2198
|
+
ganttLayoutCache = null;
|
|
2199
|
+
sankeyLayoutCache = null;
|
|
2200
|
+
}
|
|
2130
2201
|
__expose({
|
|
2131
2202
|
refresh: () => render(true),
|
|
2132
2203
|
update(newOptions) {
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
cachedPadding = null;
|
|
2136
|
-
scatterHitCache = null;
|
|
2137
|
-
legendBoundsCache = null;
|
|
2138
|
-
ganttLayoutCache = null;
|
|
2139
|
-
sankeyLayoutCache = null;
|
|
2204
|
+
assignSpec(props.options, newOptions);
|
|
2205
|
+
invalidateHitCaches();
|
|
2140
2206
|
specVersion.value++;
|
|
2141
2207
|
debouncedRender(true);
|
|
2142
2208
|
},
|
|
@@ -2206,7 +2272,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2206
2272
|
if (v < min) min = v;
|
|
2207
2273
|
if (v > max) max = v;
|
|
2208
2274
|
};
|
|
2209
|
-
if (opt.series) opt.series.forEach((s) => s.data.forEach((v) => !isMissingValue(v) && consider(v)));
|
|
2275
|
+
if (opt.series) opt.series.forEach((s) => (s.data || []).forEach((v) => !isMissingValue(v) && consider(v)));
|
|
2210
2276
|
if (opt.scatterData) opt.scatterData.forEach((p) => consider(p.y));
|
|
2211
2277
|
if (opt.candleData) opt.candleData.forEach((c) => {
|
|
2212
2278
|
consider(c.high);
|
|
@@ -2279,6 +2345,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2279
2345
|
mouseX: -1,
|
|
2280
2346
|
mouseY: -1,
|
|
2281
2347
|
showCrosshair: false,
|
|
2348
|
+
zoomRange: void 0,
|
|
2282
2349
|
brushRect: null,
|
|
2283
2350
|
hoveredToolbox: null,
|
|
2284
2351
|
focusSeries: null
|
|
@@ -2299,7 +2366,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2299
2366
|
if (spec === null || typeof spec !== "object") return;
|
|
2300
2367
|
const next = cloneSpec(spec);
|
|
2301
2368
|
Object.keys(props.options).forEach((k) => delete props.options[k]);
|
|
2302
|
-
|
|
2369
|
+
assignSpec(props.options, next);
|
|
2303
2370
|
hiddenSeries.value = /* @__PURE__ */ new Set();
|
|
2304
2371
|
focusSeries.value = null;
|
|
2305
2372
|
brushRect.value = null;
|
|
@@ -2321,8 +2388,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2321
2388
|
p: zoom.position,
|
|
2322
2389
|
h: zoom.height
|
|
2323
2390
|
}) : "";
|
|
2324
|
-
|
|
2325
|
-
cachedPlotArea = null;
|
|
2391
|
+
invalidateHitCaches();
|
|
2326
2392
|
specVersion.value++;
|
|
2327
2393
|
debouncedRender(true);
|
|
2328
2394
|
},
|
|
@@ -2452,7 +2518,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2452
2518
|
], 44, _hoisted_1);
|
|
2453
2519
|
};
|
|
2454
2520
|
}
|
|
2455
|
-
}), [["__scopeId", "data-v-
|
|
2521
|
+
}), [["__scopeId", "data-v-af1c6d5e"]]);
|
|
2456
2522
|
//#endregion
|
|
2457
2523
|
//#region src/useChart.js
|
|
2458
2524
|
var USE_CHART_KEY = /* @__PURE__ */ Symbol("ev-chart-context");
|
|
@@ -2516,95 +2582,6 @@ function injectChartContext() {
|
|
|
2516
2582
|
return inject(USE_CHART_KEY, null);
|
|
2517
2583
|
}
|
|
2518
2584
|
//#endregion
|
|
2519
|
-
//#region src/palette.js
|
|
2520
|
-
/**
|
|
2521
|
-
* 配色方案应用工具 — 中性契约的官方实现
|
|
2522
|
-
*
|
|
2523
|
-
* 把一套数据色板写入 --ev-color-series-1..8 槽位令牌并派发 'ev-theme-change',
|
|
2524
|
-
* 页面上的全部图表即时重绘。任何宿主(组件库 / 站点 / 独立页面)都可直接调用,
|
|
2525
|
-
* 不必各自实现令牌写入与事件广播。
|
|
2526
|
-
*
|
|
2527
|
-
* palette 两种形态:
|
|
2528
|
-
* - string[] 单套色值,明暗模式共用;
|
|
2529
|
-
* - { light, dark } 浅/暗两组,随 html.dark 自动换挡(经注入样式表实现)。
|
|
2530
|
-
*
|
|
2531
|
-
* clearSeriesPalette() 移除覆写(内联属性 + 注入样式表),回到内置成套色板。
|
|
2532
|
-
*/
|
|
2533
|
-
var SLOT_COUNT = 8;
|
|
2534
|
-
var PALETTE_EVENT = "ev-theme-change";
|
|
2535
|
-
var STYLE_ID = "data-ev-series-palette";
|
|
2536
|
-
var paletteStyleEl = null;
|
|
2537
|
-
function dispatchPaletteChange(dark) {
|
|
2538
|
-
if (typeof document === "undefined") return;
|
|
2539
|
-
const isDark = typeof dark === "boolean" ? dark : document.documentElement.classList.contains("dark");
|
|
2540
|
-
document.documentElement.dispatchEvent(new CustomEvent(PALETTE_EVENT, {
|
|
2541
|
-
bubbles: true,
|
|
2542
|
-
detail: { dark: isDark }
|
|
2543
|
-
}));
|
|
2544
|
-
}
|
|
2545
|
-
function removeInlineSlots() {
|
|
2546
|
-
if (typeof document === "undefined") return;
|
|
2547
|
-
for (let i = 1; i <= SLOT_COUNT; i++) document.documentElement.style.removeProperty(`--ev-color-series-${i}`);
|
|
2548
|
-
}
|
|
2549
|
-
function ensurePaletteStyleEl() {
|
|
2550
|
-
if (typeof document === "undefined") return null;
|
|
2551
|
-
if (!paletteStyleEl || !paletteStyleEl.isConnected) {
|
|
2552
|
-
paletteStyleEl = document.createElement("style");
|
|
2553
|
-
paletteStyleEl.setAttribute(STYLE_ID, "");
|
|
2554
|
-
document.head.appendChild(paletteStyleEl);
|
|
2555
|
-
}
|
|
2556
|
-
return paletteStyleEl;
|
|
2557
|
-
}
|
|
2558
|
-
function normalizeSlots(colors) {
|
|
2559
|
-
const out = {};
|
|
2560
|
-
if (!Array.isArray(colors)) return out;
|
|
2561
|
-
colors.slice(0, SLOT_COUNT).forEach((color, i) => {
|
|
2562
|
-
if (color) out[`--ev-color-series-${i + 1}`] = color;
|
|
2563
|
-
});
|
|
2564
|
-
return out;
|
|
2565
|
-
}
|
|
2566
|
-
/**
|
|
2567
|
-
* 应用一套数据色板
|
|
2568
|
-
* @param {string[] | { light: string[], dark: string[] }} palette
|
|
2569
|
-
* 数组:写入内联槽位(明暗共用);{ light, dark }:注入样式表,随 html.dark 自动换挡
|
|
2570
|
-
* @param {{ dark?: boolean, target?: HTMLElement }} [options]
|
|
2571
|
-
* dark 手动指定当前暗色态(默认探测 html.dark);target 改写注入目标
|
|
2572
|
-
* @returns {boolean} 是否写入成功
|
|
2573
|
-
*/
|
|
2574
|
-
function applySeriesPalette(palette, options = {}) {
|
|
2575
|
-
if (typeof document === "undefined") return false;
|
|
2576
|
-
const el = options.target ?? document.documentElement;
|
|
2577
|
-
if (!el || !palette) return false;
|
|
2578
|
-
if (Array.isArray(palette)) {
|
|
2579
|
-
paletteStyleEl?.remove();
|
|
2580
|
-
paletteStyleEl = null;
|
|
2581
|
-
for (const [name, value] of Object.entries(normalizeSlots(palette))) el.style.setProperty(name, value);
|
|
2582
|
-
dispatchPaletteChange(options.dark);
|
|
2583
|
-
return true;
|
|
2584
|
-
}
|
|
2585
|
-
const { light, dark } = palette;
|
|
2586
|
-
if (!Array.isArray(light) && !Array.isArray(dark)) return false;
|
|
2587
|
-
removeInlineSlots();
|
|
2588
|
-
const styleEl = ensurePaletteStyleEl();
|
|
2589
|
-
if (styleEl) {
|
|
2590
|
-
const vars = (colors) => colors.map((c, i) => `--ev-color-series-${i + 1}: ${c}`).join(";");
|
|
2591
|
-
styleEl.textContent = `${light ? `:root { ${vars(light)}; }` : ""}${dark ? ` html.dark { ${vars(dark)}; }` : ""}`;
|
|
2592
|
-
}
|
|
2593
|
-
dispatchPaletteChange(options.dark);
|
|
2594
|
-
return true;
|
|
2595
|
-
}
|
|
2596
|
-
/**
|
|
2597
|
-
* 清除配色方案覆写(内联槽位 + 注入样式表),回到内置成套色板
|
|
2598
|
-
*/
|
|
2599
|
-
function clearSeriesPalette(options = {}) {
|
|
2600
|
-
if (typeof document === "undefined") return false;
|
|
2601
|
-
paletteStyleEl?.remove();
|
|
2602
|
-
paletteStyleEl = null;
|
|
2603
|
-
removeInlineSlots();
|
|
2604
|
-
dispatchPaletteChange(options.dark);
|
|
2605
|
-
return true;
|
|
2606
|
-
}
|
|
2607
|
-
//#endregion
|
|
2608
2585
|
//#region src/index.js
|
|
2609
2586
|
var components = { EvChart: chart_default };
|
|
2610
2587
|
function install(app, _options = {}) {
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { y as CHART_PALETTES } from "./schema-CM4hKlpc.js";
|
|
2
|
+
//#region src/motion.js
|
|
3
|
+
/**
|
|
4
|
+
* 系统级「减弱动态效果」是否开启
|
|
5
|
+
* 命中时调用方应跳过进场 / 补间 / 惯性,直接出终态图;
|
|
6
|
+
* SSR 或无 matchMedia 的老环境按「不减弱」处理,绝不抛错。
|
|
7
|
+
*/
|
|
8
|
+
function prefersReducedMotion() {
|
|
9
|
+
try {
|
|
10
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
11
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
12
|
+
} catch {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 分段错峰:把全局 progress 映射为第 index 个条目的局部 progress
|
|
18
|
+
*
|
|
19
|
+
* count 个条目里,第 index 个从 stagger * index/(count-1) 处起步,所有条目都在
|
|
20
|
+
* progress = 1 时收齐;stagger = 0(或 count = 1)即全部同步,返回原 progress。
|
|
21
|
+
* 局部进度自带 1/(1-stagger) 的压缩,条目越多、错峰越均匀。
|
|
22
|
+
*/
|
|
23
|
+
function staggerProgress(progress, index, count, stagger) {
|
|
24
|
+
const p = Number.isFinite(progress) ? progress : 1;
|
|
25
|
+
const s = Number.isFinite(stagger) ? Math.max(0, Math.min(1, stagger)) : 0;
|
|
26
|
+
if (!(s > 0) || !(count > 1)) return p;
|
|
27
|
+
const start = s * ((Number.isFinite(index) ? Math.max(0, Math.min(count - 1, index)) : 0) / (count - 1));
|
|
28
|
+
return Math.max(0, Math.min(1, (p - start) / (1 - s)));
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region \0plugin-vue:export-helper
|
|
32
|
+
var _plugin_vue_export_helper_default = (sfc, props) => {
|
|
33
|
+
const target = sfc.__vccOpts || sfc;
|
|
34
|
+
for (const [key, val] of props) target[key] = val;
|
|
35
|
+
return target;
|
|
36
|
+
};
|
|
37
|
+
var PALETTE_EVENT = "ev-theme-change";
|
|
38
|
+
var STYLE_ID = "data-ev-series-palette";
|
|
39
|
+
var paletteStyleEl = null;
|
|
40
|
+
function dispatchPaletteChange(dark) {
|
|
41
|
+
if (typeof document === "undefined") return;
|
|
42
|
+
const isDark = typeof dark === "boolean" ? dark : document.documentElement.classList.contains("dark");
|
|
43
|
+
document.documentElement.dispatchEvent(new CustomEvent(PALETTE_EVENT, {
|
|
44
|
+
bubbles: true,
|
|
45
|
+
detail: { dark: isDark }
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
function removeInlineSlots() {
|
|
49
|
+
if (typeof document === "undefined") return;
|
|
50
|
+
for (let i = 1; i <= 8; i++) document.documentElement.style.removeProperty(`--ev-color-series-${i}`);
|
|
51
|
+
}
|
|
52
|
+
function ensurePaletteStyleEl() {
|
|
53
|
+
if (typeof document === "undefined") return null;
|
|
54
|
+
if (!paletteStyleEl || !paletteStyleEl.isConnected) {
|
|
55
|
+
paletteStyleEl = document.createElement("style");
|
|
56
|
+
paletteStyleEl.setAttribute(STYLE_ID, "");
|
|
57
|
+
document.head.appendChild(paletteStyleEl);
|
|
58
|
+
}
|
|
59
|
+
return paletteStyleEl;
|
|
60
|
+
}
|
|
61
|
+
function normalizeSlots(colors) {
|
|
62
|
+
const out = {};
|
|
63
|
+
if (!Array.isArray(colors)) return out;
|
|
64
|
+
colors.slice(0, 8).forEach((color, i) => {
|
|
65
|
+
if (color) out[`--ev-color-series-${i + 1}`] = color;
|
|
66
|
+
});
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 应用一套数据色板
|
|
71
|
+
* @param {string | string[] | { light: string[], dark: string[] }} palette
|
|
72
|
+
* 色系 id:按内置注册表取色;数组:写入内联槽位(明暗共用);
|
|
73
|
+
* { light, dark }:注入样式表,随 html.dark 自动换挡
|
|
74
|
+
* @param {{ dark?: boolean, target?: HTMLElement }} [options]
|
|
75
|
+
* dark 手动指定当前暗色态(默认探测 html.dark);target 改写注入目标
|
|
76
|
+
* @returns {boolean} 是否写入成功
|
|
77
|
+
*/
|
|
78
|
+
function applySeriesPalette(palette, options = {}) {
|
|
79
|
+
if (typeof document === "undefined") return false;
|
|
80
|
+
const el = options.target ?? document.documentElement;
|
|
81
|
+
if (!el || !palette) return false;
|
|
82
|
+
if (typeof palette === "string") {
|
|
83
|
+
const found = CHART_PALETTES.find((p) => p.id === palette);
|
|
84
|
+
if (!found) return false;
|
|
85
|
+
return applySeriesPalette((typeof options.dark === "boolean" ? options.dark : document.documentElement.classList.contains("dark")) ? found.dark : found.light, options);
|
|
86
|
+
}
|
|
87
|
+
if (Array.isArray(palette)) {
|
|
88
|
+
paletteStyleEl?.remove();
|
|
89
|
+
paletteStyleEl = null;
|
|
90
|
+
for (const [name, value] of Object.entries(normalizeSlots(palette))) el.style.setProperty(name, value);
|
|
91
|
+
dispatchPaletteChange(options.dark);
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
const { light, dark } = palette;
|
|
95
|
+
if (!Array.isArray(light) && !Array.isArray(dark)) return false;
|
|
96
|
+
removeInlineSlots();
|
|
97
|
+
const styleEl = ensurePaletteStyleEl();
|
|
98
|
+
if (styleEl) {
|
|
99
|
+
const vars = (colors) => colors.map((c, i) => `--ev-color-series-${i + 1}: ${c}`).join(";");
|
|
100
|
+
styleEl.textContent = `${light ? `:root { ${vars(light)}; }` : ""}${dark ? ` html.dark { ${vars(dark)}; }` : ""}`;
|
|
101
|
+
}
|
|
102
|
+
dispatchPaletteChange(options.dark);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 清除配色方案覆写(内联槽位 + 注入样式表),回到内置成套色板
|
|
107
|
+
*/
|
|
108
|
+
function clearSeriesPalette(options = {}) {
|
|
109
|
+
if (typeof document === "undefined") return false;
|
|
110
|
+
paletteStyleEl?.remove();
|
|
111
|
+
paletteStyleEl = null;
|
|
112
|
+
removeInlineSlots();
|
|
113
|
+
dispatchPaletteChange(options.dark);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { staggerProgress as a, prefersReducedMotion as i, clearSeriesPalette as n, _plugin_vue_export_helper_default as r, applySeriesPalette as t };
|