@wil-works/evoke-charts 0.2.0 → 0.3.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 CHANGED
@@ -10,6 +10,8 @@
10
10
  - **零运行时依赖**:仅 peer 依赖 Vue 3,全部绘制自研 Canvas 2D
11
11
  - **主题跟随**:从 `--ev-*` CSS 令牌实时读取颜色,宿主换主题 / 暗色即跟随;无令牌时使用内置色板兜底
12
12
  - **交互完备**:tooltip、图例点选 / 悬停高亮、十字准线、dataZoom(滑块 / 滚轮 / 触摸平移)、框选刷选、工具箱(导出 PNG / 还原)、多图 connect 联动
13
+ - **叙述与编排**:`annotations[]` 图内旁白(峰值标注 / 区间强调 / 涨跌结论)、`emphasis` 焦点弱化、`scenes` 分幕 reveal / 自动播报
14
+ - **AI 生成**:`generateChartSpec` 数据直生(CSV / 表格 → Spec,列推断与选型全自动)、`buildChartPrompt` 提示词契约(喂给任意大模型)、`lintChartSpec` 渲染自检;Spec 即 `options`,`getSpec / setSpec` 往返
13
15
  - **导出**:`toDataURL`(PNG)、`exportSVG`(真矢量,渲染指令录制重放)
14
16
  - **无障碍**:`role="img"` + aria-label、hover 信息 aria-live 播报
15
17
 
