mviz 1.4.2

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 (194) hide show
  1. package/README.md +174 -0
  2. package/dist/charts/area.d.ts +14 -0
  3. package/dist/charts/area.d.ts.map +1 -0
  4. package/dist/charts/area.js +137 -0
  5. package/dist/charts/area.js.map +1 -0
  6. package/dist/charts/bar.d.ts +14 -0
  7. package/dist/charts/bar.d.ts.map +1 -0
  8. package/dist/charts/bar.js +191 -0
  9. package/dist/charts/bar.js.map +1 -0
  10. package/dist/charts/boxplot.d.ts +14 -0
  11. package/dist/charts/boxplot.d.ts.map +1 -0
  12. package/dist/charts/boxplot.js +79 -0
  13. package/dist/charts/boxplot.js.map +1 -0
  14. package/dist/charts/bubble.d.ts +14 -0
  15. package/dist/charts/bubble.d.ts.map +1 -0
  16. package/dist/charts/bubble.js +127 -0
  17. package/dist/charts/bubble.js.map +1 -0
  18. package/dist/charts/calendar.d.ts +14 -0
  19. package/dist/charts/calendar.d.ts.map +1 -0
  20. package/dist/charts/calendar.js +94 -0
  21. package/dist/charts/calendar.js.map +1 -0
  22. package/dist/charts/combo.d.ts +14 -0
  23. package/dist/charts/combo.d.ts.map +1 -0
  24. package/dist/charts/combo.js +163 -0
  25. package/dist/charts/combo.js.map +1 -0
  26. package/dist/charts/dumbbell.d.ts +17 -0
  27. package/dist/charts/dumbbell.d.ts.map +1 -0
  28. package/dist/charts/dumbbell.js +368 -0
  29. package/dist/charts/dumbbell.js.map +1 -0
  30. package/dist/charts/funnel.d.ts +14 -0
  31. package/dist/charts/funnel.d.ts.map +1 -0
  32. package/dist/charts/funnel.js +145 -0
  33. package/dist/charts/funnel.js.map +1 -0
  34. package/dist/charts/heatmap.d.ts +14 -0
  35. package/dist/charts/heatmap.d.ts.map +1 -0
  36. package/dist/charts/heatmap.js +202 -0
  37. package/dist/charts/heatmap.js.map +1 -0
  38. package/dist/charts/histogram.d.ts +14 -0
  39. package/dist/charts/histogram.d.ts.map +1 -0
  40. package/dist/charts/histogram.js +103 -0
  41. package/dist/charts/histogram.js.map +1 -0
  42. package/dist/charts/index.d.ts +40 -0
  43. package/dist/charts/index.d.ts.map +1 -0
  44. package/dist/charts/index.js +42 -0
  45. package/dist/charts/index.js.map +1 -0
  46. package/dist/charts/line.d.ts +14 -0
  47. package/dist/charts/line.d.ts.map +1 -0
  48. package/dist/charts/line.js +134 -0
  49. package/dist/charts/line.js.map +1 -0
  50. package/dist/charts/pie.d.ts +14 -0
  51. package/dist/charts/pie.d.ts.map +1 -0
  52. package/dist/charts/pie.js +75 -0
  53. package/dist/charts/pie.js.map +1 -0
  54. package/dist/charts/registry.d.ts +36 -0
  55. package/dist/charts/registry.d.ts.map +1 -0
  56. package/dist/charts/registry.js +55 -0
  57. package/dist/charts/registry.js.map +1 -0
  58. package/dist/charts/sankey.d.ts +14 -0
  59. package/dist/charts/sankey.d.ts.map +1 -0
  60. package/dist/charts/sankey.js +74 -0
  61. package/dist/charts/sankey.js.map +1 -0
  62. package/dist/charts/scatter.d.ts +14 -0
  63. package/dist/charts/scatter.d.ts.map +1 -0
  64. package/dist/charts/scatter.js +130 -0
  65. package/dist/charts/scatter.js.map +1 -0
  66. package/dist/charts/sparkline.d.ts +19 -0
  67. package/dist/charts/sparkline.d.ts.map +1 -0
  68. package/dist/charts/sparkline.js +154 -0
  69. package/dist/charts/sparkline.js.map +1 -0
  70. package/dist/charts/waterfall.d.ts +14 -0
  71. package/dist/charts/waterfall.d.ts.map +1 -0
  72. package/dist/charts/waterfall.js +232 -0
  73. package/dist/charts/waterfall.js.map +1 -0
  74. package/dist/charts/xmr.d.ts +14 -0
  75. package/dist/charts/xmr.d.ts.map +1 -0
  76. package/dist/charts/xmr.js +456 -0
  77. package/dist/charts/xmr.js.map +1 -0
  78. package/dist/cli.d.ts +12 -0
  79. package/dist/cli.d.ts.map +1 -0
  80. package/dist/cli.js +120 -0
  81. package/dist/cli.js.map +1 -0
  82. package/dist/components/alert.d.ts +10 -0
  83. package/dist/components/alert.d.ts.map +1 -0
  84. package/dist/components/alert.js +65 -0
  85. package/dist/components/alert.js.map +1 -0
  86. package/dist/components/big_value.d.ts +10 -0
  87. package/dist/components/big_value.d.ts.map +1 -0
  88. package/dist/components/big_value.js +78 -0
  89. package/dist/components/big_value.js.map +1 -0
  90. package/dist/components/delta.d.ts +10 -0
  91. package/dist/components/delta.d.ts.map +1 -0
  92. package/dist/components/delta.js +83 -0
  93. package/dist/components/delta.js.map +1 -0
  94. package/dist/components/empty_space.d.ts +10 -0
  95. package/dist/components/empty_space.d.ts.map +1 -0
  96. package/dist/components/empty_space.js +29 -0
  97. package/dist/components/empty_space.js.map +1 -0
  98. package/dist/components/index.d.ts +21 -0
  99. package/dist/components/index.d.ts.map +1 -0
  100. package/dist/components/index.js +23 -0
  101. package/dist/components/index.js.map +1 -0
  102. package/dist/components/note.d.ts +10 -0
  103. package/dist/components/note.d.ts.map +1 -0
  104. package/dist/components/note.js +66 -0
  105. package/dist/components/note.js.map +1 -0
  106. package/dist/components/registry.d.ts +24 -0
  107. package/dist/components/registry.d.ts.map +1 -0
  108. package/dist/components/registry.js +36 -0
  109. package/dist/components/registry.js.map +1 -0
  110. package/dist/components/table.d.ts +90 -0
  111. package/dist/components/table.d.ts.map +1 -0
  112. package/dist/components/table.js +610 -0
  113. package/dist/components/table.js.map +1 -0
  114. package/dist/components/text.d.ts +10 -0
  115. package/dist/components/text.d.ts.map +1 -0
  116. package/dist/components/text.js +46 -0
  117. package/dist/components/text.js.map +1 -0
  118. package/dist/components/textarea.d.ts +10 -0
  119. package/dist/components/textarea.d.ts.map +1 -0
  120. package/dist/components/textarea.js +79 -0
  121. package/dist/components/textarea.js.map +1 -0
  122. package/dist/core/colors.d.ts +45 -0
  123. package/dist/core/colors.d.ts.map +1 -0
  124. package/dist/core/colors.js +93 -0
  125. package/dist/core/colors.js.map +1 -0
  126. package/dist/core/css.d.ts +20 -0
  127. package/dist/core/css.d.ts.map +1 -0
  128. package/dist/core/css.js +97 -0
  129. package/dist/core/css.js.map +1 -0
  130. package/dist/core/exceptions.d.ts +59 -0
  131. package/dist/core/exceptions.d.ts.map +1 -0
  132. package/dist/core/exceptions.js +100 -0
  133. package/dist/core/exceptions.js.map +1 -0
  134. package/dist/core/formatting.d.ts +53 -0
  135. package/dist/core/formatting.d.ts.map +1 -0
  136. package/dist/core/formatting.js +491 -0
  137. package/dist/core/formatting.js.map +1 -0
  138. package/dist/core/index.d.ts +10 -0
  139. package/dist/core/index.d.ts.map +1 -0
  140. package/dist/core/index.js +10 -0
  141. package/dist/core/index.js.map +1 -0
  142. package/dist/core/serializer.d.ts +29 -0
  143. package/dist/core/serializer.d.ts.map +1 -0
  144. package/dist/core/serializer.js +84 -0
  145. package/dist/core/serializer.js.map +1 -0
  146. package/dist/core/themes.d.ts +138 -0
  147. package/dist/core/themes.d.ts.map +1 -0
  148. package/dist/core/themes.js +484 -0
  149. package/dist/core/themes.js.map +1 -0
  150. package/dist/core/version-check.d.ts +23 -0
  151. package/dist/core/version-check.d.ts.map +1 -0
  152. package/dist/core/version-check.js +163 -0
  153. package/dist/core/version-check.js.map +1 -0
  154. package/dist/generate_test_harness.d.ts +13 -0
  155. package/dist/generate_test_harness.d.ts.map +1 -0
  156. package/dist/generate_test_harness.js +35 -0
  157. package/dist/generate_test_harness.js.map +1 -0
  158. package/dist/index.d.ts +17 -0
  159. package/dist/index.d.ts.map +1 -0
  160. package/dist/index.js +19 -0
  161. package/dist/index.js.map +1 -0
  162. package/dist/layout/converter.d.ts +22 -0
  163. package/dist/layout/converter.d.ts.map +1 -0
  164. package/dist/layout/converter.js +46 -0
  165. package/dist/layout/converter.js.map +1 -0
  166. package/dist/layout/csv.d.ts +15 -0
  167. package/dist/layout/csv.d.ts.map +1 -0
  168. package/dist/layout/csv.js +88 -0
  169. package/dist/layout/csv.js.map +1 -0
  170. package/dist/layout/dispatcher.d.ts +13 -0
  171. package/dist/layout/dispatcher.d.ts.map +1 -0
  172. package/dist/layout/dispatcher.js +47 -0
  173. package/dist/layout/dispatcher.js.map +1 -0
  174. package/dist/layout/index.d.ts +8 -0
  175. package/dist/layout/index.d.ts.map +1 -0
  176. package/dist/layout/index.js +8 -0
  177. package/dist/layout/index.js.map +1 -0
  178. package/dist/layout/parser.d.ts +19 -0
  179. package/dist/layout/parser.d.ts.map +1 -0
  180. package/dist/layout/parser.js +888 -0
  181. package/dist/layout/parser.js.map +1 -0
  182. package/dist/layout/templates.d.ts +32 -0
  183. package/dist/layout/templates.d.ts.map +1 -0
  184. package/dist/layout/templates.js +1016 -0
  185. package/dist/layout/templates.js.map +1 -0
  186. package/dist/types.d.ts +144 -0
  187. package/dist/types.d.ts.map +1 -0
  188. package/dist/types.js +5 -0
  189. package/dist/types.js.map +1 -0
  190. package/dist/vitest.config.d.ts +3 -0
  191. package/dist/vitest.config.d.ts.map +1 -0
  192. package/dist/vitest.config.js +14 -0
  193. package/dist/vitest.config.js.map +1 -0
  194. package/package.json +79 -0
