@dou-ui/chart 0.0.0-stage → 0.1.0-alpha.1

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 (237) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/chart.js +6 -0
  4. package/dist/chart.js.map +1 -0
  5. package/dist/chart.vue_vue_type_script_setup_true_lang.js +4245 -0
  6. package/dist/chart.vue_vue_type_script_setup_true_lang.js.map +1 -0
  7. package/dist/components/area.js +6 -0
  8. package/dist/components/area.js.map +1 -0
  9. package/dist/components/area.vue_vue_type_script_setup_true_lang.js +55 -0
  10. package/dist/components/area.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/components/axis.js +6 -0
  12. package/dist/components/axis.js.map +1 -0
  13. package/dist/components/axis.vue_vue_type_script_setup_true_lang.js +46 -0
  14. package/dist/components/axis.vue_vue_type_script_setup_true_lang.js.map +1 -0
  15. package/dist/components/bar.js +6 -0
  16. package/dist/components/bar.js.map +1 -0
  17. package/dist/components/bar.vue_vue_type_script_setup_true_lang.js +46 -0
  18. package/dist/components/bar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  19. package/dist/components/boxplot.js +6 -0
  20. package/dist/components/boxplot.js.map +1 -0
  21. package/dist/components/boxplot.vue_vue_type_script_setup_true_lang.js +42 -0
  22. package/dist/components/boxplot.vue_vue_type_script_setup_true_lang.js.map +1 -0
  23. package/dist/components/brush.js +6 -0
  24. package/dist/components/brush.js.map +1 -0
  25. package/dist/components/brush.vue_vue_type_script_setup_true_lang.js +42 -0
  26. package/dist/components/brush.vue_vue_type_script_setup_true_lang.js.map +1 -0
  27. package/dist/components/funnel.js +6 -0
  28. package/dist/components/funnel.js.map +1 -0
  29. package/dist/components/funnel.vue_vue_type_script_setup_true_lang.js +41 -0
  30. package/dist/components/funnel.vue_vue_type_script_setup_true_lang.js.map +1 -0
  31. package/dist/components/gauge.js +6 -0
  32. package/dist/components/gauge.js.map +1 -0
  33. package/dist/components/gauge.vue_vue_type_script_setup_true_lang.js +91 -0
  34. package/dist/components/gauge.vue_vue_type_script_setup_true_lang.js.map +1 -0
  35. package/dist/components/heatmap.js +6 -0
  36. package/dist/components/heatmap.js.map +1 -0
  37. package/dist/components/heatmap.vue_vue_type_script_setup_true_lang.js +45 -0
  38. package/dist/components/heatmap.vue_vue_type_script_setup_true_lang.js.map +1 -0
  39. package/dist/components/histogram.js +6 -0
  40. package/dist/components/histogram.js.map +1 -0
  41. package/dist/components/histogram.vue_vue_type_script_setup_true_lang.js +61 -0
  42. package/dist/components/histogram.vue_vue_type_script_setup_true_lang.js.map +1 -0
  43. package/dist/components/line.js +6 -0
  44. package/dist/components/line.js.map +1 -0
  45. package/dist/components/line.vue_vue_type_script_setup_true_lang.js +52 -0
  46. package/dist/components/line.vue_vue_type_script_setup_true_lang.js.map +1 -0
  47. package/dist/components/marker.js +6 -0
  48. package/dist/components/marker.js.map +1 -0
  49. package/dist/components/marker.vue_vue_type_script_setup_true_lang.js +31 -0
  50. package/dist/components/marker.vue_vue_type_script_setup_true_lang.js.map +1 -0
  51. package/dist/components/pie.js +6 -0
  52. package/dist/components/pie.js.map +1 -0
  53. package/dist/components/pie.vue_vue_type_script_setup_true_lang.js +42 -0
  54. package/dist/components/pie.vue_vue_type_script_setup_true_lang.js.map +1 -0
  55. package/dist/components/radar.js +6 -0
  56. package/dist/components/radar.js.map +1 -0
  57. package/dist/components/radar.vue_vue_type_script_setup_true_lang.js +45 -0
  58. package/dist/components/radar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  59. package/dist/components/range.js +6 -0
  60. package/dist/components/range.js.map +1 -0
  61. package/dist/components/range.vue_vue_type_script_setup_true_lang.js +27 -0
  62. package/dist/components/range.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/components/scatter.js +6 -0
  64. package/dist/components/scatter.js.map +1 -0
  65. package/dist/components/scatter.vue_vue_type_script_setup_true_lang.js +45 -0
  66. package/dist/components/scatter.vue_vue_type_script_setup_true_lang.js.map +1 -0
  67. package/dist/components/sunburst.js +6 -0
  68. package/dist/components/sunburst.js.map +1 -0
  69. package/dist/components/sunburst.vue_vue_type_script_setup_true_lang.js +36 -0
  70. package/dist/components/sunburst.vue_vue_type_script_setup_true_lang.js.map +1 -0
  71. package/dist/components/tooltip.js +6 -0
  72. package/dist/components/tooltip.js.map +1 -0
  73. package/dist/components/tooltip.vue_vue_type_script_setup_true_lang.js +31 -0
  74. package/dist/components/tooltip.vue_vue_type_script_setup_true_lang.js.map +1 -0
  75. package/dist/components/treemap.js +6 -0
  76. package/dist/components/treemap.js.map +1 -0
  77. package/dist/components/treemap.vue_vue_type_script_setup_true_lang.js +33 -0
  78. package/dist/components/treemap.vue_vue_type_script_setup_true_lang.js.map +1 -0
  79. package/dist/components/waterfall.js +6 -0
  80. package/dist/components/waterfall.js.map +1 -0
  81. package/dist/components/waterfall.vue_vue_type_script_setup_true_lang.js +49 -0
  82. package/dist/components/waterfall.vue_vue_type_script_setup_true_lang.js.map +1 -0
  83. package/dist/components/zoom.js +6 -0
  84. package/dist/components/zoom.js.map +1 -0
  85. package/dist/components/zoom.vue_vue_type_script_setup_true_lang.js +37 -0
  86. package/dist/components/zoom.vue_vue_type_script_setup_true_lang.js.map +1 -0
  87. package/dist/context.js +30 -0
  88. package/dist/context.js.map +1 -0
  89. package/dist/core/bar.js +223 -0
  90. package/dist/core/bar.js.map +1 -0
  91. package/dist/core/box.js +150 -0
  92. package/dist/core/box.js.map +1 -0
  93. package/dist/core/colors.js +58 -0
  94. package/dist/core/colors.js.map +1 -0
  95. package/dist/core/data.js +257 -0
  96. package/dist/core/data.js.map +1 -0
  97. package/dist/core/decimate.js +211 -0
  98. package/dist/core/decimate.js.map +1 -0
  99. package/dist/core/format.js +151 -0
  100. package/dist/core/format.js.map +1 -0
  101. package/dist/core/funnel.js +68 -0
  102. package/dist/core/funnel.js.map +1 -0
  103. package/dist/core/grid.js +87 -0
  104. package/dist/core/grid.js.map +1 -0
  105. package/dist/core/heatmap.js +187 -0
  106. package/dist/core/heatmap.js.map +1 -0
  107. package/dist/core/histogram.js +81 -0
  108. package/dist/core/histogram.js.map +1 -0
  109. package/dist/core/hit.js +115 -0
  110. package/dist/core/hit.js.map +1 -0
  111. package/dist/core/labels.js +141 -0
  112. package/dist/core/labels.js.map +1 -0
  113. package/dist/core/layout.js +1002 -0
  114. package/dist/core/layout.js.map +1 -0
  115. package/dist/core/line.js +230 -0
  116. package/dist/core/line.js.map +1 -0
  117. package/dist/core/marker.js +205 -0
  118. package/dist/core/marker.js.map +1 -0
  119. package/dist/core/model.js +391 -0
  120. package/dist/core/model.js.map +1 -0
  121. package/dist/core/painter.js +79 -0
  122. package/dist/core/painter.js.map +1 -0
  123. package/dist/core/pattern.js +102 -0
  124. package/dist/core/pattern.js.map +1 -0
  125. package/dist/core/pie.js +119 -0
  126. package/dist/core/pie.js.map +1 -0
  127. package/dist/core/radar.js +83 -0
  128. package/dist/core/radar.js.map +1 -0
  129. package/dist/core/scale.js +149 -0
  130. package/dist/core/scale.js.map +1 -0
  131. package/dist/core/scatter.js +263 -0
  132. package/dist/core/scatter.js.map +1 -0
  133. package/dist/core/svg.js +209 -0
  134. package/dist/core/svg.js.map +1 -0
  135. package/dist/core/sync.js +21 -0
  136. package/dist/core/sync.js.map +1 -0
  137. package/dist/core/time.js +217 -0
  138. package/dist/core/time.js.map +1 -0
  139. package/dist/core/tree.js +348 -0
  140. package/dist/core/tree.js.map +1 -0
  141. package/dist/core/warn.js +11 -0
  142. package/dist/core/warn.js.map +1 -0
  143. package/dist/core/waterfall.js +134 -0
  144. package/dist/core/waterfall.js.map +1 -0
  145. package/dist/core/window.js +94 -0
  146. package/dist/core/window.js.map +1 -0
  147. package/dist/define.js +62 -0
  148. package/dist/define.js.map +1 -0
  149. package/dist/index.js +49 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/locale.js +170 -0
  152. package/dist/locale.js.map +1 -0
  153. package/dist/overlay.js +6 -0
  154. package/dist/overlay.js.map +1 -0
  155. package/dist/overlay.vue_vue_type_script_setup_true_lang.js +207 -0
  156. package/dist/overlay.vue_vue_type_script_setup_true_lang.js.map +1 -0
  157. package/dist/pointer.js +6 -0
  158. package/dist/pointer.js.map +1 -0
  159. package/dist/pointer.vue_vue_type_script_setup_true_lang.js +136 -0
  160. package/dist/pointer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  161. package/dist/static.js +6 -0
  162. package/dist/static.js.map +1 -0
  163. package/dist/static.vue_vue_type_script_setup_true_lang.js +34 -0
  164. package/dist/static.vue_vue_type_script_setup_true_lang.js.map +1 -0
  165. package/dist/style.css +1 -0
  166. package/dist/style.d.ts +1 -0
  167. package/dist/style.js +3 -0
  168. package/dist/table.js +6 -0
  169. package/dist/table.js.map +1 -0
  170. package/dist/table.vue_vue_type_script_setup_true_lang.js +52 -0
  171. package/dist/table.vue_vue_type_script_setup_true_lang.js.map +1 -0
  172. package/dist/types/chart.vue.d.ts +24 -0
  173. package/dist/types/components/area.vue.d.ts +16 -0
  174. package/dist/types/components/axis.vue.d.ts +8 -0
  175. package/dist/types/components/bar.vue.d.ts +14 -0
  176. package/dist/types/components/boxplot.vue.d.ts +14 -0
  177. package/dist/types/components/brush.vue.d.ts +22 -0
  178. package/dist/types/components/funnel.vue.d.ts +14 -0
  179. package/dist/types/components/gauge.vue.d.ts +17 -0
  180. package/dist/types/components/heatmap.vue.d.ts +14 -0
  181. package/dist/types/components/histogram.vue.d.ts +14 -0
  182. package/dist/types/components/line.vue.d.ts +16 -0
  183. package/dist/types/components/marker.vue.d.ts +6 -0
  184. package/dist/types/components/pie.vue.d.ts +23 -0
  185. package/dist/types/components/radar.vue.d.ts +16 -0
  186. package/dist/types/components/range.vue.d.ts +12 -0
  187. package/dist/types/components/scatter.vue.d.ts +14 -0
  188. package/dist/types/components/sunburst.vue.d.ts +17 -0
  189. package/dist/types/components/tooltip.vue.d.ts +13 -0
  190. package/dist/types/components/treemap.vue.d.ts +8 -0
  191. package/dist/types/components/waterfall.vue.d.ts +16 -0
  192. package/dist/types/components/zoom.vue.d.ts +18 -0
  193. package/dist/types/context.d.ts +87 -0
  194. package/dist/types/core/bar.d.ts +38 -0
  195. package/dist/types/core/box.d.ts +25 -0
  196. package/dist/types/core/colors.d.ts +16 -0
  197. package/dist/types/core/data.d.ts +72 -0
  198. package/dist/types/core/decimate.d.ts +39 -0
  199. package/dist/types/core/format.d.ts +33 -0
  200. package/dist/types/core/funnel.d.ts +15 -0
  201. package/dist/types/core/grid.d.ts +18 -0
  202. package/dist/types/core/heatmap.d.ts +17 -0
  203. package/dist/types/core/histogram.d.ts +23 -0
  204. package/dist/types/core/hit.d.ts +31 -0
  205. package/dist/types/core/labels.d.ts +45 -0
  206. package/dist/types/core/layout.d.ts +259 -0
  207. package/dist/types/core/line.d.ts +36 -0
  208. package/dist/types/core/marker.d.ts +67 -0
  209. package/dist/types/core/model.d.ts +86 -0
  210. package/dist/types/core/painter.d.ts +34 -0
  211. package/dist/types/core/pattern.d.ts +14 -0
  212. package/dist/types/core/pie.d.ts +66 -0
  213. package/dist/types/core/radar.d.ts +12 -0
  214. package/dist/types/core/scale.d.ts +60 -0
  215. package/dist/types/core/scatter.d.ts +16 -0
  216. package/dist/types/core/series.d.ts +228 -0
  217. package/dist/types/core/svg.d.ts +63 -0
  218. package/dist/types/core/sync.d.ts +8 -0
  219. package/dist/types/core/time.d.ts +20 -0
  220. package/dist/types/core/tree.d.ts +84 -0
  221. package/dist/types/core/warn.d.ts +4 -0
  222. package/dist/types/core/waterfall.d.ts +24 -0
  223. package/dist/types/core/window.d.ts +36 -0
  224. package/dist/types/define.d.ts +115 -0
  225. package/dist/types/index.d.ts +363 -0
  226. package/dist/types/locale.d.ts +100 -0
  227. package/dist/types/overlay.vue.d.ts +95 -0
  228. package/dist/types/pointer.vue.d.ts +53 -0
  229. package/dist/types/static.vue.d.ts +24 -0
  230. package/dist/types/table.vue.d.ts +19 -0
  231. package/dist/types/types.d.ts +555 -0
  232. package/dist/types/zoom-layer.vue.d.ts +41 -0
  233. package/dist/zoom-layer.js +6 -0
  234. package/dist/zoom-layer.js.map +1 -0
  235. package/dist/zoom-layer.vue_vue_type_script_setup_true_lang.js +210 -0
  236. package/dist/zoom-layer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  237. package/package.json +53 -4
