@wil-works/evoke-charts 0.4.0 → 0.5.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/dist/{ai-BdpMydhW.js → ai-BmXDig6M.js} +4024 -1606
- package/dist/ai.mjs +1 -1
- package/dist/evoke-charts.css +31 -31
- package/dist/index.mjs +201 -56
- package/package.json +1 -1
package/dist/ai.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as SPEC_RULES, c as inferColumns, d as parseNumeric, f as chartOptionsSchema, i as formatExamples, l as looksLikeTime, n as buildChartPrompt, o as detectIntent, p as validateOptions, r as SPEC_EXAMPLES, s as generateChartSpec, t as lintChartSpec, u as parseDataTable } from "./ai-
|
|
1
|
+
import { a as SPEC_RULES, c as inferColumns, d as parseNumeric, f as chartOptionsSchema, i as formatExamples, l as looksLikeTime, n as buildChartPrompt, o as detectIntent, p as validateOptions, r as SPEC_EXAMPLES, s as generateChartSpec, t as lintChartSpec, u as parseDataTable } from "./ai-BmXDig6M.js";
|
|
2
2
|
export { SPEC_EXAMPLES, SPEC_RULES, buildChartPrompt, chartOptionsSchema, detectIntent, formatExamples, generateChartSpec, inferColumns, lintChartSpec, looksLikeTime, parseDataTable, parseNumeric, validateOptions };
|
package/dist/evoke-charts.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
.ev-chart[data-v-
|
|
2
|
+
.ev-chart[data-v-df8a90cc] {
|
|
3
3
|
position: relative;
|
|
4
4
|
/* 容器不带边框:是否加框、加多粗由宿主决定,图表只负责内容;
|
|
5
5
|
圆角裁剪下沉到 canvas 与浮层自身(border-radius: inherit) */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
/* 关键:canvas 必须能接收鼠标事件 */
|
|
12
|
-
.ev-chart__canvas[data-v-
|
|
12
|
+
.ev-chart__canvas[data-v-df8a90cc] {
|
|
13
13
|
position: absolute;
|
|
14
14
|
top: 0;
|
|
15
15
|
left: 0;
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
|
|
24
24
|
/* HTML 覆盖层:只在内容层,不与 canvas 抢交互(子元素可自行 pointer-events:auto),
|
|
25
25
|
也不压过 tooltip(z-index 100) */
|
|
26
|
-
.ev-chart__overlay[data-v-
|
|
26
|
+
.ev-chart__overlay[data-v-df8a90cc] {
|
|
27
27
|
position: absolute;
|
|
28
28
|
inset: 0;
|
|
29
29
|
z-index: 1;
|
|
30
30
|
pointer-events: none;
|
|
31
31
|
border-radius: inherit;
|
|
32
32
|
}
|
|
33
|
-
.ev-chart__tooltip[data-v-
|
|
33
|
+
.ev-chart__tooltip[data-v-df8a90cc] {
|
|
34
34
|
position: absolute;
|
|
35
35
|
pointer-events: none;
|
|
36
36
|
z-index: 100;
|
|
@@ -50,47 +50,47 @@
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/* tooltip 淡入淡出(仅 opacity,位置由 left/top transition 负责) */
|
|
53
|
-
.ev-chart-tooltip-enter-active[data-v-
|
|
54
|
-
.ev-chart-tooltip-leave-active[data-v-
|
|
53
|
+
.ev-chart-tooltip-enter-active[data-v-df8a90cc],
|
|
54
|
+
.ev-chart-tooltip-leave-active[data-v-df8a90cc] {
|
|
55
55
|
transition: var(--ev-tooltip-fade-transition);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
/* 进入期间禁用位置 transition,避免首次出现时从旧位置滑入 */
|
|
59
|
-
.ev-chart-tooltip-enter-active[data-v-
|
|
59
|
+
.ev-chart-tooltip-enter-active[data-v-df8a90cc] {
|
|
60
60
|
transition:
|
|
61
61
|
var(--ev-tooltip-fade-transition),
|
|
62
62
|
left 0s,
|
|
63
63
|
top 0s;
|
|
64
64
|
}
|
|
65
|
-
.ev-chart-tooltip-enter-from[data-v-
|
|
66
|
-
.ev-chart-tooltip-leave-to[data-v-
|
|
65
|
+
.ev-chart-tooltip-enter-from[data-v-df8a90cc],
|
|
66
|
+
.ev-chart-tooltip-leave-to[data-v-df8a90cc] {
|
|
67
67
|
opacity: 0;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/* v-html 注入的内容不带 scoped 属性,需用 :deep() 穿透 */
|
|
71
|
-
[data-v-
|
|
71
|
+
[data-v-df8a90cc] .ev-chart__tooltip-title {
|
|
72
72
|
color: var(--ev-text-color-secondary, #6b7280);
|
|
73
73
|
font-size: 12px;
|
|
74
74
|
margin-bottom: 6px;
|
|
75
75
|
font-weight: 500;
|
|
76
76
|
}
|
|
77
|
-
[data-v-
|
|
77
|
+
[data-v-df8a90cc] .ev-chart__tooltip-item {
|
|
78
78
|
display: flex;
|
|
79
79
|
align-items: center;
|
|
80
80
|
gap: 8px;
|
|
81
81
|
padding: 2px 0;
|
|
82
82
|
}
|
|
83
|
-
[data-v-
|
|
83
|
+
[data-v-df8a90cc] .ev-chart__tooltip-dot {
|
|
84
84
|
width: 8px;
|
|
85
85
|
height: 8px;
|
|
86
86
|
border-radius: 50%;
|
|
87
87
|
flex-shrink: 0;
|
|
88
88
|
display: inline-block;
|
|
89
89
|
}
|
|
90
|
-
[data-v-
|
|
90
|
+
[data-v-df8a90cc] .ev-chart__tooltip-name {
|
|
91
91
|
color: var(--ev-text-color-primary, #111827);
|
|
92
92
|
}
|
|
93
|
-
[data-v-
|
|
93
|
+
[data-v-df8a90cc] .ev-chart__tooltip-value {
|
|
94
94
|
color: var(--ev-text-color-primary, #111827);
|
|
95
95
|
font-weight: 600;
|
|
96
96
|
margin-left: auto;
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/* ══════ 空数据占位 ══════ */
|
|
102
|
-
.ev-chart__empty[data-v-
|
|
102
|
+
.ev-chart__empty[data-v-df8a90cc] {
|
|
103
103
|
position: absolute;
|
|
104
104
|
inset: 0;
|
|
105
105
|
border-radius: inherit;
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
gap: 14px;
|
|
113
113
|
user-select: none;
|
|
114
114
|
}
|
|
115
|
-
.ev-chart__empty-icon-wrap[data-v-
|
|
115
|
+
.ev-chart__empty-icon-wrap[data-v-df8a90cc] {
|
|
116
116
|
display: flex;
|
|
117
117
|
align-items: center;
|
|
118
118
|
justify-content: center;
|
|
@@ -121,19 +121,19 @@
|
|
|
121
121
|
border-radius: 16px;
|
|
122
122
|
background: var(--ev-fill-color-light, #f5f7fa);
|
|
123
123
|
}
|
|
124
|
-
.ev-chart__empty-img[data-v-
|
|
124
|
+
.ev-chart__empty-img[data-v-df8a90cc] {
|
|
125
125
|
width: 32px;
|
|
126
126
|
height: 32px;
|
|
127
127
|
opacity: 0.4;
|
|
128
128
|
}
|
|
129
|
-
.ev-chart__empty-text[data-v-
|
|
129
|
+
.ev-chart__empty-text[data-v-df8a90cc] {
|
|
130
130
|
letter-spacing: 0.04em;
|
|
131
131
|
font-weight: 500;
|
|
132
132
|
font-size: 13px;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/* ══════ 加载中骨架 ══════ */
|
|
136
|
-
.ev-chart__loading[data-v-
|
|
136
|
+
.ev-chart__loading[data-v-df8a90cc] {
|
|
137
137
|
position: absolute;
|
|
138
138
|
inset: 0;
|
|
139
139
|
border-radius: inherit;
|
|
@@ -142,20 +142,20 @@
|
|
|
142
142
|
justify-content: center;
|
|
143
143
|
background: var(--ev-bg-color, #ffffff);
|
|
144
144
|
}
|
|
145
|
-
.ev-chart__loading-bars[data-v-
|
|
145
|
+
.ev-chart__loading-bars[data-v-df8a90cc] {
|
|
146
146
|
display: flex;
|
|
147
147
|
align-items: flex-end;
|
|
148
148
|
gap: 6px;
|
|
149
149
|
height: 60px;
|
|
150
150
|
}
|
|
151
|
-
.ev-chart__loading-bar[data-v-
|
|
151
|
+
.ev-chart__loading-bar[data-v-df8a90cc] {
|
|
152
152
|
width: 10px;
|
|
153
153
|
height: 40px;
|
|
154
154
|
border-radius: 4px;
|
|
155
155
|
background: var(--ev-border-color, #e2e8f0);
|
|
156
|
-
animation: ev-chart-shimmer-
|
|
156
|
+
animation: ev-chart-shimmer-df8a90cc 1.2s ease-in-out infinite;
|
|
157
157
|
}
|
|
158
|
-
@keyframes ev-chart-shimmer-
|
|
158
|
+
@keyframes ev-chart-shimmer-df8a90cc {
|
|
159
159
|
0%,
|
|
160
160
|
100% {
|
|
161
161
|
transform: scaleY(0.4);
|
|
@@ -168,7 +168,7 @@
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
/* ══════ 错误边界 ══════ */
|
|
171
|
-
.ev-chart__error[data-v-
|
|
171
|
+
.ev-chart__error[data-v-df8a90cc] {
|
|
172
172
|
position: absolute;
|
|
173
173
|
inset: 0;
|
|
174
174
|
border-radius: inherit;
|
|
@@ -182,13 +182,13 @@
|
|
|
182
182
|
padding: 20px;
|
|
183
183
|
text-align: center;
|
|
184
184
|
}
|
|
185
|
-
.ev-chart__error-icon[data-v-
|
|
185
|
+
.ev-chart__error-icon[data-v-df8a90cc] {
|
|
186
186
|
display: flex;
|
|
187
187
|
align-items: center;
|
|
188
188
|
justify-content: center;
|
|
189
189
|
font-size: 30px;
|
|
190
190
|
}
|
|
191
|
-
.ev-chart__error-text[data-v-
|
|
191
|
+
.ev-chart__error-text[data-v-df8a90cc] {
|
|
192
192
|
font-size: 12px;
|
|
193
193
|
line-height: 1.5;
|
|
194
194
|
max-width: 80%;
|
|
@@ -196,17 +196,17 @@
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/* ══════ 进入/离开淡入淡出 ══════ */
|
|
199
|
-
.ev-chart-fade-enter-active[data-v-
|
|
200
|
-
.ev-chart-fade-leave-active[data-v-
|
|
199
|
+
.ev-chart-fade-enter-active[data-v-df8a90cc],
|
|
200
|
+
.ev-chart-fade-leave-active[data-v-df8a90cc] {
|
|
201
201
|
transition: opacity 0.2s ease;
|
|
202
202
|
}
|
|
203
|
-
.ev-chart-fade-enter-from[data-v-
|
|
204
|
-
.ev-chart-fade-leave-to[data-v-
|
|
203
|
+
.ev-chart-fade-enter-from[data-v-df8a90cc],
|
|
204
|
+
.ev-chart-fade-leave-to[data-v-df8a90cc] {
|
|
205
205
|
opacity: 0;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
/* ══════ 无障碍:sr-only ══════ */
|
|
209
|
-
.ev-chart__sr-only[data-v-
|
|
209
|
+
.ev-chart__sr-only[data-v-df8a90cc] {
|
|
210
210
|
position: absolute;
|
|
211
211
|
width: 1px;
|
|
212
212
|
height: 1px;
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { $ as INTERACTION, A as squarifyTreemap, B as calendarHitTest, C as chordHitTest, D as computeSunburstGeometry, E as boxplotHitTest, F as matrixFieldExtent, G as getPadding, H as getHeatmapCategories, I as scatterGroupColors, J as resolveTickExtendedRange, K as getTheme, L as scatterPointPositions, M as computeFacetGrids, N as computeMatrixCells, O as sunburstValue, P as computePieMaxRadius, Q as DEFAULT_I18N_ZH, R as getLegendBounds, S as arcHitTest, T as vennHitTest, U as xToCategoryIndex, V as funnelStepColor, W as createAnimation, X as CHART_PALETTES, Y as updateAnimation, Z as resolveChartPalette, _ as getSliderGeometry, b as zoomToSlice, et as applyWheelZoom, f as chartOptionsSchema, g as getDataZoomConfig, h as createSvgRecorder, j as buildPieSlices, k as computeBins, m as renderChart, n as buildChartPrompt, nt as resolveCursor, p as validateOptions, q as isMissingValue, s as generateChartSpec, t as lintChartSpec, tt as pickTooltipRows, u as parseDataTable, v as windowToX, w as sankeyHitTest, x as ganttHitTest, y as xToPercent, z as getToolboxBounds } from "./ai-BmXDig6M.js";
|
|
2
2
|
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
3
|
//#region src/connect.js
|
|
4
4
|
var connectGroups = /* @__PURE__ */ new Map();
|
|
@@ -126,6 +126,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
126
126
|
case "funnel": return !opt.funnelData || opt.funnelData.length === 0;
|
|
127
127
|
case "gauge": return !opt.gauge;
|
|
128
128
|
case "heatmap": return !opt.heatmapData || opt.heatmapData.length === 0;
|
|
129
|
+
case "calendar-heatmap": return !opt.calendarData || opt.calendarData.length === 0;
|
|
129
130
|
case "candle": return !opt.candleData || opt.candleData.length === 0;
|
|
130
131
|
case "bullet": return !opt.bulletData || opt.bulletData.length === 0;
|
|
131
132
|
case "treemap": return !opt.treemapData || opt.treemapData.length === 0;
|
|
@@ -136,6 +137,12 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
136
137
|
case "bin": return !opt.series || opt.series.length === 0 || opt.series.every((s) => !s.data || s.data.length === 0);
|
|
137
138
|
case "sparkline": return !opt.series || opt.series.length === 0 || !opt.series[0]?.data?.length;
|
|
138
139
|
case "radar": return !opt.radarIndicators?.length || !opt.radarSeries?.length;
|
|
140
|
+
case "sankey":
|
|
141
|
+
case "chord":
|
|
142
|
+
case "arc": return !(opt.sankeyData || opt.chordData || opt.arcData)?.nodes?.length;
|
|
143
|
+
case "venn": return !opt.vennData || opt.vennData.length === 0;
|
|
144
|
+
case "gantt": return !opt.ganttData || opt.ganttData.length === 0;
|
|
145
|
+
case "scatter-matrix": return !opt.matrixFields?.length || !opt.matrixData?.length;
|
|
139
146
|
default: return !opt.labels?.length || !opt.series?.length;
|
|
140
147
|
}
|
|
141
148
|
});
|
|
@@ -159,6 +166,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
159
166
|
let hoverIndex = -1;
|
|
160
167
|
let hoverAnimProgress = 0;
|
|
161
168
|
let hoverAnimFrameId = null;
|
|
169
|
+
let hoverAnimDone = null;
|
|
162
170
|
const hiddenSeries = ref(/* @__PURE__ */ new Set());
|
|
163
171
|
const focusSeries = ref(null);
|
|
164
172
|
const emphasisSeriesName = computed(() => {
|
|
@@ -443,12 +451,44 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
443
451
|
mouseY,
|
|
444
452
|
showCrosshair: hoverIndex >= 0,
|
|
445
453
|
hoverAnimProgress,
|
|
454
|
+
focusAnimProgress,
|
|
446
455
|
zoomRange: isZoomEnabled() ? zoomRange.value : void 0,
|
|
447
456
|
brushRect: brushRect.value,
|
|
448
457
|
focusSeries: focusSeries.value,
|
|
449
458
|
hoveredToolbox: hoveredToolbox.value
|
|
450
459
|
};
|
|
451
460
|
}
|
|
461
|
+
let focusAnimProgress = 1;
|
|
462
|
+
let focusAnimFrameId = null;
|
|
463
|
+
function animateFocusProgress() {
|
|
464
|
+
if (focusAnimFrameId !== null) {
|
|
465
|
+
cancelAnimationFrame(focusAnimFrameId);
|
|
466
|
+
focusAnimFrameId = null;
|
|
467
|
+
}
|
|
468
|
+
const target = focusSeries.value ? 1 : 0;
|
|
469
|
+
if (props.options.animation?.enabled === false || target === focusAnimProgress) {
|
|
470
|
+
focusAnimProgress = target;
|
|
471
|
+
redraw();
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
const start = focusAnimProgress;
|
|
475
|
+
const startTime = performance.now();
|
|
476
|
+
const duration = 180;
|
|
477
|
+
function frame(now) {
|
|
478
|
+
const tRaw = Math.min((now - startTime) / duration, 1);
|
|
479
|
+
focusAnimProgress = start + (target - start) * (1 - Math.pow(1 - tRaw, 3));
|
|
480
|
+
redraw();
|
|
481
|
+
if (tRaw < 1) focusAnimFrameId = requestAnimationFrame(frame);
|
|
482
|
+
else focusAnimFrameId = null;
|
|
483
|
+
}
|
|
484
|
+
focusAnimFrameId = requestAnimationFrame(frame);
|
|
485
|
+
}
|
|
486
|
+
function stopFocusAnimation() {
|
|
487
|
+
if (focusAnimFrameId !== null) {
|
|
488
|
+
cancelAnimationFrame(focusAnimFrameId);
|
|
489
|
+
focusAnimFrameId = null;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
452
492
|
function snapshotSeriesData(opt) {
|
|
453
493
|
const map = /* @__PURE__ */ new Map();
|
|
454
494
|
(opt.series || []).forEach((s) => map.set(s.name, s.data.map((v) => isMissingValue(v) ? 0 : v)));
|
|
@@ -564,31 +604,40 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
564
604
|
cancelAnimationFrame(hoverAnimFrameId);
|
|
565
605
|
hoverAnimFrameId = null;
|
|
566
606
|
}
|
|
607
|
+
hoverAnimDone = null;
|
|
567
608
|
}
|
|
568
609
|
function usesHoverAnimation() {
|
|
569
610
|
const t = props.options.type;
|
|
570
|
-
return t === "pie" || t === "doughnut" || t === "rose" || t === "sunburst" || t === "treemap";
|
|
611
|
+
return t === "pie" || t === "doughnut" || t === "rose" || t === "sunburst" || t === "treemap" || t === "radar";
|
|
612
|
+
}
|
|
613
|
+
function animatesHoverEnter() {
|
|
614
|
+
const t = props.options.type;
|
|
615
|
+
return t === "pie" || t === "doughnut" || t === "rose" || t === "radar" || t === "venn" || t === "sankey" || t === "chord" || t === "arc";
|
|
571
616
|
}
|
|
572
617
|
function clearHover() {
|
|
573
618
|
if (hoverIndex === -1) return false;
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
619
|
+
if (animatesHoverEnter()) startHoverAnimation(-1, () => {
|
|
620
|
+
hoverIndex = -1;
|
|
621
|
+
redraw();
|
|
622
|
+
});
|
|
577
623
|
else {
|
|
624
|
+
hoverIndex = -1;
|
|
578
625
|
stopHoverAnimation();
|
|
579
626
|
hoverAnimProgress = 0;
|
|
580
627
|
redraw();
|
|
581
628
|
}
|
|
582
629
|
return true;
|
|
583
630
|
}
|
|
584
|
-
function startHoverAnimation(dir) {
|
|
585
|
-
if (!
|
|
631
|
+
function startHoverAnimation(dir, onDone) {
|
|
632
|
+
if (!animatesHoverEnter()) return;
|
|
586
633
|
if (props.options.animation?.enabled === false) {
|
|
587
634
|
hoverAnimProgress = dir > 0 ? 1 : 0;
|
|
588
635
|
redraw();
|
|
636
|
+
if (onDone) onDone();
|
|
589
637
|
return;
|
|
590
638
|
}
|
|
591
639
|
stopHoverAnimation();
|
|
640
|
+
hoverAnimDone = onDone || null;
|
|
592
641
|
const duration = 220;
|
|
593
642
|
const startTime = performance.now();
|
|
594
643
|
const startProgress = hoverAnimProgress;
|
|
@@ -604,7 +653,12 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
604
653
|
}
|
|
605
654
|
renderChart(canvasRef.value, buildRenderParams(1));
|
|
606
655
|
if (tRaw < 1) hoverAnimFrameId = requestAnimationFrame(frame);
|
|
607
|
-
else
|
|
656
|
+
else {
|
|
657
|
+
hoverAnimFrameId = null;
|
|
658
|
+
const done = hoverAnimDone;
|
|
659
|
+
hoverAnimDone = null;
|
|
660
|
+
if (done) done();
|
|
661
|
+
}
|
|
608
662
|
}
|
|
609
663
|
hoverAnimFrameId = requestAnimationFrame(frame);
|
|
610
664
|
}
|
|
@@ -624,7 +678,12 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
624
678
|
"rose",
|
|
625
679
|
"radar",
|
|
626
680
|
"funnel",
|
|
627
|
-
"scatter"
|
|
681
|
+
"scatter",
|
|
682
|
+
"sankey",
|
|
683
|
+
"chord",
|
|
684
|
+
"arc",
|
|
685
|
+
"venn",
|
|
686
|
+
"candle"
|
|
628
687
|
];
|
|
629
688
|
function checkLegendHit(x, y) {
|
|
630
689
|
const canvas = canvasRef.value;
|
|
@@ -751,7 +810,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
751
810
|
const i = Math.floor(relativeY / stepHeight);
|
|
752
811
|
if (i < 0 || i >= drawData.length) return null;
|
|
753
812
|
const data = drawData[i];
|
|
754
|
-
const color = data.
|
|
813
|
+
const color = funnelStepColor(data, allFunnel.indexOf(data) < 0 ? i : allFunnel.indexOf(data), theme);
|
|
755
814
|
return {
|
|
756
815
|
index: i,
|
|
757
816
|
params: {
|
|
@@ -794,27 +853,61 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
794
853
|
};
|
|
795
854
|
}
|
|
796
855
|
if (options.type === "boxplot") {
|
|
797
|
-
const
|
|
798
|
-
if (
|
|
799
|
-
const
|
|
800
|
-
const
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
856
|
+
const visible = (options.boxData || []).filter((b) => !(b.group && hiddenSeries.value.has(b.group)) && !hiddenSeries.value.has(b.label));
|
|
857
|
+
if (visible.length === 0) return null;
|
|
858
|
+
const showOutliers = options.showOutliers !== false;
|
|
859
|
+
const allValues = visible.flatMap((b) => [
|
|
860
|
+
b.min,
|
|
861
|
+
b.max,
|
|
862
|
+
...showOutliers ? b.outliers || [] : []
|
|
863
|
+
]);
|
|
864
|
+
const axisCfg = options.boxHorizontal ? options.xAxis || {} : options.yAxis || {};
|
|
865
|
+
const ext = resolveTickExtendedRange(axisCfg.min ?? Math.min(...allValues), axisCfg.max ?? Math.max(...allValues), axisCfg.ticks || 5);
|
|
866
|
+
return boxplotHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value, {
|
|
867
|
+
min: ext.min,
|
|
868
|
+
max: ext.max
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
if (options.type === "calendar-heatmap") return calendarHitTest(canvasX, canvasY, plotArea, options, theme);
|
|
872
|
+
if (options.type === "sankey") return sankeyHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value);
|
|
873
|
+
if (options.type === "venn") return vennHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value);
|
|
874
|
+
if (options.type === "chord") return chordHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value);
|
|
875
|
+
if (options.type === "arc") return arcHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value);
|
|
876
|
+
if (options.type === "gantt") return ganttHitTest(canvasX, canvasY, plotArea, options, theme, hiddenSeries.value);
|
|
877
|
+
if (options.type === "scatter-matrix") {
|
|
878
|
+
const fields = options.matrixFields || [];
|
|
879
|
+
const records = options.matrixData || [];
|
|
880
|
+
if (fields.length === 0 || records.length === 0) return null;
|
|
881
|
+
const cells = computeMatrixCells(plotArea, fields);
|
|
882
|
+
const cell = cells.find((c) => canvasX >= c.x && canvasX <= c.x + c.width && canvasY >= c.y && canvasY <= c.y + c.height);
|
|
883
|
+
if (!cell || cell.row === cell.col) return null;
|
|
884
|
+
const extX = matrixFieldExtent(records, cell.xField);
|
|
885
|
+
const extY = matrixFieldExtent(records, cell.yField);
|
|
886
|
+
const px = (v) => cell.x + 5 + (v - extX.min) / (extX.max - extX.min) * (cell.width - 10);
|
|
887
|
+
const py = (v) => cell.y + cell.height - 5 - (v - extY.min) / (extY.max - extY.min) * (cell.height - 10);
|
|
888
|
+
let nearest = -1;
|
|
889
|
+
let minDist = Infinity;
|
|
890
|
+
records.forEach((record, ri) => {
|
|
891
|
+
const xv = record[cell.xField];
|
|
892
|
+
const yv = record[cell.yField];
|
|
893
|
+
if (typeof xv !== "number" || typeof yv !== "number") return;
|
|
894
|
+
const dist = Math.sqrt((canvasX - px(xv)) ** 2 + (canvasY - py(yv)) ** 2);
|
|
895
|
+
if (dist < minDist) {
|
|
896
|
+
minDist = dist;
|
|
897
|
+
nearest = ri;
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
if (nearest < 0 || minDist > 18) return null;
|
|
901
|
+
const record = records[nearest];
|
|
902
|
+
const cellIndex = cells.indexOf(cell);
|
|
804
903
|
return {
|
|
805
|
-
index:
|
|
904
|
+
index: cellIndex,
|
|
806
905
|
params: {
|
|
807
|
-
seriesName:
|
|
808
|
-
name: `${
|
|
809
|
-
value: [
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
b.median,
|
|
813
|
-
b.q3,
|
|
814
|
-
b.max
|
|
815
|
-
],
|
|
816
|
-
color,
|
|
817
|
-
dataIndex: i + sliceStartOffset(),
|
|
906
|
+
seriesName: record.label || `${cell.yField} × ${cell.xField}`,
|
|
907
|
+
name: `${cell.xField}=${record[cell.xField]}, ${cell.yField}=${record[cell.yField]}`,
|
|
908
|
+
value: record[cell.yField],
|
|
909
|
+
color: record.color || theme.colors[0],
|
|
910
|
+
dataIndex: cellIndex,
|
|
818
911
|
seriesIndex: 0
|
|
819
912
|
}
|
|
820
913
|
};
|
|
@@ -886,22 +979,56 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
886
979
|
if (options.type === "scatter") {
|
|
887
980
|
const scatterData = options.scatterData || [];
|
|
888
981
|
if (scatterData.length === 0) return null;
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
982
|
+
if (options.facet === true) {
|
|
983
|
+
const grid = computeFacetGrids(scatterData, plotArea, options);
|
|
984
|
+
if (!grid) return null;
|
|
985
|
+
for (const facet of grid.facets) {
|
|
986
|
+
const a = facet.area;
|
|
987
|
+
if (canvasX < a.x || canvasX > a.x + a.width || canvasY < a.y || canvasY > a.y + a.height) continue;
|
|
988
|
+
let nearestLocal = -1;
|
|
989
|
+
let minDistance = Infinity;
|
|
990
|
+
facet.data.forEach((point, i) => {
|
|
991
|
+
const ppx = facet.toX(point.x);
|
|
992
|
+
const ppy = facet.toY(point.y);
|
|
993
|
+
const dist = Math.sqrt((canvasX - ppx) ** 2 + (canvasY - ppy) ** 2);
|
|
994
|
+
if (dist < minDistance) {
|
|
995
|
+
minDistance = dist;
|
|
996
|
+
nearestLocal = i;
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
if (nearestLocal < 0 || minDistance > 24) return null;
|
|
1000
|
+
const point = facet.data[nearestLocal];
|
|
1001
|
+
const globalIdx = scatterData.indexOf(point);
|
|
1002
|
+
const color = point.color || theme.colors[globalIdx % theme.colors.length];
|
|
1003
|
+
return {
|
|
1004
|
+
index: globalIdx,
|
|
1005
|
+
params: {
|
|
1006
|
+
seriesName: point.group || point.label || `Point ${globalIdx + 1}`,
|
|
1007
|
+
name: `(${point.x}, ${point.y})`,
|
|
1008
|
+
value: point.y,
|
|
1009
|
+
color,
|
|
1010
|
+
dataIndex: globalIdx,
|
|
1011
|
+
seriesIndex: 0
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
return null;
|
|
1016
|
+
}
|
|
893
1017
|
const yValues = scatterData.map((d) => d.y);
|
|
894
1018
|
const axisConfig = options.yAxis || {};
|
|
895
1019
|
const rawMin = axisConfig.min ?? Math.min(...yValues);
|
|
896
1020
|
const rawMax = axisConfig.max ?? Math.max(...yValues);
|
|
897
1021
|
const yExt = resolveTickExtendedRange(rawMin, rawMax, axisConfig.ticks || 5);
|
|
898
|
-
const
|
|
1022
|
+
const positions = scatterPointPositions(scatterData, {
|
|
1023
|
+
min: yExt.min,
|
|
1024
|
+
max: yExt.max
|
|
1025
|
+
}, plotArea, options);
|
|
1026
|
+
const groupColors = scatterGroupColors(scatterData, theme);
|
|
899
1027
|
let nearestIndex = -1;
|
|
900
1028
|
let minDistance = Infinity;
|
|
901
1029
|
scatterData.forEach((point, i) => {
|
|
902
|
-
|
|
903
|
-
const
|
|
904
|
-
const py = plotArea.y + plotArea.height - normalizedY * plotArea.height;
|
|
1030
|
+
if (hiddenSeries.value.has(point.label || `P${i + 1}`) || point.group && hiddenSeries.value.has(point.group)) return;
|
|
1031
|
+
const [px, py] = positions[i];
|
|
905
1032
|
const dist = Math.sqrt((canvasX - px) ** 2 + (canvasY - py) ** 2);
|
|
906
1033
|
if (dist < minDistance) {
|
|
907
1034
|
minDistance = dist;
|
|
@@ -910,11 +1037,11 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
910
1037
|
});
|
|
911
1038
|
if (nearestIndex >= 0 && minDistance < 30) {
|
|
912
1039
|
const point = scatterData[nearestIndex];
|
|
913
|
-
const color = point.color || theme.colors[nearestIndex % theme.colors.length];
|
|
1040
|
+
const color = point.color || (point.group && groupColors.has(point.group) ? groupColors.get(point.group) : theme.colors[nearestIndex % theme.colors.length]);
|
|
914
1041
|
return {
|
|
915
1042
|
index: nearestIndex,
|
|
916
1043
|
params: {
|
|
917
|
-
seriesName: point.label || `Point ${nearestIndex + 1}`,
|
|
1044
|
+
seriesName: point.label || point.group || `Point ${nearestIndex + 1}`,
|
|
918
1045
|
name: `(${point.x}, ${point.y})`,
|
|
919
1046
|
value: point.y,
|
|
920
1047
|
color,
|
|
@@ -944,6 +1071,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
944
1071
|
candle.high,
|
|
945
1072
|
candle.low
|
|
946
1073
|
],
|
|
1074
|
+
volume: (options.volumeData || [])[i],
|
|
947
1075
|
color,
|
|
948
1076
|
dataIndex: i,
|
|
949
1077
|
seriesIndex: 0
|
|
@@ -1062,6 +1190,16 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1062
1190
|
const centerY = plotArea.y + plotArea.height / 2;
|
|
1063
1191
|
const radius = Math.max(40, Math.min(plotArea.width, plotArea.height) / 2 - 30);
|
|
1064
1192
|
const angleStep = Math.PI * 2 / indicators.length;
|
|
1193
|
+
const labelOffset = options.radarLabelOffset ?? 12;
|
|
1194
|
+
let labelHit = -1;
|
|
1195
|
+
indicators.forEach((indicator, i) => {
|
|
1196
|
+
if (labelHit >= 0) return;
|
|
1197
|
+
const angle = i * angleStep - Math.PI / 2;
|
|
1198
|
+
const lx = centerX + Math.cos(angle) * (radius + labelOffset);
|
|
1199
|
+
const ly = centerY + Math.sin(angle) * (radius + labelOffset);
|
|
1200
|
+
if (Math.sqrt((canvasX - lx) ** 2 + (canvasY - ly) ** 2) <= 18) labelHit = i;
|
|
1201
|
+
});
|
|
1202
|
+
if (labelHit >= 0) return radarAxisHover(labelHit, indicators, series, options, theme);
|
|
1065
1203
|
let nearestIndex = -1;
|
|
1066
1204
|
let minDist = Infinity;
|
|
1067
1205
|
indicators.forEach((_, i) => {
|
|
@@ -1078,18 +1216,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1078
1216
|
}
|
|
1079
1217
|
});
|
|
1080
1218
|
if (nearestIndex < 0 || minDist > 30) return null;
|
|
1081
|
-
|
|
1082
|
-
seriesName: s.name,
|
|
1083
|
-
name: indicators[nearestIndex].name,
|
|
1084
|
-
value: s.data[nearestIndex],
|
|
1085
|
-
color: s.color || theme.colors[options.series.indexOf(s) % theme.colors.length],
|
|
1086
|
-
dataIndex: nearestIndex,
|
|
1087
|
-
seriesIndex: sIdx
|
|
1088
|
-
}));
|
|
1089
|
-
return {
|
|
1090
|
-
index: nearestIndex,
|
|
1091
|
-
params
|
|
1092
|
-
};
|
|
1219
|
+
return radarAxisHover(nearestIndex, indicators, series, options, theme);
|
|
1093
1220
|
}
|
|
1094
1221
|
const labels = options.labels || [];
|
|
1095
1222
|
if (labels.length === 0) return null;
|
|
@@ -1097,6 +1224,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1097
1224
|
if (dataIndex < 0 || dataIndex >= labels.length) return null;
|
|
1098
1225
|
const visibleSeries = (options.series || []).filter((s) => !hiddenSeries.value.has(s.name));
|
|
1099
1226
|
if (visibleSeries.length === 0) return null;
|
|
1227
|
+
const volume = (options.volumeData || [])[dataIndex];
|
|
1100
1228
|
if (props.options.tooltip?.showAllSeries !== false && visibleSeries.length > 1) {
|
|
1101
1229
|
if (visibleSeries.every((s) => isMissingValue(s.data[dataIndex]))) return null;
|
|
1102
1230
|
return {
|
|
@@ -1105,6 +1233,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1105
1233
|
seriesName: s.name,
|
|
1106
1234
|
name: labels[dataIndex],
|
|
1107
1235
|
value: s.data[dataIndex],
|
|
1236
|
+
volume,
|
|
1108
1237
|
color: s.color || theme.colors[options.series.indexOf(s) % theme.colors.length],
|
|
1109
1238
|
dataIndex: dataIndex + sliceStartOffset(),
|
|
1110
1239
|
seriesIndex: sIdx
|
|
@@ -1120,6 +1249,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1120
1249
|
seriesName: series.name,
|
|
1121
1250
|
name: labels[dataIndex],
|
|
1122
1251
|
value: series.data[dataIndex],
|
|
1252
|
+
volume,
|
|
1123
1253
|
color,
|
|
1124
1254
|
dataIndex: dataIndex + sliceStartOffset(),
|
|
1125
1255
|
seriesIndex: 0
|
|
@@ -1127,6 +1257,20 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1127
1257
|
};
|
|
1128
1258
|
}
|
|
1129
1259
|
}
|
|
1260
|
+
/** 雷达轴悬浮:返回该维度上全部可见系列的 tooltip 行 */
|
|
1261
|
+
function radarAxisHover(axisIndex, indicators, series, options, theme) {
|
|
1262
|
+
return {
|
|
1263
|
+
index: axisIndex,
|
|
1264
|
+
params: series.map((s, sIdx) => ({
|
|
1265
|
+
seriesName: s.name,
|
|
1266
|
+
name: indicators[axisIndex].name,
|
|
1267
|
+
value: s.data[axisIndex],
|
|
1268
|
+
color: s.color || theme.colors[(options.radarSeries || []).indexOf(s) % theme.colors.length],
|
|
1269
|
+
dataIndex: axisIndex,
|
|
1270
|
+
seriesIndex: sIdx
|
|
1271
|
+
}))
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1130
1274
|
function setZoomRange(next) {
|
|
1131
1275
|
const minSpan = INTERACTION.zoom.minSpan;
|
|
1132
1276
|
let { start, end } = next;
|
|
@@ -1444,7 +1588,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1444
1588
|
const nextFocus = props.options.legend?.hoverEmphasis !== false && legendName ? legendName : null;
|
|
1445
1589
|
if (nextFocus !== focusSeries.value) {
|
|
1446
1590
|
focusSeries.value = nextFocus;
|
|
1447
|
-
|
|
1591
|
+
animateFocusProgress();
|
|
1448
1592
|
}
|
|
1449
1593
|
}
|
|
1450
1594
|
if (legendName) {
|
|
@@ -1454,13 +1598,13 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1454
1598
|
}
|
|
1455
1599
|
if (e.pointerType === "touch") return;
|
|
1456
1600
|
const result = getHoveredData(e.clientX, e.clientY);
|
|
1457
|
-
const
|
|
1601
|
+
const enterAnimated = animatesHoverEnter();
|
|
1458
1602
|
if (result && props.options.tooltip?.show !== false) {
|
|
1459
1603
|
const newIndex = result.index;
|
|
1460
1604
|
if (newIndex !== hoverIndex) {
|
|
1461
1605
|
const prevIndex = hoverIndex;
|
|
1462
1606
|
hoverIndex = newIndex;
|
|
1463
|
-
if (
|
|
1607
|
+
if (enterAnimated) {
|
|
1464
1608
|
if (prevIndex === -1) startHoverAnimation(1);
|
|
1465
1609
|
else {
|
|
1466
1610
|
stopHoverAnimation();
|
|
@@ -1484,7 +1628,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1484
1628
|
});
|
|
1485
1629
|
ariaLiveText.value = `${emitParams.seriesName}: ${formatTooltipValue(emitParams.value)}`;
|
|
1486
1630
|
}
|
|
1487
|
-
}
|
|
1631
|
+
} else if (enterAnimated && hoverAnimProgress < 1) startHoverAnimation(1);
|
|
1488
1632
|
applyTooltipContent(result.params);
|
|
1489
1633
|
if (props.options.tooltip?.trigger === "click") return;
|
|
1490
1634
|
lastMouseClientX = e.clientX;
|
|
@@ -1771,6 +1915,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
1771
1915
|
stopHoverAnimation();
|
|
1772
1916
|
stopTweenAnimation();
|
|
1773
1917
|
stopSceneTimer();
|
|
1918
|
+
stopFocusAnimation();
|
|
1774
1919
|
if (tooltipRafId !== null) {
|
|
1775
1920
|
cancelAnimationFrame(tooltipRafId);
|
|
1776
1921
|
tooltipRafId = null;
|
|
@@ -2087,7 +2232,7 @@ var chart_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__
|
|
|
2087
2232
|
], 12, _hoisted_1);
|
|
2088
2233
|
};
|
|
2089
2234
|
}
|
|
2090
|
-
}), [["__scopeId", "data-v-
|
|
2235
|
+
}), [["__scopeId", "data-v-df8a90cc"]]);
|
|
2091
2236
|
//#endregion
|
|
2092
2237
|
//#region src/useChart.js
|
|
2093
2238
|
var USE_CHART_KEY = /* @__PURE__ */ Symbol("ev-chart-context");
|