@@ -0,0 +1,368 @@
1
+ /**
2
+ * Dumbbell chart generator
3
+ *
4
+ * Dumbbell plots show comparisons between two values for each category,
5
+ * connected by a line with directional color-coding.
6
+ */
7
+ import { COLORS, FONT_SIZE_TINY, DUMBBELL_SYMBOL_SIZE, DEFAULT_CHART_HEIGHT, getThemeColors, } from '../core/themes.js';
8
+ import { wrapHtml } from '../core/serializer.js';
9
+ import { inferFormat, getAxisFormatterJs } from '../core/formatting.js';
10
+ import { registerChart, registerOptions } from './registry.js';
11
+ // Directional colors
12
+ const POSITIVE_COLOR = COLORS.POSITIVE_GREEN;
13
+ const NEGATIVE_COLOR = COLORS.ERROR_RED;
14
+ const NEUTRAL_COLOR = '#888888';
15
+ // Dark mode variants
16
+ const POSITIVE_COLOR_DARK = '#6ed020';
17
+ const NEGATIVE_COLOR_DARK = '#e05040';
18
+ const NEUTRAL_COLOR_DARK = '#a0a0a0';
19
+ /**
20
+ * Get a nice floor value for axis
21
+ */
22
+ function niceFloor(val, step) {
23
+ return Math.floor(val / step) * step;
24
+ }
25
+ /**
26
+ * Get a nice ceiling value for axis
27
+ */
28
+ function niceCeil(val, step) {
29
+ return Math.ceil(val / step) * step;
30
+ }
31
+ /**
32
+ * Get a nice step size based on data range
33
+ */
34
+ function getNiceStep(dataRange) {
35
+ if (dataRange <= 0)
36
+ return 1;
37
+ const magnitude = Math.pow(10, Math.floor(Math.log10(dataRange)));
38
+ const normalized = dataRange / magnitude;
39
+ if (normalized <= 2)
40
+ return magnitude / 5;
41
+ if (normalized <= 5)
42
+ return magnitude / 2;
43
+ return magnitude;
44
+ }
45
+ /**
46
+ * Build ECharts options for a dumbbell plot with directional coloring
47
+ */
48
+ export function buildDumbbellOptions(spec) {
49
+ const data = (spec.data ?? []);
50
+ const categoryField = spec.category ?? 'category';
51
+ const startField = spec.start ?? 'start';
52
+ const endField = spec.end ?? 'end';
53
+ const startLabel = spec.startLabel ?? startField.replace(/_/g, ' ');
54
+ const endLabel = spec.endLabel ?? endField.replace(/_/g, ' ');
55
+ const theme = (spec.theme ?? 'light');
56
+ const higherIsBetter = spec.higherIsBetter ?? true;
57
+ const showValues = spec.showValues ?? true;
58
+ const colors = getThemeColors(theme);
59
+ const isDark = theme === 'dark';
60
+ // Get directional colors based on theme
61
+ const positiveColor = isDark ? POSITIVE_COLOR_DARK : POSITIVE_COLOR;
62
+ const negativeColor = isDark ? NEGATIVE_COLOR_DARK : NEGATIVE_COLOR;
63
+ const neutralColor = isDark ? NEUTRAL_COLOR_DARK : NEUTRAL_COLOR;
64
+ // Extract data
65
+ const categories = data.map((d) => String(d[categoryField] ?? ''));
66
+ const startValues = data.map((d) => (d[startField] ?? 0));
67
+ const endValues = data.map((d) => (d[endField] ?? 0));
68
+ // Determine color for each row
69
+ const rowColors = startValues.map((s, i) => {
70
+ const e = endValues[i];
71
+ if (s === e)
72
+ return neutralColor;
73
+ if (higherIsBetter) {
74
+ return e > s ? positiveColor : negativeColor;
75
+ }
76
+ return e < s ? positiveColor : negativeColor;
77
+ });
78
+ // Infer value format
79
+ const sampleValue = startValues[0] ?? 0;
80
+ const valueFormat = spec.format ?? inferFormat(startField, sampleValue);
81
+ const isCurrency = valueFormat?.includes('usd');
82
+ const axisFormatter = getAxisFormatterJs(valueFormat);
83
+ // Calculate axis limits
84
+ const allValues = [...startValues, ...endValues];
85
+ let xMin = spec.xMin;
86
+ let xMax = spec.xMax;
87
+ if (allValues.length > 0) {
88
+ const minVal = Math.min(...allValues);
89
+ const maxVal = Math.max(...allValues);
90
+ const dataRange = maxVal !== minVal ? maxVal - minVal : Math.max(Math.abs(maxVal), 1);
91
+ const step = getNiceStep(dataRange);
92
+ const padding = Math.max(dataRange * 0.15, step);
93
+ const rawMin = minVal - padding;
94
+ const rawMax = maxVal + padding;
95
+ if (xMin === undefined) {
96
+ xMin = minVal >= 0 ? Math.max(0, niceFloor(rawMin, step)) : niceFloor(rawMin, step);
97
+ }
98
+ if (xMax === undefined) {
99
+ xMax = niceCeil(rawMax, step);
100
+ }
101
+ }
102
+ // Value formatter for labels inside dots
103
+ const valueFormatterJs = `function(params) {
104
+ var v = params.value[0];
105
+ var abs = Math.abs(v);
106
+ var isCurrency = ${isCurrency ? 'true' : 'false'};
107
+ var prefix = isCurrency ? '$' : '';
108
+ if (abs >= 1000000) {
109
+ var val = v / 1000000;
110
+ var formatted = isCurrency ? Math.round(val) : (Math.abs(val) >= 10 ? Math.round(val) : val.toFixed(1));
111
+ return prefix + formatted + 'm';
112
+ }
113
+ if (abs >= 1000) {
114
+ var val = v / 1000;
115
+ var formatted = isCurrency ? Math.round(val) : (Math.abs(val) >= 10 ? Math.round(val) : val.toFixed(1));
116
+ return prefix + formatted + 'k';
117
+ }
118
+ return isCurrency ? prefix + Math.round(v) : v;
119
+ }`;
120
+ // Build line data for custom series
121
+ const lineData = startValues.map((s, i) => {
122
+ const e = endValues[i];
123
+ const c = rowColors[i];
124
+ const isNoChange = s === e ? 1 : 0;
125
+ return [i, s, e, c, isNoChange];
126
+ });
127
+ // Custom render function for connecting lines with arrows
128
+ const renderItemJs = `function(params, api) {
129
+ var categoryIndex = api.value(0);
130
+ var start = api.value(1);
131
+ var end = api.value(2);
132
+ var color = api.value(3);
133
+ var isNoChange = api.value(4);
134
+ var startCoord = api.coord([start, categoryIndex]);
135
+ var endCoord = api.coord([end, categoryIndex]);
136
+
137
+ var dx = endCoord[0] - startCoord[0];
138
+ var absDx = Math.abs(dx);
139
+ var dotRadius = ${Math.floor(DUMBBELL_SYMBOL_SIZE / 2)};
140
+ var arrowSize = 5;
141
+ var arrowWidth = 3;
142
+
143
+ if (isNoChange || absDx < 1) {
144
+ return null;
145
+ }
146
+
147
+ var dotDiameter = dotRadius * 2;
148
+ if (absDx < dotDiameter) {
149
+ return null;
150
+ }
151
+
152
+ var lineStartX = startCoord[0] + (dx > 0 ? dotRadius : -dotRadius);
153
+ var lineEndX = endCoord[0] - (dx > 0 ? dotRadius : -dotRadius);
154
+ var lineClearance = Math.abs(lineEndX - lineStartX);
155
+
156
+ if (lineClearance < arrowSize + 2) {
157
+ return {
158
+ type: 'line',
159
+ shape: {
160
+ x1: lineStartX,
161
+ y1: startCoord[1],
162
+ x2: lineEndX,
163
+ y2: endCoord[1]
164
+ },
165
+ style: {
166
+ stroke: color,
167
+ lineWidth: 2
168
+ }
169
+ };
170
+ }
171
+
172
+ var arrowTipX = lineEndX;
173
+ var arrowBaseX = arrowTipX - (dx > 0 ? arrowSize : -arrowSize);
174
+
175
+ return {
176
+ type: 'group',
177
+ children: [
178
+ {
179
+ type: 'line',
180
+ shape: {
181
+ x1: lineStartX,
182
+ y1: startCoord[1],
183
+ x2: arrowBaseX,
184
+ y2: endCoord[1]
185
+ },
186
+ style: {
187
+ stroke: color,
188
+ lineWidth: 2
189
+ }
190
+ },
191
+ {
192
+ type: 'polygon',
193
+ shape: {
194
+ points: [
195
+ [arrowTipX, endCoord[1]],
196
+ [arrowBaseX, endCoord[1] - arrowWidth],
197
+ [arrowBaseX, endCoord[1] + arrowWidth]
198
+ ]
199
+ },
200
+ style: {
201
+ fill: color
202
+ }
203
+ }
204
+ ]
205
+ };
206
+ }`;
207
+ const series = [
208
+ // Connecting lines with arrows
209
+ {
210
+ name: 'range',
211
+ type: 'custom',
212
+ renderItem: { _js_: renderItemJs },
213
+ encode: { x: [1, 2], y: 0 },
214
+ data: lineData,
215
+ z: 1,
216
+ },
217
+ ];
218
+ // Start dots - outline style
219
+ const startData = startValues.map((v, i) => ({
220
+ value: [v, i],
221
+ itemStyle: {
222
+ color: colors.background,
223
+ borderColor: rowColors[i],
224
+ borderWidth: 2,
225
+ opacity: 1,
226
+ },
227
+ label: {
228
+ show: showValues,
229
+ position: 'inside',
230
+ fontSize: FONT_SIZE_TINY - 2,
231
+ fontWeight: 'bold',
232
+ color: rowColors[i],
233
+ formatter: { _js_: valueFormatterJs },
234
+ },
235
+ }));
236
+ series.push({
237
+ name: startLabel,
238
+ type: 'scatter',
239
+ data: startData,
240
+ symbolSize: DUMBBELL_SYMBOL_SIZE,
241
+ z: 10,
242
+ });
243
+ // End dots - filled style
244
+ const endData = endValues.map((v, i) => ({
245
+ value: [v, i],
246
+ itemStyle: {
247
+ color: rowColors[i],
248
+ opacity: 1,
249
+ },
250
+ label: {
251
+ show: showValues,
252
+ position: 'inside',
253
+ fontSize: FONT_SIZE_TINY - 2,
254
+ fontWeight: 'bold',
255
+ color: '#ffffff',
256
+ formatter: { _js_: valueFormatterJs },
257
+ },
258
+ }));
259
+ series.push({
260
+ name: endLabel,
261
+ type: 'scatter',
262
+ data: endData,
263
+ symbolSize: DUMBBELL_SYMBOL_SIZE,
264
+ z: 10,
265
+ });
266
+ // Tooltip formatter
267
+ const tooltipFormatterJs = `function(params) {
268
+ if (params.seriesName === 'range') return '';
269
+ var cat = ${JSON.stringify(categories)}[params.data.value ? params.data.value[1] : params.data[1]];
270
+ var val = params.data.value ? params.data.value[0] : params.data[0];
271
+ return '<strong>' + cat + '</strong><br/>' + params.seriesName + ': ' + val;
272
+ }`;
273
+ return {
274
+ backgroundColor: 'transparent',
275
+ animation: false,
276
+ tooltip: {
277
+ trigger: 'item',
278
+ backgroundColor: colors.paper,
279
+ borderColor: colors.border,
280
+ textStyle: { color: colors.text },
281
+ formatter: { _js_: tooltipFormatterJs },
282
+ },
283
+ legend: {
284
+ show: true,
285
+ data: [
286
+ {
287
+ name: startLabel,
288
+ icon: 'circle',
289
+ itemStyle: {
290
+ color: colors.background,
291
+ borderColor: colors.textSecondary,
292
+ borderWidth: 2,
293
+ },
294
+ },
295
+ {
296
+ name: endLabel,
297
+ icon: 'circle',
298
+ itemStyle: {
299
+ color: colors.textSecondary,
300
+ },
301
+ },
302
+ ],
303
+ bottom: 0,
304
+ textStyle: { color: colors.textSecondary, fontSize: FONT_SIZE_TINY },
305
+ },
306
+ grid: {
307
+ left: '3%',
308
+ right: '4%',
309
+ top: '3%',
310
+ bottom: '15%',
311
+ containLabel: true,
312
+ },
313
+ xAxis: {
314
+ type: 'value',
315
+ min: xMin,
316
+ max: xMax,
317
+ axisLine: { show: false },
318
+ axisTick: { show: false },
319
+ axisLabel: {
320
+ color: colors.textSecondary,
321
+ ...(axisFormatter && { formatter: axisFormatter }),
322
+ },
323
+ splitLine: { lineStyle: { color: colors.border, type: [2, 3], opacity: 0.6 } },
324
+ },
325
+ yAxis: {
326
+ type: 'category',
327
+ data: categories,
328
+ inverse: true,
329
+ axisLine: { show: false },
330
+ axisTick: { show: false },
331
+ axisLabel: {
332
+ color: colors.textSecondary,
333
+ rotate: 0,
334
+ interval: 0,
335
+ },
336
+ },
337
+ series,
338
+ };
339
+ }
340
+ /**
341
+ * Calculate minimum height for dumbbell chart based on number of rows
342
+ */
343
+ function calculateDumbbellHeight(numRows, specHeight) {
344
+ // Each row needs symbol size plus small gap to prevent vertical overlap
345
+ // With 22px symbols, 4px gap gives minimal spacing without excessive whitespace
346
+ const rowHeight = DUMBBELL_SYMBOL_SIZE + 4; // symbol + small gap
347
+ const legendHeight = 40;
348
+ const gridPadding = 60; // top + bottom margins
349
+ const minHeight = (numRows * rowHeight) + legendHeight + gridPadding;
350
+ // Use spec height if provided and larger than minimum, otherwise use calculated minimum
351
+ if (typeof specHeight === 'number') {
352
+ return Math.max(specHeight, minHeight);
353
+ }
354
+ return Math.max(DEFAULT_CHART_HEIGHT, minHeight);
355
+ }
356
+ /**
357
+ * Generate a dumbbell chart
358
+ */
359
+ function generateDumbbell(spec) {
360
+ const data = (spec.data ?? []);
361
+ const height = calculateDumbbellHeight(data.length, spec.height);
362
+ return wrapHtml('chart', buildDumbbellOptions(spec), '', '100%', height);
363
+ }
364
+ // Register the chart
365
+ registerChart('dumbbell')(generateDumbbell);
366
+ registerOptions('dumbbell')(buildDumbbellOptions);
367
+ export { generateDumbbell };
368
+ //# sourceMappingURL=dumbbell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dumbbell.js","sourceRoot":"","sources":["../../charts/dumbbell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Funnel chart generator
3
+ */
4
+ import type { ChartSpec } from '../types.js';
5
+ /**
6
+ * Build ECharts options for a funnel chart
7
+ */
8
+ export declare function buildFunnelOptions(spec: ChartSpec): Record<string, unknown>;
9
+ /**
10
+ * Generate a funnel chart
11
+ */
12
+ declare function generateFunnel(spec: ChartSpec): string;
13
+ export { generateFunnel };
14
+ //# sourceMappingURL=funnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.d.ts","sourceRoot":"","sources":["../../charts/funnel.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAoB,MAAM,aAAa,CAAC;AAmE/D;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsE3E;AAED;;GAEG;AACH,iBAAS,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAG/C;AAMD,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Funnel chart generator
3
+ */
4
+ import { FONT_SIZE_XXS, getThemeColors, getPalette } from '../core/themes.js';
5
+ import { wrapHtml } from '../core/serializer.js';
6
+ import { inferFormat } from '../core/formatting.js';
7
+ import { registerChart, registerOptions } from './registry.js';
8
+ /**
9
+ * Get JavaScript formatter for funnel chart labels/tooltips
10
+ */
11
+ function getFunnelFormatterJs(fmt) {
12
+ // Smart auto-formatting based on magnitude
13
+ if (fmt === 'auto' || fmt === 'usd_auto' || fmt === null || fmt === undefined) {
14
+ const isCurrency = fmt === 'usd_auto' ? 'true' : 'false';
15
+ return {
16
+ _js_: `function(params) {
17
+ var v = params.value;
18
+ if (v == null) return params.name;
19
+ var abs = Math.abs(v);
20
+ var neg = v < 0;
21
+ var p = ${isCurrency} ? '$' : '';
22
+ var r;
23
+ if (abs >= 1e9) {
24
+ var s = abs / 1e9;
25
+ r = s >= 100 ? p + s.toFixed(1) + 'b' : s >= 10 ? p + s.toFixed(2) + 'b' : p + s.toFixed(3) + 'b';
26
+ } else if (abs >= 1e6) {
27
+ var s = abs / 1e6;
28
+ r = s >= 100 ? p + s.toFixed(1) + 'm' : s >= 10 ? p + s.toFixed(2) + 'm' : p + s.toFixed(3) + 'm';
29
+ } else if (abs >= 1e4) {
30
+ var s = abs / 1e3;
31
+ r = s >= 100 ? p + s.toFixed(1) + 'k' : p + s.toFixed(2) + 'k';
32
+ } else if (abs >= 1e3) {
33
+ r = p + abs.toLocaleString('en-US', {maximumFractionDigits: 0});
34
+ } else {
35
+ r = abs === Math.floor(abs) ? p + abs : p + abs.toFixed(2);
36
+ }
37
+ var formatted = neg ? '(' + r + ')' : r;
38
+ return params.name + ': ' + formatted;
39
+ }`,
40
+ };
41
+ }
42
+ // Specific format handlers
43
+ switch (fmt) {
44
+ case 'usd':
45
+ return { _js_: "function(params) { return params.name + ': $' + params.value.toLocaleString(); }" };
46
+ case 'usd0k':
47
+ return {
48
+ _js_: "function(params) { return params.name + ': $' + (params.value/1000).toFixed(0) + 'k'; }",
49
+ };
50
+ case 'pct':
51
+ case 'pct1':
52
+ return {
53
+ _js_: "function(params) { return params.name + ': ' + (params.value * 100).toFixed(1) + '%'; }",
54
+ };
55
+ case 'pct0':
56
+ return {
57
+ _js_: "function(params) { return params.name + ': ' + (params.value * 100).toFixed(0) + '%'; }",
58
+ };
59
+ case 'num0':
60
+ return { _js_: "function(params) { return params.name + ': ' + params.value.toLocaleString(); }" };
61
+ case 'num1':
62
+ return { _js_: "function(params) { return params.name + ': ' + params.value.toFixed(1); }" };
63
+ default:
64
+ return { _js_: "function(params) { return params.name + ': ' + params.value.toLocaleString(); }" };
65
+ }
66
+ }
67
+ /**
68
+ * Build ECharts options for a funnel chart
69
+ */
70
+ export function buildFunnelOptions(spec) {
71
+ const data = (spec.data ?? []);
72
+ const valueField = spec.value ?? 'value';
73
+ const nameField = spec.name ?? 'name';
74
+ const theme = (spec.theme ?? 'light');
75
+ const colors = getThemeColors(theme);
76
+ const palette = getPalette(theme);
77
+ // Build funnel data
78
+ const funnelData = data.map((d) => ({
79
+ name: String(d[nameField] ?? ''),
80
+ value: (d[valueField] ?? 0),
81
+ }));
82
+ // Sort descending by value
83
+ funnelData.sort((a, b) => b.value - a.value);
84
+ // Assign colors
85
+ funnelData.forEach((item, i) => {
86
+ item.itemStyle = { color: palette[i % palette.length] };
87
+ });
88
+ // Infer format from value field name or use explicit format
89
+ const sampleValue = funnelData[0]?.value ?? 0;
90
+ const valueFormat = spec.format ?? inferFormat(valueField, sampleValue);
91
+ // Get JavaScript formatter
92
+ const formatter = getFunnelFormatterJs(valueFormat);
93
+ return {
94
+ backgroundColor: 'transparent',
95
+ animation: false,
96
+ tooltip: {
97
+ trigger: 'item',
98
+ backgroundColor: colors.paper,
99
+ borderColor: colors.border,
100
+ textStyle: { color: colors.text },
101
+ formatter,
102
+ },
103
+ series: [
104
+ {
105
+ type: 'funnel',
106
+ left: '12%',
107
+ width: '76%',
108
+ top: '8%',
109
+ bottom: '8%',
110
+ min: 0,
111
+ max: funnelData[0]?.value ?? 100,
112
+ minSize: '0%',
113
+ maxSize: '100%',
114
+ sort: 'descending',
115
+ gap: 2,
116
+ label: {
117
+ show: true,
118
+ position: 'inside',
119
+ formatter,
120
+ color: '#fff',
121
+ fontSize: FONT_SIZE_XXS,
122
+ },
123
+ itemStyle: {
124
+ borderWidth: 0,
125
+ },
126
+ emphasis: {
127
+ disabled: true,
128
+ },
129
+ data: funnelData,
130
+ },
131
+ ],
132
+ };
133
+ }
134
+ /**
135
+ * Generate a funnel chart
136
+ */
137
+ function generateFunnel(spec) {
138
+ const height = typeof spec.height === 'number' ? spec.height : 300;
139
+ return wrapHtml('chart', buildFunnelOptions(spec), '', '100%', height);
140
+ }
141
+ // Register the chart
142
+ registerChart('funnel')(generateFunnel);
143
+ registerOptions('funnel')(buildFunnelOptions);
144
+ export { generateFunnel };
145
+ //# sourceMappingURL=funnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.js","sourceRoot":"","sources":["../../charts/funnel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Heatmap chart generator
3
+ */
4
+ import type { ChartSpec } from '../types.js';
5
+ /**
6
+ * Build ECharts options for a heatmap
7
+ */
8
+ export declare function buildHeatmapOptions(spec: ChartSpec): Record<string, unknown>;
9
+ /**
10
+ * Generate a heatmap chart
11
+ */
12
+ declare function generateHeatmap(spec: ChartSpec): string;
13
+ export { generateHeatmap };
14
+ //# sourceMappingURL=heatmap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heatmap.d.ts","sourceRoot":"","sources":["../../charts/heatmap.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAgC,MAAM,aAAa,CAAC;AA+F3E;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsG5E;AAED;;GAEG;AACH,iBAAS,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAGhD;AAMD,OAAO,EAAE,eAAe,EAAE,CAAC"}