@@ -61,7 +63,7 @@ const options = {
61
63
  图表颜色按以下 `--ev-*` 令牌实时读取(`document.documentElement` 上取值),未定义的槽位逐槽回落到内置成套色板:
62
64
 
63
65
  - 系列色:`--ev-color-series-1` … `--ev-color-series-8`(数据系列专用色板,与状态语义色解耦;槽 1 未定义时回读 `--ev-color-primary`,主题跟随不受影响)
64
- - 表面:`--ev-bg-color`、`--ev-bg-color-overlay`、`--ev-app-card-border`
66
+ - 表面:`--ev-bg-color`、`--ev-bg-color-overlay`
65
67
  - 文字:`--ev-text-color-primary / -secondary / -danger`
66
68
  - 边线:`--ev-border-color / -light / -dark`
67
69
  - 填充:`--ev-fill-color-light / -dark`
@@ -1,24 +1,36 @@
1
1
 
2
- .ev-chart[data-v-a07b68e8] {
2
+ .ev-chart[data-v-ce034a2a] {
3
3
  position: relative;
4
- overflow: hidden;
4
+ /* 容器不带边框:是否加框、加多粗由宿主决定,图表只负责内容;
5
+ 圆角裁剪下沉到 canvas 与浮层自身(border-radius: inherit) */
6
+ overflow: visible;
5
7
  border-radius: 8px;
6
8
  background: var(--ev-bg-color, #ffffff);
7
- border: 1px solid var(--ev-app-card-border, #e2e8f0);
8
9
  }
9
10
 
10
11
  /* 关键:canvas 必须能接收鼠标事件 */
11
- .ev-chart__canvas[data-v-a07b68e8] {
12
+ .ev-chart__canvas[data-v-ce034a2a] {
12
13
  position: absolute;
13
14
  top: 0;
14
15
  left: 0;
15
16
  width: 100%;
16
17
  height: 100%;
17
18
  display: block;
19
+ border-radius: inherit;
18
20
  /* 触摸:纵向留给页面滚动,横向拖拽由图表接管(dataZoom 平移) */
19
21
  touch-action: pan-y;
20
22
  }
21
- .ev-chart__tooltip[data-v-a07b68e8] {
23
+
24
+ /* HTML 覆盖层:只在内容层,不与 canvas 抢交互(子元素可自行 pointer-events:auto),
25
+ 也不压过 tooltip(z-index 100) */
26
+ .ev-chart__overlay[data-v-ce034a2a] {
27
+ position: absolute;
28
+ inset: 0;
29
+ z-index: 1;
30
+ pointer-events: none;
31
+ border-radius: inherit;
32
+ }
33
+ .ev-chart__tooltip[data-v-ce034a2a] {
22
34
  position: absolute;
23
35
  pointer-events: none;
24
36
  z-index: 100;
@@ -39,47 +51,47 @@
39
51
  }
40
52
 
41
53
  /* tooltip 淡入淡出(仅 opacity,位置由 left/top transition 负责) */
42
- .ev-chart-tooltip-enter-active[data-v-a07b68e8],
43
- .ev-chart-tooltip-leave-active[data-v-a07b68e8] {
54
+ .ev-chart-tooltip-enter-active[data-v-ce034a2a],
55
+ .ev-chart-tooltip-leave-active[data-v-ce034a2a] {
44
56
  transition: opacity 0.18s ease;
45
57
  }
46
58
 
47
59
  /* 进入期间禁用位置 transition,避免首次出现时从旧位置滑入 */
48
- .ev-chart-tooltip-enter-active[data-v-a07b68e8] {
60
+ .ev-chart-tooltip-enter-active[data-v-ce034a2a] {
49
61
  transition:
50
62
  opacity 0.18s ease,
51
63
  left 0s,
52
64
  top 0s;
53
65
  }
54
- .ev-chart-tooltip-enter-from[data-v-a07b68e8],
55
- .ev-chart-tooltip-leave-to[data-v-a07b68e8] {
66
+ .ev-chart-tooltip-enter-from[data-v-ce034a2a],
67
+ .ev-chart-tooltip-leave-to[data-v-ce034a2a] {
56
68
  opacity: 0;
57
69
  }
58
70
 
59
71
  /* v-html 注入的内容不带 scoped 属性,需用 :deep() 穿透 */
60
- [data-v-a07b68e8] .ev-chart__tooltip-title {
72
+ [data-v-ce034a2a] .ev-chart__tooltip-title {
61
73
  color: var(--ev-text-color-secondary, #6b7280);
62
74
  font-size: 12px;
63
75
  margin-bottom: 6px;
64
76
  font-weight: 500;
65
77
  }
66
- [data-v-a07b68e8] .ev-chart__tooltip-item {
78
+ [data-v-ce034a2a] .ev-chart__tooltip-item {
67
79
  display: flex;
68
80
  align-items: center;
69
81
  gap: 8px;
70
82
  padding: 2px 0;
71
83
  }
72
- [data-v-a07b68e8] .ev-chart__tooltip-dot {
84
+ [data-v-ce034a2a] .ev-chart__tooltip-dot {
73
85
  width: 8px;
74
86
  height: 8px;
75
87
  border-radius: 50%;
76
88
  flex-shrink: 0;
77
89
  display: inline-block;
78
90
  }
79
- [data-v-a07b68e8] .ev-chart__tooltip-name {
91
+ [data-v-ce034a2a] .ev-chart__tooltip-name {
80
92
  color: var(--ev-text-color-primary, #111827);
81
93
  }
82
- [data-v-a07b68e8] .ev-chart__tooltip-value {
94
+ [data-v-ce034a2a] .ev-chart__tooltip-value {
83
95
  color: var(--ev-text-color-primary, #111827);
84
96
  font-weight: 600;
85
97
  margin-left: auto;
@@ -88,9 +100,10 @@
88
100
  }
89
101
 
90
102
  /* ══════ 空数据占位 ══════ */
91
- .ev-chart__empty[data-v-a07b68e8] {
103
+ .ev-chart__empty[data-v-ce034a2a] {
92
104
  position: absolute;
93
105
  inset: 0;
106
+ border-radius: inherit;
94
107
  display: flex;
95
108
  flex-direction: column;
96
109
  align-items: center;
@@ -100,7 +113,7 @@
100
113
  gap: 14px;
101
114
  user-select: none;
102
115
  }
103
- .ev-chart__empty-icon-wrap[data-v-a07b68e8] {
116
+ .ev-chart__empty-icon-wrap[data-v-ce034a2a] {
104
117
  display: flex;
105
118
  align-items: center;
106
119
  justify-content: center;
@@ -109,40 +122,41 @@
109
122
  border-radius: 16px;
110
123
  background: var(--ev-fill-color-light, #f5f7fa);
111
124
  }
112
- .ev-chart__empty-img[data-v-a07b68e8] {
125
+ .ev-chart__empty-img[data-v-ce034a2a] {
113
126
  width: 32px;
114
127
  height: 32px;
115
128
  opacity: 0.4;
116
129
  }
117
- .ev-chart__empty-text[data-v-a07b68e8] {
130
+ .ev-chart__empty-text[data-v-ce034a2a] {
118
131
  letter-spacing: 0.04em;
119
132
  font-weight: 500;
120
133
  font-size: 13px;
121
134
  }
122
135
 
123
136
  /* ══════ 加载中骨架 ══════ */
124
- .ev-chart__loading[data-v-a07b68e8] {
137
+ .ev-chart__loading[data-v-ce034a2a] {
125
138
  position: absolute;
126
139
  inset: 0;
140
+ border-radius: inherit;
127
141
  display: flex;
128
142
  align-items: center;
129
143
  justify-content: center;
130
144
  background: var(--ev-bg-color, #ffffff);
131
145
  }
132
- .ev-chart__loading-bars[data-v-a07b68e8] {
146
+ .ev-chart__loading-bars[data-v-ce034a2a] {
133
147
  display: flex;
134
148
  align-items: flex-end;
135
149
  gap: 6px;
136
150
  height: 60px;
137
151
  }
138
- .ev-chart__loading-bar[data-v-a07b68e8] {
152
+ .ev-chart__loading-bar[data-v-ce034a2a] {
139
153
  width: 10px;
140
154
  height: 40px;
141
155
  border-radius: 4px;
142
156
  background: var(--ev-border-color, #e2e8f0);
143
- animation: ev-chart-shimmer-a07b68e8 1.2s ease-in-out infinite;
157
+ animation: ev-chart-shimmer-ce034a2a 1.2s ease-in-out infinite;
144
158
  }
145
- @keyframes ev-chart-shimmer-a07b68e8 {
159
+ @keyframes ev-chart-shimmer-ce034a2a {
146
160
  0%,
147
161
  100% {
148
162
  transform: scaleY(0.4);
@@ -155,9 +169,10 @@
155
169
  }
156
170
 
157
171
  /* ══════ 错误边界 ══════ */
158
- .ev-chart__error[data-v-a07b68e8] {
172
+ .ev-chart__error[data-v-ce034a2a] {
159
173
  position: absolute;
160
174
  inset: 0;
175
+ border-radius: inherit;
161
176
  display: flex;
162
177
  flex-direction: column;
163
178
  align-items: center;
@@ -168,13 +183,13 @@
168
183
  padding: 20px;
169
184
  text-align: center;
170
185
  }
171
- .ev-chart__error-icon[data-v-a07b68e8] {
186
+ .ev-chart__error-icon[data-v-ce034a2a] {
172
187
  display: flex;
173
188
  align-items: center;
174
189
  justify-content: center;
175
190
  font-size: 30px;
176
191
  }
177
- .ev-chart__error-text[data-v-a07b68e8] {
192
+ .ev-chart__error-text[data-v-ce034a2a] {
178
193
  font-size: 12px;
179
194
  line-height: 1.5;
180
195
  max-width: 80%;
@@ -182,17 +197,17 @@
182
197
  }
183
198
 
184
199
  /* ══════ 进入/离开淡入淡出 ══════ */
185
- .ev-chart-fade-enter-active[data-v-a07b68e8],
186
- .ev-chart-fade-leave-active[data-v-a07b68e8] {
200
+ .ev-chart-fade-enter-active[data-v-ce034a2a],
201
+ .ev-chart-fade-leave-active[data-v-ce034a2a] {
187
202
  transition: opacity 0.2s ease;
188
203
  }
189
- .ev-chart-fade-enter-from[data-v-a07b68e8],
190
- .ev-chart-fade-leave-to[data-v-a07b68e8] {
204
+ .ev-chart-fade-enter-from[data-v-ce034a2a],
205
+ .ev-chart-fade-leave-to[data-v-ce034a2a] {
191
206
  opacity: 0;
192
207
  }
193
208
 
194
209
  /* ══════ 无障碍:sr-only ══════ */
195
- .ev-chart__sr-only[data-v-a07b68e8] {
210
+ .ev-chart__sr-only[data-v-ce034a2a] {
196
211
  position: absolute;
197
212
  width: 1px;
198
213
  height: 1px;