@@ -0,0 +1,134 @@
1
+ import { visibleRange } from "./decimate.js";
2
+ import { barLabels, barPlacement } from "./bar.js";
3
+ import { read, rowOf } from "./data.js";
4
+ // src/core/waterfall.ts
5
+ /**
6
+ * The bars of a waterfall: where each starts (`base`) and ends (`top`), and
7
+ * its value (`y`): the change, or for a total row, the running total. A
8
+ * row without a value is left out and changes nothing.
9
+ */
10
+ function waterfallSteps(rows, changes, total) {
11
+ const n = changes.length;
12
+ const y = new Float64Array(n);
13
+ const top = new Float64Array(n);
14
+ const base = new Float64Array(n);
15
+ let sum = 0;
16
+ for (let i = 0; i < n; i++) {
17
+ if (total !== void 0 && read(rowOf(rows, i), total, i)) {
18
+ y[i] = top[i] = sum;
19
+ base[i] = 0;
20
+ continue;
21
+ }
22
+ const change = changes[i];
23
+ if (change !== change) {
24
+ y[i] = top[i] = base[i] = NaN;
25
+ continue;
26
+ }
27
+ y[i] = change;
28
+ base[i] = sum;
29
+ sum += change;
30
+ top[i] = sum;
31
+ }
32
+ return {
33
+ y,
34
+ top,
35
+ base
36
+ };
37
+ }
38
+ /** Whether row `i` of a waterfall is a total. */
39
+ function isTotal(series, i) {
40
+ const total = series.props.total;
41
+ return total !== void 0 && !!read(rowOf(series.rows, i), total, i);
42
+ }
43
+ function draw(painter, series, view) {
44
+ const { x: sx, y: sy, dpr, horizontal } = view;
45
+ const xs = series.x.values;
46
+ const { top, base } = series;
47
+ if (!base) return;
48
+ const [from, to] = visibleRange(xs, series.x.sorted, sx.domain[0], sx.domain[1]);
49
+ const { offset, width } = barPlacement(view.band, series.slot);
50
+ const snap = (v) => Math.round(v * dpr) / dpr;
51
+ const radius = Math.max(0, series.props.radius ?? 2);
52
+ const p = (u, v) => horizontal ? [v, u] : [u, v];
53
+ if (series.props.connectors ?? true) {
54
+ painter.save();
55
+ painter.strokeStyle = view.colors.baseline;
56
+ painter.lineWidth = 1;
57
+ painter.setLineDash([3, 3]);
58
+ painter.beginPath();
59
+ let last = -1;
60
+ for (let i = from; i < to; i++) {
61
+ if (top[i] !== top[i] || xs[i] !== xs[i]) continue;
62
+ if (last >= 0) {
63
+ const v = snap(sy.map(top[last])) + .5;
64
+ const u0 = snap(sx.map(xs[last]) + offset + width);
65
+ const u1 = snap(sx.map(xs[i]) + offset);
66
+ if (u1 > u0) {
67
+ painter.moveTo(...p(u0, v));
68
+ painter.lineTo(...p(u1, v));
69
+ }
70
+ }
71
+ last = i;
72
+ }
73
+ painter.stroke();
74
+ painter.restore();
75
+ }
76
+ const bar = (i) => {
77
+ const value = top[i];
78
+ const x = xs[i];
79
+ if (value !== value || x !== x) return;
80
+ const u0 = snap(sx.map(x) + offset);
81
+ const u1 = Math.max(u0 + 1 / dpr, snap(sx.map(x) + offset + width));
82
+ let v0 = snap(sy.map(base[i]));
83
+ let v1 = snap(sy.map(value));
84
+ if (Math.abs(v1 - v0) < 1) [v0, v1] = [v0 - .5, v0 + .5];
85
+ const lo = Math.min(v0, v1);
86
+ const hi = Math.max(v0, v1);
87
+ const r = Math.min(radius, (u1 - u0) / 2, (hi - lo) / 2);
88
+ const zero = snap(sy.map(0));
89
+ const rLo = Math.abs(lo - zero) < 1 ? 0 : r;
90
+ const rHi = Math.abs(hi - zero) < 1 ? 0 : r;
91
+ if (r < .5) {
92
+ const [x0, y0] = p(u0, lo);
93
+ const [x1, y1] = p(u1, hi);
94
+ painter.rect(Math.min(x0, x1), Math.min(y0, y1), Math.abs(x1 - x0), Math.abs(y1 - y0));
95
+ return;
96
+ }
97
+ const corner = (u, v, nu, nv, cr) => {
98
+ if (cr > 0) painter.arcTo(...p(u, v), ...p(nu, nv), cr);
99
+ else painter.lineTo(...p(u, v));
100
+ };
101
+ painter.moveTo(...p((u0 + u1) / 2, lo));
102
+ corner(u1, lo, u1, hi, rLo);
103
+ corner(u1, hi, u0, hi, rHi);
104
+ corner(u0, hi, u0, lo, rHi);
105
+ corner(u0, lo, u1, lo, rLo);
106
+ painter.closePath();
107
+ };
108
+ painter.save();
109
+ const groups = /* @__PURE__ */ new Map();
110
+ for (let i = from; i < to; i++) {
111
+ const color = series.colors?.[i] ?? series.color;
112
+ let group = groups.get(color);
113
+ if (!group) groups.set(color, group = []);
114
+ group.push(i);
115
+ }
116
+ for (const [color, rows] of groups) {
117
+ painter.fillStyle = color;
118
+ painter.beginPath();
119
+ for (const i of rows) bar(i);
120
+ painter.fill();
121
+ }
122
+ painter.restore();
123
+ }
124
+ var waterfallKind = {
125
+ type: "bar",
126
+ waterfall: true,
127
+ zero: true,
128
+ band: true,
129
+ draw,
130
+ labels: barLabels
131
+ };
132
+ export { isTotal, waterfallKind, waterfallSteps };
133
+
134
+ //# sourceMappingURL=waterfall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waterfall.js","names":[],"sources":["../../src/core/waterfall.ts"],"sourcesContent":["import { barLabels, barPlacement } from './bar'\nimport { read, rowOf, type ChartAccessor, type ChartData } from './data'\nimport { visibleRange } from './decimate'\nimport type { Painter } from './painter'\nimport type { ChartSeries, ChartSeriesKind } from './series'\n\n/*\n * A waterfall: each row a change, drawn as a bar floating from the running\n * total before it to the total after; a total row (`total`) is a bar from\n * 0 up to the running total so far. A thin line joins each bar's end to\n * the next bar, at the total they share.\n */\n\nexport interface WaterfallStyle {\n /** Whether a row is a total: a key of the row or a function of it. */\n total?: ChartAccessor\n /** Corner radius of the bars, in px. */\n radius?: number\n /** Lines from each bar to the next, at the total they share. */\n connectors?: boolean\n labelPosition?: 'outside' | 'inside'\n}\n\n/**\n * The bars of a waterfall: where each starts (`base`) and ends (`top`), and\n * its value (`y`): the change, or for a total row, the running total. A\n * row without a value is left out and changes nothing.\n */\nexport function waterfallSteps(\n rows: ChartData,\n changes: Float64Array,\n total: ChartAccessor | undefined,\n): { y: Float64Array; top: Float64Array; base: Float64Array } {\n const n = changes.length\n const y = new Float64Array(n)\n const top = new Float64Array(n)\n const base = new Float64Array(n)\n let sum = 0\n for (let i = 0; i < n; i++) {\n if (total !== undefined && read(rowOf(rows, i), total, i)) {\n y[i] = top[i] = sum\n base[i] = 0\n continue\n }\n const change = changes[i]!\n if (change !== change) {\n y[i] = top[i] = base[i] = Number.NaN\n continue\n }\n y[i] = change\n base[i] = sum\n sum += change\n top[i] = sum\n }\n return { y, top, base }\n}\n\n/** Whether row `i` of a waterfall is a total. */\nexport function isTotal(series: Pick<ChartSeries<WaterfallStyle>, 'props' | 'rows'>, i: number) {\n const total = series.props.total\n return total !== undefined && !!read(rowOf(series.rows, i), total, i)\n}\n\nfunction draw(\n painter: Painter,\n series: ChartSeries<WaterfallStyle>,\n view: Parameters<ChartSeriesKind['draw']>[2],\n) {\n const { x: sx, y: sy, dpr, horizontal } = view\n const xs = series.x.values\n const { top, base } = series\n if (!base) return\n const [from, to] = visibleRange(xs, series.x.sorted, sx.domain[0], sx.domain[1])\n const { offset, width } = barPlacement(view.band, series.slot)\n const snap = (v: number) => Math.round(v * dpr) / dpr\n const radius = Math.max(0, series.props.radius ?? 2)\n const p = (u: number, v: number): [number, number] => (horizontal ? [v, u] : [u, v])\n\n // the lines first, under the bars: from each bar's end to the next bar\n if (series.props.connectors ?? true) {\n painter.save()\n painter.strokeStyle = view.colors.baseline\n painter.lineWidth = 1\n painter.setLineDash([3, 3])\n painter.beginPath()\n let last = -1\n for (let i = from; i < to; i++) {\n if (top[i] !== top[i] || xs[i] !== xs[i]) continue\n if (last >= 0) {\n // the total after the last bar, where this one starts (or a total bar ends)\n const v = snap(sy.map(top[last]!)) + 0.5\n const u0 = snap(sx.map(xs[last]!) + offset + width)\n const u1 = snap(sx.map(xs[i]!) + offset)\n if (u1 > u0) {\n painter.moveTo(...p(u0, v))\n painter.lineTo(...p(u1, v))\n }\n }\n last = i\n }\n painter.stroke()\n painter.restore()\n }\n\n const bar = (i: number) => {\n const value = top[i]!\n const x = xs[i]!\n if (value !== value || x !== x) return\n const u0 = snap(sx.map(x) + offset)\n const u1 = Math.max(u0 + 1 / dpr, snap(sx.map(x) + offset + width))\n let v0 = snap(sy.map(base[i]!))\n let v1 = snap(sy.map(value))\n // no change still shows, as a hairline at the total\n if (Math.abs(v1 - v0) < 1) [v0, v1] = [v0 - 0.5, v0 + 0.5]\n const lo = Math.min(v0, v1)\n const hi = Math.max(v0, v1)\n const r = Math.min(radius, (u1 - u0) / 2, (hi - lo) / 2)\n // the corners round, but not at an end that stands on 0 (a total's foot)\n const zero = snap(sy.map(0))\n const rLo = Math.abs(lo - zero) < 1 ? 0 : r\n const rHi = Math.abs(hi - zero) < 1 ? 0 : r\n if (r < 0.5) {\n const [x0, y0] = p(u0, lo)\n const [x1, y1] = p(u1, hi)\n painter.rect(Math.min(x0, x1), Math.min(y0, y1), Math.abs(x1 - x0), Math.abs(y1 - y0))\n return\n }\n const corner = (u: number, v: number, nu: number, nv: number, cr: number) => {\n if (cr > 0) painter.arcTo(...p(u, v), ...p(nu, nv), cr)\n else painter.lineTo(...p(u, v))\n }\n painter.moveTo(...p((u0 + u1) / 2, lo))\n corner(u1, lo, u1, hi, rLo)\n corner(u1, hi, u0, hi, rHi)\n corner(u0, hi, u0, lo, rHi)\n corner(u0, lo, u1, lo, rLo)\n painter.closePath()\n }\n\n painter.save()\n const groups = new Map<string, number[]>()\n for (let i = from; i < to; i++) {\n const color = series.colors?.[i] ?? series.color\n let group = groups.get(color)\n if (!group) groups.set(color, (group = []))\n group.push(i)\n }\n for (const [color, rows] of groups) {\n painter.fillStyle = color\n painter.beginPath()\n for (const i of rows) bar(i)\n painter.fill()\n }\n painter.restore()\n}\n\nexport const waterfallKind: ChartSeriesKind<WaterfallStyle> = {\n type: 'bar',\n waterfall: true,\n zero: true,\n band: true,\n draw,\n labels: barLabels,\n}\n"],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import { toTime } from "./data.js";
2
+ // src/core/window.ts
3
+ /** Turns a value as given (a category, a date, a number) into the scale's number; `NaN` if it can't be. */
4
+ function valueToNumber(value, kind, categories) {
5
+ if (kind === "category") {
6
+ const at = categories.indexOf(String(value));
7
+ return at < 0 ? NaN : at;
8
+ }
9
+ if (kind === "time") return toTime(value);
10
+ return typeof value === "number" ? value : Number(value);
11
+ }
12
+ /** The value as given for a scale number: the category, a `Date`, or the number. */
13
+ function numberToValue(value, kind, categories) {
14
+ if (kind === "category") return categories[value] ?? "";
15
+ if (kind === "time") return new Date(value);
16
+ return value;
17
+ }
18
+ /**
19
+ * The window of an interval as given; categories take their whole step,
20
+ * from half a step before the first to half after the last. `null` for
21
+ * none, or one that can't be read.
22
+ */
23
+ function intervalToWindow(interval, kind, categories) {
24
+ if (!interval) return null;
25
+ let a = valueToNumber(interval[0], kind, categories);
26
+ let b = valueToNumber(interval[1], kind, categories);
27
+ if (a !== a || b !== b) return null;
28
+ if (a > b) [a, b] = [b, a];
29
+ return kind === "category" ? [a - .5, b + .5] : a === b ? null : [a, b];
30
+ }
31
+ /** The interval of a window: for categories, the first and last mostly in it. */
32
+ function windowToInterval(window, kind, categories) {
33
+ if (kind === "category") {
34
+ const [a, b] = snapCategories(window);
35
+ return [categories[a + .5] ?? "", categories[b - .5] ?? ""];
36
+ }
37
+ return [numberToValue(window[0], kind, categories), numberToValue(window[1], kind, categories)];
38
+ }
39
+ /** A window on categories moved to whole steps, keeping at least one. */
40
+ function snapCategories([a, b]) {
41
+ let from = Math.round(a + .5);
42
+ let to = Math.round(b - .5);
43
+ if (to < from) from = to = Math.round((a + b) / 2);
44
+ return [from - .5, to + .5];
45
+ }
46
+ var same = {
47
+ to: (v) => v,
48
+ from: (v) => v
49
+ };
50
+ var log = {
51
+ to: Math.log10,
52
+ from: (u) => 10 ** u
53
+ };
54
+ var unitsOf = (scale) => scale.kind === "log" ? log : same;
55
+ /**
56
+ * `window` kept inside `full`, at least `least` wide (in units): a window
57
+ * that runs over an end is moved back, not cut. `null` when it covers
58
+ * all of `full`.
59
+ */
60
+ function clampWindow(window, full, least, units = same) {
61
+ const f0 = units.to(full[0]);
62
+ const f1 = units.to(full[1]);
63
+ let a = units.to(Math.min(window[0], window[1]));
64
+ let b = units.to(Math.max(window[0], window[1]));
65
+ const span = f1 - f0;
66
+ if (!(span > 0) || a !== a || b !== b) return null;
67
+ const wanted = Math.min(span, Math.max(b - a, Math.min(least, span)));
68
+ if (b - a < wanted) {
69
+ const middle = (a + b) / 2;
70
+ a = middle - wanted / 2;
71
+ b = middle + wanted / 2;
72
+ }
73
+ if (a < f0) [a, b] = [f0, f0 + (b - a)];
74
+ if (b > f1) [a, b] = [f1 - (b - a), f1];
75
+ a = Math.max(a, f0);
76
+ if (b - a >= span * (1 - 1e-9)) return null;
77
+ return [units.from(a), units.from(b)];
78
+ }
79
+ /** The window `scale` shows with its range moved `by` px: dragging the plot by `-by`. */
80
+ function panWindow(scale, by) {
81
+ const [r0, r1] = scale.range;
82
+ return order(scale.invert(r0 + by), scale.invert(r1 + by));
83
+ }
84
+ /** The window `scale` shows zoomed by `factor` (below 1 is in) about the pixel `at`. */
85
+ function zoomWindow(scale, at, factor) {
86
+ const [r0, r1] = scale.range;
87
+ return order(scale.invert(at + (r0 - at) * factor), scale.invert(at + (r1 - at) * factor));
88
+ }
89
+ var order = (a, b) => a <= b ? [a, b] : [b, a];
90
+ /** Whether `value` is at or between the ends of `window`. */
91
+ var within = (value, window) => value >= window[0] && value <= window[1];
92
+ export { clampWindow, intervalToWindow, numberToValue, panWindow, snapCategories, unitsOf, valueToNumber, windowToInterval, within, zoomWindow };
93
+
94
+ //# sourceMappingURL=window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window.js","names":[],"sources":["../../src/core/window.ts"],"sourcesContent":["/*\n * The stretch of an axis that is shown when zoomed in: a window on the\n * axis' whole domain, in the scale's own numbers (category indices, ms on\n * a time axis). Kept apart from the chart so it can be tested alone.\n */\nimport { toTime, type XKind } from './data'\nimport type { ChartTickValue } from './layout'\nimport type { Scale } from './scale'\n\nexport type Window = [number, number]\n\n/** Turns a value as given (a category, a date, a number) into the scale's number; `NaN` if it can't be. */\nexport function valueToNumber(value: ChartTickValue, kind: XKind, categories: string[]): number {\n if (kind === 'category') {\n const at = categories.indexOf(String(value))\n return at < 0 ? Number.NaN : at\n }\n if (kind === 'time') return toTime(value)\n return typeof value === 'number' ? value : Number(value)\n}\n\n/** The value as given for a scale number: the category, a `Date`, or the number. */\nexport function numberToValue(value: number, kind: XKind, categories: string[]): ChartTickValue {\n if (kind === 'category') return categories[value] ?? ''\n if (kind === 'time') return new Date(value)\n return value\n}\n\n/**\n * The window of an interval as given; categories take their whole step,\n * from half a step before the first to half after the last. `null` for\n * none, or one that can't be read.\n */\nexport function intervalToWindow(\n interval: readonly [ChartTickValue, ChartTickValue] | null | undefined,\n kind: XKind,\n categories: string[],\n): Window | null {\n if (!interval) return null\n let a = valueToNumber(interval[0], kind, categories)\n let b = valueToNumber(interval[1], kind, categories)\n if (a !== a || b !== b) return null\n if (a > b) [a, b] = [b, a]\n return kind === 'category' ? [a - 0.5, b + 0.5] : a === b ? null : [a, b]\n}\n\n/** The interval of a window: for categories, the first and last mostly in it. */\nexport function windowToInterval(\n window: Window,\n kind: XKind,\n categories: string[],\n): [ChartTickValue, ChartTickValue] {\n if (kind === 'category') {\n const [a, b] = snapCategories(window)\n return [categories[a + 0.5] ?? '', categories[b - 0.5] ?? '']\n }\n return [numberToValue(window[0], kind, categories), numberToValue(window[1], kind, categories)]\n}\n\n/** A window on categories moved to whole steps, keeping at least one. */\nexport function snapCategories([a, b]: Window): Window {\n let from = Math.round(a + 0.5)\n let to = Math.round(b - 0.5)\n if (to < from) {\n const middle = Math.round((a + b) / 2)\n from = to = middle\n }\n return [from - 0.5, to + 0.5]\n}\n\n/** Numbers a scale is even in: the log of a log scale's values. */\nexport interface Units {\n to: (value: number) => number\n from: (unit: number) => number\n}\n\nconst same: Units = { to: (v) => v, from: (v) => v }\nconst log: Units = { to: Math.log10, from: (u) => 10 ** u }\nexport const unitsOf = (scale: Pick<Scale, 'kind'>): Units => (scale.kind === 'log' ? log : same)\n\n/**\n * `window` kept inside `full`, at least `least` wide (in units): a window\n * that runs over an end is moved back, not cut. `null` when it covers\n * all of `full`.\n */\nexport function clampWindow(\n window: Window,\n full: Window,\n least: number,\n units: Units = same,\n): Window | null {\n const f0 = units.to(full[0])\n const f1 = units.to(full[1])\n let a = units.to(Math.min(window[0], window[1]))\n let b = units.to(Math.max(window[0], window[1]))\n const span = f1 - f0\n if (!(span > 0) || a !== a || b !== b) return null\n const wanted = Math.min(span, Math.max(b - a, Math.min(least, span)))\n if (b - a < wanted) {\n const middle = (a + b) / 2\n a = middle - wanted / 2\n b = middle + wanted / 2\n }\n if (a < f0) [a, b] = [f0, f0 + (b - a)]\n if (b > f1) [a, b] = [f1 - (b - a), f1]\n a = Math.max(a, f0)\n // all of it: not zoomed\n if (b - a >= span * (1 - 1e-9)) return null\n return [units.from(a), units.from(b)]\n}\n\n/** The window `scale` shows with its range moved `by` px: dragging the plot by `-by`. */\nexport function panWindow(scale: Scale, by: number): Window {\n const [r0, r1] = scale.range\n return order(scale.invert(r0 + by), scale.invert(r1 + by))\n}\n\n/** The window `scale` shows zoomed by `factor` (below 1 is in) about the pixel `at`. */\nexport function zoomWindow(scale: Scale, at: number, factor: number): Window {\n const [r0, r1] = scale.range\n return order(scale.invert(at + (r0 - at) * factor), scale.invert(at + (r1 - at) * factor))\n}\n\nconst order = (a: number, b: number): Window => (a <= b ? [a, b] : [b, a])\n\n/** Whether `value` is at or between the ends of `window`. */\nexport const within = (value: number, window: Window) => value >= window[0] && value <= window[1]\n"],"mappings":"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"}
package/dist/define.js ADDED
@@ -0,0 +1,62 @@
1
+ import { useChartPart, useOwnNode } from "./context.js";
2
+ import { defineComponent, useModel } from "vue";
3
+ // src/define.ts
4
+ /** The props every series component takes. */
5
+ var seriesProps = {
6
+ y: {
7
+ type: [String, Function],
8
+ required: true
9
+ },
10
+ name: String,
11
+ data: [Array, Object],
12
+ x: [String, Function],
13
+ color: String,
14
+ tone: String,
15
+ axis: String,
16
+ stack: {
17
+ type: [String, Boolean],
18
+ default: void 0
19
+ },
20
+ /** Turned off in the legend (`v-model:hidden`). */
21
+ hidden: Boolean
22
+ };
23
+ /**
24
+ * Makes a series component of your own. It sits in a `DouChart` like the
25
+ * built-in ones and gets the same axes, stacking, legend and colors:
26
+ * describe how it widens the axes (`zero`, `band`, `inset`) and how it draws.
27
+ *
28
+ * ```ts
29
+ * const DouChartLollipop = defineChartSeries({
30
+ * type: 'lollipop',
31
+ * zero: true,
32
+ * props: { radius: { type: Number, default: 4 } },
33
+ * draw(painter, series, view) { … },
34
+ * })
35
+ * ```
36
+ */
37
+ function defineChartSeries(options) {
38
+ const { props: own, ...kind } = options;
39
+ const component = `DouChart${options.type[0].toUpperCase()}${options.type.slice(1)}`;
40
+ return defineComponent({
41
+ name: component,
42
+ props: {
43
+ ...seriesProps,
44
+ ...own
45
+ },
46
+ emits: ["update:hidden"],
47
+ setup(props) {
48
+ const el = useOwnNode();
49
+ const hidden = useModel(props, "hidden");
50
+ useChartPart(component, (chart) => chart.addSeries({
51
+ kind,
52
+ props,
53
+ el,
54
+ hidden
55
+ }));
56
+ return () => null;
57
+ }
58
+ });
59
+ }
60
+ export { defineChartSeries };
61
+
62
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","names":[],"sources":["../src/define.ts"],"sourcesContent":["import type { Tone } from 'dou-ui'\nimport {\n defineComponent,\n useModel,\n type ComponentObjectPropsOptions,\n type ExtractPropTypes,\n type PropType,\n} from 'vue'\nimport type { ChartAccessor, ChartData } from './core/data'\nimport type { ChartSeriesKind, ChartValueAxis } from './core/series'\nimport { useChartPart, useOwnNode } from './context'\n\n/** The props every series component takes. */\nconst seriesProps = {\n y: { type: [String, Function] as PropType<ChartAccessor>, required: true },\n name: String,\n data: [Array, Object] as PropType<ChartData>,\n x: [String, Function] as PropType<ChartAccessor>,\n color: String,\n tone: String as PropType<Tone>,\n axis: String as PropType<ChartValueAxis>,\n stack: { type: [String, Boolean] as PropType<string | boolean>, default: undefined },\n /** Turned off in the legend (`v-model:hidden`). */\n hidden: Boolean,\n} as const\n\nexport interface ChartSeriesOptions<Props extends ComponentObjectPropsOptions> extends Omit<\n ChartSeriesKind<ExtractPropTypes<Props>>,\n 'draw'\n> {\n /** Props of its own, declared as for any component; they reach `draw` on `series.props`. */\n props?: Props\n /**\n * Draws the series. `series` has its values read into columns (`x.values`,\n * `top`), `view` the scales; `view.point(x, value)` gives where a value lands. Draw only through\n * `painter`, and keep to the points on screen for large data.\n */\n draw: ChartSeriesKind<ExtractPropTypes<Props>>['draw']\n}\n\n/**\n * Makes a series component of your own. It sits in a `DouChart` like the\n * built-in ones and gets the same axes, stacking, legend and colors:\n * describe how it widens the axes (`zero`, `band`, `inset`) and how it draws.\n *\n * ```ts\n * const DouChartLollipop = defineChartSeries({\n * type: 'lollipop',\n * zero: true,\n * props: { radius: { type: Number, default: 4 } },\n * draw(painter, series, view) { … },\n * })\n * ```\n */\nexport function defineChartSeries<Props extends ComponentObjectPropsOptions = {}>(\n options: ChartSeriesOptions<Props>,\n) {\n const { props: own, ...kind } = options\n const component = `DouChart${options.type[0]!.toUpperCase()}${options.type.slice(1)}`\n return defineComponent({\n name: component,\n props: { ...seriesProps, ...(own as Props) },\n emits: ['update:hidden'],\n setup(props) {\n const el = useOwnNode()\n const hidden = useModel(props as { hidden: boolean }, 'hidden')\n useChartPart(component, (chart) =>\n chart.addSeries({ kind: kind as ChartSeriesKind<any>, props: props as never, el, hidden }),\n )\n return () => null\n },\n })\n}\n"],"mappings":";;;;AAaA,IAAM,cAAc;CAClB,GAAG;EAAE,MAAM,CAAC,QAAQ,QAAQ;EAA8B,UAAU;CAAK;CACzE,MAAM;CACN,MAAM,CAAC,OAAO,MAAM;CACpB,GAAG,CAAC,QAAQ,QAAQ;CACpB,OAAO;CACP,MAAM;CACN,MAAM;CACN,OAAO;EAAE,MAAM,CAAC,QAAQ,OAAO;EAAiC,SAAS,KAAA;CAAU;;CAEnF,QAAQ;AACV;;;;;;;;;;;;;;;AA8BA,SAAgB,kBACd,SACA;CACA,MAAM,EAAE,OAAO,KAAK,GAAG,SAAS;CAChC,MAAM,YAAY,WAAW,QAAQ,KAAK,EAAE,CAAE,YAAY,IAAI,QAAQ,KAAK,MAAM,CAAC;CAClF,OAAO,gBAAgB;EACrB,MAAM;EACN,OAAO;GAAE,GAAG;GAAa,GAAI;EAAc;EAC3C,OAAO,CAAC,eAAe;EACvB,MAAM,OAAO;GACX,MAAM,KAAK,WAAW;GACtB,MAAM,SAAS,SAAS,OAA8B,QAAQ;GAC9D,aAAa,YAAY,UACvB,MAAM,UAAU;IAAQ;IAAqC;IAAgB;IAAI;GAAO,CAAC,CAC3F;GACA,aAAa;EACf;CACF,CAAC;AACH"}
package/dist/index.js ADDED
@@ -0,0 +1,49 @@
1
+ import area_default from "./components/area.js";
2
+ import axis_default from "./components/axis.js";
3
+ import bar_default from "./components/bar.js";
4
+ import line_default from "./components/line.js";
5
+ import pie_default from "./components/pie.js";
6
+ import heatmap_default from "./components/heatmap.js";
7
+ import radar_default from "./components/radar.js";
8
+ import funnel_default from "./components/funnel.js";
9
+ import waterfall_default from "./components/waterfall.js";
10
+ import histogram_default from "./components/histogram.js";
11
+ import boxplot_default from "./components/boxplot.js";
12
+ import gauge_default from "./components/gauge.js";
13
+ import treemap_default from "./components/treemap.js";
14
+ import sunburst_default from "./components/sunburst.js";
15
+ import scatter_default from "./components/scatter.js";
16
+ import tooltip_default from "./components/tooltip.js";
17
+ import zoom_default from "./components/zoom.js";
18
+ import brush_default from "./components/brush.js";
19
+ import range_default from "./components/range.js";
20
+ import marker_default from "./components/marker.js";
21
+ import { chartLocales, useChartMessages } from "./locale.js";
22
+ import chart_default from "./chart.js";
23
+ import { defineChartSeries } from "./define.js";
24
+ import { withInstall } from "dou-ui";
25
+ // src/index.ts
26
+ var DouChart = withInstall(chart_default);
27
+ var DouChartAxis = withInstall(axis_default);
28
+ var DouChartLine = withInstall(line_default);
29
+ var DouChartArea = withInstall(area_default);
30
+ var DouChartBar = withInstall(bar_default);
31
+ var DouChartScatter = withInstall(scatter_default);
32
+ var DouChartPie = withInstall(pie_default);
33
+ var DouChartHeatmap = withInstall(heatmap_default);
34
+ var DouChartRadar = withInstall(radar_default);
35
+ var DouChartFunnel = withInstall(funnel_default);
36
+ var DouChartWaterfall = withInstall(waterfall_default);
37
+ var DouChartHistogram = withInstall(histogram_default);
38
+ var DouChartBoxplot = withInstall(boxplot_default);
39
+ var DouChartGauge = withInstall(gauge_default);
40
+ var DouChartTreemap = withInstall(treemap_default);
41
+ var DouChartSunburst = withInstall(sunburst_default);
42
+ var DouChartTooltip = withInstall(tooltip_default);
43
+ var DouChartZoom = withInstall(zoom_default);
44
+ var DouChartBrush = withInstall(brush_default);
45
+ var DouChartRange = withInstall(range_default);
46
+ var DouChartMarker = withInstall(marker_default);
47
+ export { DouChart, DouChart as default, DouChartArea, DouChartAxis, DouChartBar, DouChartBoxplot, DouChartBrush, DouChartFunnel, DouChartGauge, DouChartHeatmap, DouChartHistogram, DouChartLine, DouChartMarker, DouChartPie, DouChartRadar, DouChartRange, DouChartScatter, DouChartSunburst, DouChartTooltip, DouChartTreemap, DouChartWaterfall, DouChartZoom, chartLocales, defineChartSeries, useChartMessages };
48
+
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Chart","Axis","Line","Area","Bar","Scatter","Pie","Heatmap","Radar","Funnel","Waterfall","Histogram","Boxplot","Gauge","Treemap","Sunburst","Tooltip","Zoom","Brush","Range","Marker"],"sources":["../src/index.ts"],"sourcesContent":["import { withInstall } from 'dou-ui'\nimport Area from './components/area.vue'\nimport Axis from './components/axis.vue'\nimport Bar from './components/bar.vue'\nimport Line from './components/line.vue'\nimport Pie from './components/pie.vue'\nimport Heatmap from './components/heatmap.vue'\nimport Radar from './components/radar.vue'\nimport Funnel from './components/funnel.vue'\nimport Waterfall from './components/waterfall.vue'\nimport Histogram from './components/histogram.vue'\nimport Boxplot from './components/boxplot.vue'\nimport Gauge from './components/gauge.vue'\nimport Treemap from './components/treemap.vue'\nimport Sunburst from './components/sunburst.vue'\nimport Scatter from './components/scatter.vue'\nimport Tooltip from './components/tooltip.vue'\nimport Zoom from './components/zoom.vue'\nimport Brush from './components/brush.vue'\nimport Range from './components/range.vue'\nimport Marker from './components/marker.vue'\nimport Chart from './chart.vue'\n\nexport const DouChart = withInstall(Chart)\nexport const DouChartAxis = withInstall<typeof Axis, {}>(Axis)\nexport const DouChartLine = withInstall<typeof Line, {}>(Line)\nexport const DouChartArea = withInstall<typeof Area, {}>(Area)\nexport const DouChartBar = withInstall<typeof Bar, {}>(Bar)\nexport const DouChartScatter = withInstall<typeof Scatter, {}>(Scatter)\nexport const DouChartPie = withInstall<typeof Pie, {}>(Pie)\nexport const DouChartHeatmap = withInstall<typeof Heatmap, {}>(Heatmap)\nexport const DouChartRadar = withInstall<typeof Radar, {}>(Radar)\nexport const DouChartFunnel = withInstall<typeof Funnel, {}>(Funnel)\nexport const DouChartWaterfall = withInstall<typeof Waterfall, {}>(Waterfall)\nexport const DouChartHistogram = withInstall<typeof Histogram, {}>(Histogram)\nexport const DouChartBoxplot = withInstall<typeof Boxplot, {}>(Boxplot)\nexport const DouChartGauge = withInstall<typeof Gauge, {}>(Gauge)\nexport const DouChartTreemap = withInstall<typeof Treemap, {}>(Treemap)\nexport const DouChartSunburst = withInstall<typeof Sunburst, {}>(Sunburst)\nexport const DouChartTooltip = withInstall<typeof Tooltip, {}>(Tooltip)\nexport const DouChartZoom = withInstall<typeof Zoom, {}>(Zoom)\nexport const DouChartBrush = withInstall<typeof Brush, {}>(Brush)\nexport const DouChartRange = withInstall<typeof Range, {}>(Range)\nexport const DouChartMarker = withInstall<typeof Marker, {}>(Marker)\nexport default DouChart\n\nexport { defineChartSeries } from './define'\nexport type { ChartSeriesOptions } from './define'\nexport type {\n ChartAreaProps,\n ChartAxisProps,\n ChartBarProps,\n ChartBoxplotProps,\n ChartItemColor,\n ChartDataLabel,\n ChartLabelFormat,\n ChartBrushEvent,\n ChartBrushProps,\n ChartExportOptions,\n ChartEmits,\n ChartExpose,\n ChartFunnelProps,\n ChartGaugeProps,\n ChartGaugeSlots,\n ChartHeatmapProps,\n ChartHistogramProps,\n ChartImageOptions,\n ChartInterval,\n ChartLineProps,\n ChartMarkerProps,\n ChartPieProps,\n ChartPieSlots,\n ChartPointEvent,\n ChartRadarProps,\n ChartProps,\n ChartScatterProps,\n ChartSunburstProps,\n ChartSunburstSlots,\n ChartSlots,\n ChartTooltipItem,\n ChartTooltipProps,\n ChartTooltipSlots,\n ChartTreeProps,\n ChartTreemapProps,\n ChartWaterfallProps,\n ChartZoomAxis,\n ChartZoomProps,\n} from './types'\nexport type {\n ChartAccessor,\n ChartColumns,\n ChartData,\n ChartRow,\n XColumn as ChartXColumn,\n} from './core/data'\nexport type {\n ChartAxisRole,\n ChartAxisType,\n ChartLegendPlacement,\n ChartTickValue,\n} from './core/layout'\nexport type { ChartCategorySort } from './core/model'\nexport type { ChartPattern } from './core/pattern'\nexport type { Painter as ChartPainter, Rect as ChartRect } from './core/painter'\nexport type { Scale as ChartScale } from './core/scale'\nexport type {\n ChartColors,\n ChartHit,\n ChartSeries,\n ChartSeriesKind,\n ChartSeriesProps,\n ChartValueAxis,\n ChartView,\n} from './core/series'\nexport { chartLocales, useChartMessages } from './locale'\nexport type { ChartMessages, ChartMessagesOverride } from './locale'\n\ndeclare module 'vue' {\n export interface GlobalComponents {\n DouChart: typeof DouChart\n DouChartAxis: typeof DouChartAxis\n DouChartLine: typeof DouChartLine\n DouChartArea: typeof DouChartArea\n DouChartBar: typeof DouChartBar\n DouChartScatter: typeof DouChartScatter\n DouChartHeatmap: typeof DouChartHeatmap\n DouChartRadar: typeof DouChartRadar\n DouChartFunnel: typeof DouChartFunnel\n DouChartWaterfall: typeof DouChartWaterfall\n DouChartHistogram: typeof DouChartHistogram\n DouChartBoxplot: typeof DouChartBoxplot\n DouChartGauge: typeof DouChartGauge\n DouChartTreemap: typeof DouChartTreemap\n DouChartSunburst: typeof DouChartSunburst\n DouChartPie: typeof DouChartPie\n DouChartTooltip: typeof DouChartTooltip\n DouChartZoom: typeof DouChartZoom\n DouChartBrush: typeof DouChartBrush\n DouChartRange: typeof DouChartRange\n DouChartMarker: typeof DouChartMarker\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAa,WAAW,YAAYA,aAAK;AACzC,IAAa,eAAe,YAA6BC,YAAI;AAC7D,IAAa,eAAe,YAA6BC,YAAI;AAC7D,IAAa,eAAe,YAA6BC,YAAI;AAC7D,IAAa,cAAc,YAA4BC,WAAG;AAC1D,IAAa,kBAAkB,YAAgCC,eAAO;AACtE,IAAa,cAAc,YAA4BC,WAAG;AAC1D,IAAa,kBAAkB,YAAgCC,eAAO;AACtE,IAAa,gBAAgB,YAA8BC,aAAK;AAChE,IAAa,iBAAiB,YAA+BC,cAAM;AACnE,IAAa,oBAAoB,YAAkCC,iBAAS;AAC5E,IAAa,oBAAoB,YAAkCC,iBAAS;AAC5E,IAAa,kBAAkB,YAAgCC,eAAO;AACtE,IAAa,gBAAgB,YAA8BC,aAAK;AAChE,IAAa,kBAAkB,YAAgCC,eAAO;AACtE,IAAa,mBAAmB,YAAiCC,gBAAQ;AACzE,IAAa,kBAAkB,YAAgCC,eAAO;AACtE,IAAa,eAAe,YAA6BC,YAAI;AAC7D,IAAa,gBAAgB,YAA8BC,aAAK;AAChE,IAAa,gBAAgB,YAA8BC,aAAK;AAChE,IAAa,iBAAiB,YAA+BC,cAAM"}
package/dist/locale.js ADDED
@@ -0,0 +1,170 @@
1
+ import { useLocale } from "dou-ui";
2
+ import { computed, toValue } from "vue";
3
+ // src/locale.ts
4
+ var zhCN = {
5
+ chart: "图表",
6
+ series: "{name}:{count} 个数据点,最小 {min},最大 {max}",
7
+ seriesEmpty: "{name}:没有数据",
8
+ heatmap: "{name}:{rows} 行 {columns} 列,最小 {min},最大 {max}({at})",
9
+ slice: "{label} {value}({share})",
10
+ pie: "{name}:{slices}",
11
+ listSeparator: ";",
12
+ itemSeparator: ",",
13
+ share: "{value}({share})",
14
+ band: "{from} ~ {to}",
15
+ waterfallStep: "{change},累计 {total}",
16
+ boxHigh: "上限",
17
+ boxQ3: "上四分位",
18
+ boxMedian: "中位数",
19
+ boxQ1: "下四分位",
20
+ boxLow: "下限",
21
+ boxOutliers: "异常值 {count} 个",
22
+ boxSeries: "{name}:{count} 组,最小 {min},最大 {max}",
23
+ binsSeries: "{name}:{count} 个区间,最少 {min},最多 {max}",
24
+ gauge: "{name} {value},范围 {min} ~ {max}",
25
+ gaugeValue: "{value},范围 {min} ~ {max}",
26
+ box: "中位数 {median},四分位 {q1} ~ {q3},范围 {low} ~ {high}",
27
+ legendHint: "按 Alt+Enter 或按住 Alt 点击只显示这一项,再按一次恢复全部",
28
+ hiddenSlices: "已隐藏 {count} 项,占比只按显示的部分计算",
29
+ keys: "{summary}。用方向键逐个查看数据",
30
+ zoomKeys: "{summary}。用方向键逐个查看数据,加号和减号缩放,0 复位",
31
+ zoomed: "显示 {from} 至 {to}",
32
+ zoomReset: "显示全部",
33
+ rangeStart: "区间起点",
34
+ rangeEnd: "区间终点",
35
+ range: "{chart},横轴从 {from} 到 {to}",
36
+ rangeDown: "{chart},纵轴从 {from} 到 {to}",
37
+ summary: "{chart}。{series}",
38
+ empty: "没有数据",
39
+ table: "图表数据",
40
+ tableOf: "{names}的数据",
41
+ nameSeparator: "、",
42
+ tableSeries: "系列",
43
+ tableValue: "值",
44
+ tableShare: "占比",
45
+ tableNode: "节点",
46
+ count: "数量",
47
+ stageRate: "转化率",
48
+ totalRate: "总转化率",
49
+ tableMore: "只显示前 {shown} 行,共 {count} 行"
50
+ };
51
+ var zhTW = {
52
+ chart: "圖表",
53
+ series: "{name}:{count} 個資料點,最小 {min},最大 {max}",
54
+ seriesEmpty: "{name}:沒有資料",
55
+ heatmap: "{name}:{rows} 行 {columns} 列,最小 {min},最大 {max}({at})",
56
+ slice: "{label} {value}({share})",
57
+ pie: "{name}:{slices}",
58
+ listSeparator: ";",
59
+ itemSeparator: ",",
60
+ share: "{value}({share})",
61
+ band: "{from} ~ {to}",
62
+ waterfallStep: "{change},累計 {total}",
63
+ boxHigh: "上限",
64
+ boxQ3: "上四分位",
65
+ boxMedian: "中位數",
66
+ boxQ1: "下四分位",
67
+ boxLow: "下限",
68
+ boxOutliers: "異常值 {count} 個",
69
+ boxSeries: "{name}:{count} 組,最小 {min},最大 {max}",
70
+ binsSeries: "{name}:{count} 個區間,最少 {min},最多 {max}",
71
+ gauge: "{name} {value},範圍 {min} ~ {max}",
72
+ gaugeValue: "{value},範圍 {min} ~ {max}",
73
+ box: "中位數 {median},四分位 {q1} ~ {q3},範圍 {low} ~ {high}",
74
+ legendHint: "按 Alt+Enter 或按住 Alt 點擊只顯示這一項,再按一次恢復全部",
75
+ hiddenSlices: "已隱藏 {count} 項,占比只按顯示的部分計算",
76
+ keys: "{summary}。用方向鍵逐個查看資料",
77
+ zoomKeys: "{summary}。用方向鍵逐個查看資料,加號和減號縮放,0 復位",
78
+ zoomed: "顯示 {from} 至 {to}",
79
+ zoomReset: "顯示全部",
80
+ rangeStart: "區間起點",
81
+ rangeEnd: "區間終點",
82
+ range: "{chart},橫軸從 {from} 到 {to}",
83
+ rangeDown: "{chart},縱軸從 {from} 到 {to}",
84
+ summary: "{chart}。{series}",
85
+ empty: "沒有資料",
86
+ table: "圖表資料",
87
+ tableOf: "{names}的資料",
88
+ nameSeparator: "、",
89
+ tableSeries: "系列",
90
+ tableValue: "值",
91
+ tableShare: "佔比",
92
+ tableNode: "節點",
93
+ count: "數量",
94
+ stageRate: "轉化率",
95
+ totalRate: "總轉化率",
96
+ tableMore: "只顯示前 {shown} 列,共 {count} 列"
97
+ };
98
+ var en = {
99
+ chart: "Chart",
100
+ series: "{name}: {count} points, from {min} to {max}",
101
+ seriesEmpty: "{name}: no data",
102
+ heatmap: "{name}: {rows} rows, {columns} columns, from {min} to {max} ({at})",
103
+ slice: "{label} {value} ({share})",
104
+ pie: "{name}: {slices}",
105
+ listSeparator: "; ",
106
+ itemSeparator: ", ",
107
+ share: "{value} ({share})",
108
+ band: "{from} – {to}",
109
+ waterfallStep: "{change}, total {total}",
110
+ boxHigh: "Upper whisker",
111
+ boxQ3: "Upper quartile",
112
+ boxMedian: "Median",
113
+ boxQ1: "Lower quartile",
114
+ boxLow: "Lower whisker",
115
+ boxOutliers: "{count} outliers",
116
+ boxSeries: "{name}: {count} groups, min {min}, max {max}",
117
+ binsSeries: "{name}: {count} bins, fewest {min}, most {max}",
118
+ gauge: "{name} {value}, range {min} – {max}",
119
+ gaugeValue: "{value}, range {min} – {max}",
120
+ box: "median {median}, quartiles {q1} – {q3}, range {low} – {high}",
121
+ legendHint: "Alt+Enter or Alt+click shows only this one; again shows all",
122
+ hiddenSlices: "{count} hidden; shares are of the slices shown",
123
+ keys: "{summary}. Use the arrow keys to read each point",
124
+ zoomKeys: "{summary}. Use the arrow keys to read each point, plus and minus to zoom, 0 to reset",
125
+ zoomed: "Showing {from} to {to}",
126
+ zoomReset: "Showing all",
127
+ rangeStart: "Range start",
128
+ rangeEnd: "Range end",
129
+ range: "{chart}, x from {from} to {to}",
130
+ rangeDown: "{chart}, x from {from} to {to}",
131
+ summary: "{chart}. {series}",
132
+ empty: "No data",
133
+ table: "Chart data",
134
+ tableOf: "Data of {names}",
135
+ nameSeparator: ", ",
136
+ tableSeries: "Series",
137
+ tableValue: "Value",
138
+ tableShare: "Share",
139
+ tableNode: "Node",
140
+ count: "Count",
141
+ stageRate: "Conversion",
142
+ totalRate: "Overall",
143
+ tableMore: "Showing the first {shown} of {count} rows"
144
+ };
145
+ var chartLocales = {
146
+ "zh-CN": zhCN,
147
+ "zh-TW": zhTW,
148
+ en
149
+ };
150
+ /**
151
+ * The chart's texts, picked by the name of DouUI's current locale.
152
+ * Pass `messages` to override any of them.
153
+ */
154
+ function useChartMessages(override) {
155
+ const { locale } = useLocale();
156
+ return computed(() => {
157
+ const name = locale.value.name;
158
+ const base = chartLocales[name] ?? chartLocales[name.split("-")[0]] ?? (name.startsWith("zh") ? zhCN : en);
159
+ const extra = toValue(override);
160
+ return extra ? {
161
+ ...base,
162
+ ...extra
163
+ } : base;
164
+ });
165
+ }
166
+ /** Fills `{name}` placeholders. */
167
+ var format = (text, params) => text.replace(/\{(\w+)\}/g, (match, key) => String(params[key] ?? match));
168
+ export { chartLocales, format, useChartMessages };
169
+
170
+ //# sourceMappingURL=locale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locale.js","names":[],"sources":["../src/locale.ts"],"sourcesContent":["import { useLocale } from 'dou-ui'\nimport { computed, toValue, type MaybeRefOrGetter } from 'vue'\n\nexport interface ChartMessages {\n /** The chart's accessible name when it has no `description`. */\n chart: string\n /** Read out for each series: `{name}`, `{count}` points, from `{min}` to `{max}`. */\n series: string\n /** Read out for a series without points: `{name}`. */\n seriesEmpty: string\n /**\n * Read out for a heatmap: `{name}`, `{rows}` rows and `{columns}` columns, the\n * smallest `{min}` and largest `{max}` value and where it is, `{at}`.\n */\n heatmap: string\n /** Read out for a slice of a pie: `{label}`, `{value}`, `{share}` (a percentage). */\n slice: string\n /** Read out for a pie with a `name`: `{name}`, `{slices}`. */\n pie: string\n /** Joins the series in the summary. */\n listSeparator: string\n /** Joins what is read out for one x or point. */\n itemSeparator: string\n /** A slice's value in its tooltip: `{value}`, `{share}` (a percentage). */\n share: string\n /** A band's two ends in its tooltip: `{from}`, `{to}`. */\n band: string\n /** A waterfall's change and the running total after it: `{change}`, `{total}`. */\n waterfallStep: string\n /** A box plot's numbers, in its tooltip: its top and bottom whisker, quartiles and median. */\n boxHigh: string\n boxQ3: string\n boxMedian: string\n boxQ1: string\n boxLow: string\n /** The values past a box plot's whiskers: `{count}`. */\n boxOutliers: string\n /** A box plot in the summary: `{name}`, `{count}` (its groups), `{min}`, `{max}`. */\n boxSeries: string\n /** A histogram in the summary: `{name}`, `{count}` (its bins), `{min}`, `{max}` (counts). */\n binsSeries: string\n /** A gauge, read out: `{name}`, `{value}`, `{min}`, `{max}`. */\n gauge: string\n /** The same, for a gauge without a name. */\n gaugeValue: string\n /** A box plot's numbers in one line, read out and in the table: `{median}`, `{q1}`, `{q3}`, `{low}`, `{high}`. */\n box: string\n /** Read out with each legend entry: how to show it alone. */\n legendHint: string\n /** Under a pie with slices turned off: `{count}`. */\n hiddenSlices: string\n /** The summary of a chart that can be explored with the keys: `{summary}`. */\n keys: string\n /** The same, for a chart that can also be zoomed: `{summary}`. */\n zoomKeys: string\n /** Read out after zooming with the keys: `{from}`, `{to}`. */\n zoomed: string\n /** Read out after going back to the whole chart. */\n zoomReset: string\n /** The range strip's handles. */\n rangeStart: string\n rangeEnd: string\n /** The chart with the range of its x axis: `{chart}`, `{from}`, `{to}`. */\n range: string\n /** The same, for a `horizontal` chart, whose x axis runs down the side. */\n rangeDown: string\n /** The summary: `{chart}` (with its range) and `{series}` (the series joined). */\n summary: string\n /** Shown, and read out, when no series has a value. */\n empty: string\n /** The table view's caption when the chart has no `aria-label` nor named series. */\n table: string\n /** The table view's caption from its series' names: `{names}`. */\n tableOf: string\n /** Joins the series' names in the table's caption. */\n nameSeparator: string\n /** The table view's head over the series' names, for a scatter's points. */\n tableSeries: string\n /** The table view's head over the values, for a scatter's points and a pie. */\n tableValue: string\n /** The table view's head over a pie's shares. */\n tableShare: string\n /** The table view's head over a tree's nodes. */\n tableNode: string\n /** What a histogram counts, when it has no `name`. */\n count: string\n /** A funnel stage's share of the stage before it, in its tooltip, table and summary. */\n stageRate: string\n /** A funnel stage's share of the first stage. */\n totalRate: string\n /** Under a table cut short: `{shown}` rows of `{count}`. */\n tableMore: string\n}\n\nconst zhCN: ChartMessages = {\n chart: '图表',\n series: '{name}:{count} 个数据点,最小 {min},最大 {max}',\n seriesEmpty: '{name}:没有数据',\n heatmap: '{name}:{rows} 行 {columns} 列,最小 {min},最大 {max}({at})',\n slice: '{label} {value}({share})',\n pie: '{name}:{slices}',\n listSeparator: ';',\n itemSeparator: ',',\n share: '{value}({share})',\n band: '{from} ~ {to}',\n waterfallStep: '{change},累计 {total}',\n boxHigh: '上限',\n boxQ3: '上四分位',\n boxMedian: '中位数',\n boxQ1: '下四分位',\n boxLow: '下限',\n boxOutliers: '异常值 {count} 个',\n boxSeries: '{name}:{count} 组,最小 {min},最大 {max}',\n binsSeries: '{name}:{count} 个区间,最少 {min},最多 {max}',\n gauge: '{name} {value},范围 {min} ~ {max}',\n gaugeValue: '{value},范围 {min} ~ {max}',\n box: '中位数 {median},四分位 {q1} ~ {q3},范围 {low} ~ {high}',\n legendHint: '按 Alt+Enter 或按住 Alt 点击只显示这一项,再按一次恢复全部',\n hiddenSlices: '已隐藏 {count} 项,占比只按显示的部分计算',\n keys: '{summary}。用方向键逐个查看数据',\n zoomKeys: '{summary}。用方向键逐个查看数据,加号和减号缩放,0 复位',\n zoomed: '显示 {from} 至 {to}',\n zoomReset: '显示全部',\n rangeStart: '区间起点',\n rangeEnd: '区间终点',\n range: '{chart},横轴从 {from} 到 {to}',\n rangeDown: '{chart},纵轴从 {from} 到 {to}',\n summary: '{chart}。{series}',\n empty: '没有数据',\n table: '图表数据',\n tableOf: '{names}的数据',\n nameSeparator: '、',\n tableSeries: '系列',\n tableValue: '值',\n tableShare: '占比',\n tableNode: '节点',\n count: '数量',\n stageRate: '转化率',\n totalRate: '总转化率',\n tableMore: '只显示前 {shown} 行,共 {count} 行',\n}\n\nconst zhTW: ChartMessages = {\n chart: '圖表',\n series: '{name}:{count} 個資料點,最小 {min},最大 {max}',\n seriesEmpty: '{name}:沒有資料',\n heatmap: '{name}:{rows} 行 {columns} 列,最小 {min},最大 {max}({at})',\n slice: '{label} {value}({share})',\n pie: '{name}:{slices}',\n listSeparator: ';',\n itemSeparator: ',',\n share: '{value}({share})',\n band: '{from} ~ {to}',\n waterfallStep: '{change},累計 {total}',\n boxHigh: '上限',\n boxQ3: '上四分位',\n boxMedian: '中位數',\n boxQ1: '下四分位',\n boxLow: '下限',\n boxOutliers: '異常值 {count} 個',\n boxSeries: '{name}:{count} 組,最小 {min},最大 {max}',\n binsSeries: '{name}:{count} 個區間,最少 {min},最多 {max}',\n gauge: '{name} {value},範圍 {min} ~ {max}',\n gaugeValue: '{value},範圍 {min} ~ {max}',\n box: '中位數 {median},四分位 {q1} ~ {q3},範圍 {low} ~ {high}',\n legendHint: '按 Alt+Enter 或按住 Alt 點擊只顯示這一項,再按一次恢復全部',\n hiddenSlices: '已隱藏 {count} 項,占比只按顯示的部分計算',\n keys: '{summary}。用方向鍵逐個查看資料',\n zoomKeys: '{summary}。用方向鍵逐個查看資料,加號和減號縮放,0 復位',\n zoomed: '顯示 {from} 至 {to}',\n zoomReset: '顯示全部',\n rangeStart: '區間起點',\n rangeEnd: '區間終點',\n range: '{chart},橫軸從 {from} 到 {to}',\n rangeDown: '{chart},縱軸從 {from} 到 {to}',\n summary: '{chart}。{series}',\n empty: '沒有資料',\n table: '圖表資料',\n tableOf: '{names}的資料',\n nameSeparator: '、',\n tableSeries: '系列',\n tableValue: '值',\n tableShare: '佔比',\n tableNode: '節點',\n count: '數量',\n stageRate: '轉化率',\n totalRate: '總轉化率',\n tableMore: '只顯示前 {shown} 列,共 {count} 列',\n}\n\nconst en: ChartMessages = {\n chart: 'Chart',\n series: '{name}: {count} points, from {min} to {max}',\n seriesEmpty: '{name}: no data',\n heatmap: '{name}: {rows} rows, {columns} columns, from {min} to {max} ({at})',\n slice: '{label} {value} ({share})',\n pie: '{name}: {slices}',\n listSeparator: '; ',\n itemSeparator: ', ',\n share: '{value} ({share})',\n band: '{from} – {to}',\n waterfallStep: '{change}, total {total}',\n boxHigh: 'Upper whisker',\n boxQ3: 'Upper quartile',\n boxMedian: 'Median',\n boxQ1: 'Lower quartile',\n boxLow: 'Lower whisker',\n boxOutliers: '{count} outliers',\n boxSeries: '{name}: {count} groups, min {min}, max {max}',\n binsSeries: '{name}: {count} bins, fewest {min}, most {max}',\n gauge: '{name} {value}, range {min} – {max}',\n gaugeValue: '{value}, range {min} – {max}',\n box: 'median {median}, quartiles {q1} – {q3}, range {low} – {high}',\n legendHint: 'Alt+Enter or Alt+click shows only this one; again shows all',\n hiddenSlices: '{count} hidden; shares are of the slices shown',\n keys: '{summary}. Use the arrow keys to read each point',\n zoomKeys: '{summary}. Use the arrow keys to read each point, plus and minus to zoom, 0 to reset',\n zoomed: 'Showing {from} to {to}',\n zoomReset: 'Showing all',\n rangeStart: 'Range start',\n rangeEnd: 'Range end',\n range: '{chart}, x from {from} to {to}',\n rangeDown: '{chart}, x from {from} to {to}',\n summary: '{chart}. {series}',\n empty: 'No data',\n table: 'Chart data',\n tableOf: 'Data of {names}',\n nameSeparator: ', ',\n tableSeries: 'Series',\n tableValue: 'Value',\n tableShare: 'Share',\n tableNode: 'Node',\n count: 'Count',\n stageRate: 'Conversion',\n totalRate: 'Overall',\n tableMore: 'Showing the first {shown} of {count} rows',\n}\n\nexport const chartLocales: Record<string, ChartMessages> = {\n 'zh-CN': zhCN,\n 'zh-TW': zhTW,\n en,\n}\n\nexport type ChartMessagesOverride = Partial<ChartMessages>\n\n/**\n * The chart's texts, picked by the name of DouUI's current locale.\n * Pass `messages` to override any of them.\n */\nexport function useChartMessages(override?: MaybeRefOrGetter<ChartMessagesOverride | undefined>) {\n const { locale } = useLocale()\n return computed<ChartMessages>(() => {\n const name = locale.value.name\n const base =\n chartLocales[name] ?? chartLocales[name.split('-')[0]!] ?? (name.startsWith('zh') ? zhCN : en)\n const extra = toValue(override)\n return extra ? { ...base, ...extra } : base\n })\n}\n\n/** Fills `{name}` placeholders. */\nexport const format = (text: string, params: Record<string, string | number>) =>\n text.replace(/\\{(\\w+)\\}/g, (match, key: string) => String(params[key] ?? match))\n"],"mappings":";;;AA8FA,IAAM,OAAsB;CAC1B,OAAO;CACP,QAAQ;CACR,aAAa;CACb,SAAS;CACT,OAAO;CACP,KAAK;CACL,eAAe;CACf,eAAe;CACf,OAAO;CACP,MAAM;CACN,eAAe;CACf,SAAS;CACT,OAAO;CACP,WAAW;CACX,OAAO;CACP,QAAQ;CACR,aAAa;CACb,WAAW;CACX,YAAY;CACZ,OAAO;CACP,YAAY;CACZ,KAAK;CACL,YAAY;CACZ,cAAc;CACd,MAAM;CACN,UAAU;CACV,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,UAAU;CACV,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,OAAO;CACP,SAAS;CACT,eAAe;CACf,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,OAAO;CACP,WAAW;CACX,WAAW;CACX,WAAW;AACb;AAEA,IAAM,OAAsB;CAC1B,OAAO;CACP,QAAQ;CACR,aAAa;CACb,SAAS;CACT,OAAO;CACP,KAAK;CACL,eAAe;CACf,eAAe;CACf,OAAO;CACP,MAAM;CACN,eAAe;CACf,SAAS;CACT,OAAO;CACP,WAAW;CACX,OAAO;CACP,QAAQ;CACR,aAAa;CACb,WAAW;CACX,YAAY;CACZ,OAAO;CACP,YAAY;CACZ,KAAK;CACL,YAAY;CACZ,cAAc;CACd,MAAM;CACN,UAAU;CACV,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,UAAU;CACV,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,OAAO;CACP,SAAS;CACT,eAAe;CACf,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,OAAO;CACP,WAAW;CACX,WAAW;CACX,WAAW;AACb;AAEA,IAAM,KAAoB;CACxB,OAAO;CACP,QAAQ;CACR,aAAa;CACb,SAAS;CACT,OAAO;CACP,KAAK;CACL,eAAe;CACf,eAAe;CACf,OAAO;CACP,MAAM;CACN,eAAe;CACf,SAAS;CACT,OAAO;CACP,WAAW;CACX,OAAO;CACP,QAAQ;CACR,aAAa;CACb,WAAW;CACX,YAAY;CACZ,OAAO;CACP,YAAY;CACZ,KAAK;CACL,YAAY;CACZ,cAAc;CACd,MAAM;CACN,UAAU;CACV,QAAQ;CACR,WAAW;CACX,YAAY;CACZ,UAAU;CACV,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,OAAO;CACP,SAAS;CACT,eAAe;CACf,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,OAAO;CACP,WAAW;CACX,WAAW;CACX,WAAW;AACb;AAEA,IAAa,eAA8C;CACzD,SAAS;CACT,SAAS;CACT;AACF;;;;;AAQA,SAAgB,iBAAiB,UAAgE;CAC/F,MAAM,EAAE,WAAW,UAAU;CAC7B,OAAO,eAA8B;EACnC,MAAM,OAAO,OAAO,MAAM;EAC1B,MAAM,OACJ,aAAa,SAAS,aAAa,KAAK,MAAM,GAAG,CAAC,CAAC,QAAS,KAAK,WAAW,IAAI,IAAI,OAAO;EAC7F,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,OAAO,QAAQ;GAAE,GAAG;GAAM,GAAG;EAAM,IAAI;CACzC,CAAC;AACH;;AAGA,IAAa,UAAU,MAAc,WACnC,KAAK,QAAQ,eAAe,OAAO,QAAgB,OAAO,OAAO,QAAQ,KAAK,CAAC"}
@@ -0,0 +1,6 @@
1
+ import overlay_vue_vue_type_script_setup_true_lang_default from "./overlay.vue_vue_type_script_setup_true_lang.js";
2
+ // src/overlay.vue
3
+ var overlay_default = overlay_vue_vue_type_script_setup_true_lang_default;
4
+ export { overlay_default as default };
5
+
6
+ //# sourceMappingURL=overlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"overlay.js","names":["_sfc_main"],"sources":["../src/overlay.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouSpinner, DouTooltip, useNamespace, type Tone } from 'dou-ui'\nimport { onBeforeUnmount, useId, type ComputedRef, type VNodeChild } from 'vue'\nimport type { TickLabel } from './core/layout'\nimport type { PlacedDataLabel } from './core/labels'\nimport type { LegendBox } from './core/layout'\nimport type { MarkerLabel } from './core/marker'\n\n/**\n * The text over the canvas: tick labels, titles, the legend and what goes\n * in a donut's hole. Kept apart from the chart, so laying it out again\n * doesn't render the chart's slot again: a part written with a new\n * function each render (`:format=\"(v) => …\"`) would otherwise be laid out\n * again and again.\n */\nexport interface OverlayState {\n shown: ComputedRef<boolean>\n labels: ComputedRef<Array<TickLabel & { key: string; axis: string }>>\n titles: ComputedRef<\n Array<{ key: string; text: string; left: number; top: number; align: 'start' | 'end' }>\n >\n legend: ComputedRef<\n Array<{\n index: number\n text: string\n left: number\n top: number\n color: string\n kind: string\n dashed: boolean\n /** Turned off. */\n off: boolean\n /** The last one shown: it can't be turned off. */\n locked: boolean\n /** The room it takes, swatch and name, in px. */\n width: number\n /** Its name is cut short to the room down the side. */\n clipped?: boolean\n /** A heatmap's scale: its colors, least to most, in a swatch `swatch` px wide. */\n scale?: string[]\n swatch?: number\n /** The pattern over its color, as a CSS background image and its size. */\n pattern?: { image: string; size?: string }\n }>\n >\n /** Where the legend shows; its entries scroll in it when they don't all fit. */\n legendBox: ComputedRef<LegendBox | undefined>\n /** Turns the series (or slice) at `index` on or off. */\n toggle: (index: number) => void\n /** Shows only the series (or slice) at `index`, or all again. */\n isolate: (index: number) => void\n /** How to show one entry alone, read out with each entry. */\n hint: ComputedRef<string>\n /** Brings the series at `index` forward while the pointer or focus is on its entry; `null` to stop. */\n focus: (index: number | null) => void\n /** Where the donut's hole is, if there is one to fill. */\n hole: ComputedRef<{ left: number; top: number; width: number; above?: boolean } | null>\n center: () => VNodeChild\n /** The markers' labels. */\n markers: ComputedRef<Array<MarkerLabel & { key: string; tone: Tone; backdrop: boolean }>>\n /** Data labels: values by the points and on the bars; `ink` is their color, when not the default. */\n data: ComputedRef<Array<PlacedDataLabel & { ink?: string; width?: number }>>\n /** Whether the data labels show (not while the series come in). */\n dataShown: ComputedRef<boolean>\n /** The series brought forward: the other series' labels are faded too. */\n dataFocus: ComputedRef<number | null>\n /** No series has a value: the empty message shows. */\n empty: ComputedRef<boolean>\n emptyContent: () => VNodeChild\n loading: ComputedRef<boolean>\n}\n\ndefineOptions({ name: 'DouChartOverlay' })\n\nconst { state } = defineProps<{ state: OverlayState }>()\nconst ns = useNamespace('chart')\nconst {\n shown,\n labels,\n titles,\n legend,\n legendBox,\n hole,\n toggle,\n isolate,\n hint,\n focus,\n markers,\n data,\n dataShown,\n dataFocus,\n empty,\n loading,\n} = state\nconst Center = () => state.center()\nconst hintId = useId()\n\n/* the legend: a click turns an entry on or off; with Alt, or held down on a touch screen, it shows only that one */\n\n/** How long a finger stays on an entry to show only it, in ms. */\nconst HOLD = 500\nlet holdTimer: ReturnType<typeof setTimeout> | undefined\n/** A hold just showed one entry alone: the click that ends it isn't a toggle. */\nlet held = false\n\nfunction holdLegend(index: number) {\n letGo()\n held = false\n holdTimer = setTimeout(() => {\n holdTimer = undefined\n held = true\n isolate(index)\n }, HOLD)\n}\n\nfunction letGo() {\n if (holdTimer) clearTimeout(holdTimer)\n holdTimer = undefined\n}\n\nfunction onLegendClick(event: MouseEvent, index: number) {\n if (held) {\n held = false\n return\n }\n if (event.altKey) isolate(index)\n else toggle(index)\n}\n\nfunction onLegendKey(event: KeyboardEvent, index: number) {\n if (!event.altKey || (event.key !== 'Enter' && event.key !== ' ')) return\n event.preventDefault()\n isolate(index)\n}\n/** No callout menu over an entry while it is held down. */\nfunction noMenu(event: Event) {\n if (holdTimer || held) event.preventDefault()\n}\nonBeforeUnmount(letGo)\n/** Room around the legend's entries in its box, so a focus ring isn't cut off where it scrolls. */\nconst LEGEND_PAD = 4\nconst Empty = () => state.emptyContent()\n// a click focuses the entry too: only keyboard focus brings its series forward\nconst focusVisible = (e: FocusEvent) => (e.target as Element).matches(':focus-visible')\n</script>\n\n<template>\n <div v-if=\"shown\" :class=\"ns.e('labels')\" aria-hidden=\"true\">\n <span\n v-for=\"tick in labels\"\n :key=\"tick.key\"\n :class=\"[ns.e('tick'), ns.is(tick.axis), ns.is('clipped', !!tick.clipped)]\"\n :style=\"{\n transform: `translate(${tick.left}px, ${tick.top}px)`,\n width: tick.clipped ? `${tick.width}px` : undefined,\n }\"\n ><span :class=\"ns.e('text')\">{{ tick.text }}</span></span\n >\n <span\n v-for=\"title in titles\"\n :key=\"title.key\"\n :class=\"[ns.e('title'), ns.is('end', title.align === 'end')]\"\n :style=\"{ transform: `translate(${title.left}px, ${title.top}px)` }\"\n ><span :class=\"ns.e('text')\">{{ title.text }}</span></span\n >\n <span\n v-for=\"marker in markers\"\n :key=\"marker.key\"\n :class=\"[\n ns.e('marker'),\n ns.is(marker.tone),\n ns.is(marker.align),\n ns.is('backdrop', marker.backdrop),\n ]\"\n :style=\"{ transform: `translate(${marker.left}px, ${marker.top}px)` }\"\n ><span :class=\"ns.e('text')\">{{ marker.text }}</span></span\n >\n <span\n v-for=\"label in data\"\n :key=\"`data:${label.key}`\"\n :class=\"[\n ns.e('value'),\n ns.is(label.align),\n ns.is('inside', !!label.on),\n ns.is('hidden', !dataShown),\n ns.is('faded', dataFocus !== null && dataFocus !== label.series),\n ns.is('clipped', label.width !== undefined),\n ]\"\n :style=\"{\n transform: `translate(${label.left}px, ${label.top}px)`,\n color: label.ink,\n width: label.width === undefined ? undefined : `${label.width}px`,\n }\"\n ><span :class=\"ns.e('text')\">{{ label.text }}</span></span\n >\n </div>\n <div\n v-if=\"shown && legend.length && legendBox\"\n :class=\"[ns.e('legends'), ns.is('scroll', legendBox.scroll)]\"\n :style=\"{\n left: `${legendBox.x - LEGEND_PAD}px`,\n top: `${legendBox.y - LEGEND_PAD}px`,\n width: `${legendBox.width + LEGEND_PAD * 2}px`,\n height: `${legendBox.height + LEGEND_PAD * 2}px`,\n }\"\n >\n <!-- a name cut short shows in full on hover and focus; on a phone the legend goes where names aren't cut -->\n <DouTooltip\n v-for=\"item in legend\"\n :key=\"`legend:${item.index}`\"\n :content=\"item.text\"\n :disabled=\"!item.clipped\"\n >\n <button\n type=\"button\"\n :class=\"[\n ns.e('legend'),\n ns.is(item.kind),\n ns.is('dashed', item.dashed),\n ns.is('off', item.off),\n ns.is('locked', item.locked),\n ns.is('clipped', !!item.clipped),\n ]\"\n :style=\"{\n transform: `translate(${item.left - legendBox.x + LEGEND_PAD}px, ${item.top - legendBox.y + LEGEND_PAD}px)`,\n width: item.clipped ? `${item.width}px` : undefined,\n }\"\n :aria-pressed=\"!item.off\"\n :aria-describedby=\"hintId\"\n aria-keyshortcuts=\"Alt+Enter\"\n @click=\"(e) => onLegendClick(e, item.index)\"\n @keydown=\"(e) => onLegendKey(e, item.index)\"\n @pointerdown=\"(e) => e.pointerType === 'touch' && holdLegend(item.index)\"\n @pointerup=\"letGo\"\n @pointercancel=\"letGo\"\n @contextmenu=\"noMenu\"\n @pointerenter=\"(e) => e.pointerType !== 'touch' && !item.off && focus(item.index)\"\n @pointerleave=\"(letGo(), focus(null))\"\n @focus=\"(e) => focusVisible(e) && !item.off && focus(item.index)\"\n @blur=\"focus(null)\"\n >\n <span\n :class=\"ns.e('swatch')\"\n :style=\"\n item.scale\n ? {\n width: `${item.swatch}px`,\n background: `linear-gradient(to right, ${item.scale.join(', ')})`,\n }\n : item.pattern\n ? {\n color: item.color,\n backgroundImage: item.pattern.image,\n backgroundSize: item.pattern.size,\n }\n : { color: item.color }\n \"\n /><span :class=\"ns.e('text')\">{{ item.text }}</span>\n </button>\n </DouTooltip>\n <span :id=\"hintId\" hidden>{{ hint }}</span>\n </div>\n <div\n v-if=\"hole\"\n :class=\"[ns.e('center'), ns.is('above', !!hole.above)]\"\n :style=\"{ left: `${hole.left}px`, top: `${hole.top}px`, width: `${hole.width}px` }\"\n >\n <Center />\n </div>\n <div v-if=\"empty\" :class=\"ns.e('empty')\"><Empty /></div>\n <Transition name=\"dou-fade\">\n <div v-if=\"loading\" :class=\"ns.e('loading')\"><DouSpinner /></div>\n </Transition>\n</template>\n"],"mappings":""}