@cfasim-ui/charts 0.7.8 → 0.8.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 (67) hide show
  1. package/dist/BarChart/BarChart.d.ts +9 -26
  2. package/dist/ChartMenu/ChartMenu.d.ts +3 -2
  3. package/dist/ChartTooltip/ChartTooltip.d.ts +9 -12
  4. package/dist/ChoroplethMap/ChoroplethMap.d.ts +42 -190
  5. package/dist/ChoroplethMap/ChoroplethTooltip.d.ts +20 -27
  6. package/dist/ChoroplethMap/canvasLayer.d.ts +23 -6
  7. package/dist/ChoroplethMap/cityLayout.d.ts +3 -2
  8. package/dist/ChoroplethMap/mixedGeo.d.ts +74 -0
  9. package/dist/ChoroplethMap/mixedGeo.test.d.ts +1 -0
  10. package/dist/DataTable/DataTable.d.ts +3 -2
  11. package/dist/LineChart/LineChart.d.ts +9 -26
  12. package/dist/_shared/ChartAnnotations.d.ts +3 -2
  13. package/dist/_shared/ChartZoomControls.d.ts +3 -2
  14. package/dist/_shared/index.d.ts +2 -1
  15. package/dist/_shared/mapTheme.d.ts +159 -0
  16. package/dist/_shared/mapTheme.test.d.ts +1 -0
  17. package/dist/index.css +1 -1
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1821 -1462
  20. package/docs/BarChart.md +776 -0
  21. package/docs/ChoroplethMap.md +1394 -0
  22. package/docs/DataTable.md +386 -0
  23. package/docs/LineChart.md +1267 -0
  24. package/docs/index.json +56 -0
  25. package/package.json +25 -21
  26. package/src/BarChart/BarChart.md +743 -0
  27. package/src/BarChart/BarChart.vue +1901 -0
  28. package/src/ChartMenu/ChartMenu.vue +220 -0
  29. package/src/ChartMenu/download.ts +120 -0
  30. package/src/ChartTooltip/ChartTooltip.vue +97 -0
  31. package/src/ChoroplethMap/ChoroplethMap.md +1354 -0
  32. package/src/ChoroplethMap/ChoroplethMap.vue +3778 -0
  33. package/src/ChoroplethMap/ChoroplethTooltip.vue +103 -0
  34. package/src/ChoroplethMap/canvasLayer.ts +373 -0
  35. package/src/ChoroplethMap/cityLayout.ts +262 -0
  36. package/src/ChoroplethMap/hsaMapping.ts +4116 -0
  37. package/src/ChoroplethMap/mixedGeo.ts +201 -0
  38. package/src/DataTable/DataTable.md +372 -0
  39. package/src/DataTable/DataTable.vue +406 -0
  40. package/src/LineChart/LineChart.md +1225 -0
  41. package/src/LineChart/LineChart.vue +1555 -0
  42. package/src/_shared/ChartAnnotations.vue +420 -0
  43. package/src/_shared/ChartZoomControls.vue +138 -0
  44. package/src/_shared/annotations.ts +106 -0
  45. package/src/_shared/axes.ts +69 -0
  46. package/src/_shared/chartProps.ts +201 -0
  47. package/src/_shared/computeTicks.ts +42 -0
  48. package/src/_shared/contrast.ts +100 -0
  49. package/src/_shared/dateAxis.ts +501 -0
  50. package/src/_shared/index.ts +78 -0
  51. package/src/_shared/mapTheme.ts +551 -0
  52. package/src/_shared/scale.ts +86 -0
  53. package/src/_shared/seriesCsv.ts +68 -0
  54. package/src/_shared/touch.ts +8 -0
  55. package/src/_shared/useChartFoundation.ts +175 -0
  56. package/src/_shared/useChartFullscreen.ts +254 -0
  57. package/src/_shared/useChartMenu.ts +111 -0
  58. package/src/_shared/useChartPadding.ts +235 -0
  59. package/src/_shared/useChartSize.ts +58 -0
  60. package/src/_shared/useChartTooltip.ts +205 -0
  61. package/src/env.d.ts +4 -0
  62. package/src/hsa-mapping.ts +1 -0
  63. package/src/index.ts +41 -0
  64. package/src/tooltip-position.ts +55 -0
  65. package/src/us-cities/data.ts +1371 -0
  66. package/src/us-cities/index.ts +122 -0
  67. package/src/us-cities.ts +7 -0
@@ -0,0 +1,743 @@
1
+ ---
2
+ keywords:
3
+ [
4
+ bar,
5
+ column,
6
+ chart,
7
+ categorical,
8
+ grouped,
9
+ stacked,
10
+ overlay,
11
+ vertical,
12
+ horizontal,
13
+ svg,
14
+ ]
15
+ ---
16
+
17
+ # BarChart
18
+
19
+ A responsive SVG bar chart supporting single, grouped, stacked, and overlay
20
+ series in either vertical (column) or horizontal orientation. Shares axis,
21
+ tooltip, menu, and CSV export wiring with [`LineChart`](./line-chart).
22
+
23
+ ## Examples
24
+
25
+ ### Single series
26
+
27
+ <ComponentDemo>
28
+ <BarChart
29
+ :data="[12, 19, 7, 24, 16]"
30
+ :categories="['Mon', 'Tue', 'Wed', 'Thu', 'Fri']"
31
+ :height="220"
32
+ x-label="Day"
33
+ y-label="Cases"
34
+ tooltip-trigger="hover"
35
+ />
36
+
37
+ <template #code>
38
+
39
+ ```vue
40
+ <BarChart
41
+ :data="[12, 19, 7, 24, 16]"
42
+ :categories="['Mon', 'Tue', 'Wed', 'Thu', 'Fri']"
43
+ :height="220"
44
+ x-label="Day"
45
+ y-label="Cases"
46
+ tooltip-trigger="hover"
47
+ />
48
+ ```
49
+
50
+ </template>
51
+ </ComponentDemo>
52
+
53
+ ### Grouped series
54
+
55
+ <ComponentDemo>
56
+ <BarChart
57
+ :series="[
58
+ { data: [10, 14, 9, 18], legend: 'Pediatric', color: '#0057b7' },
59
+ { data: [22, 28, 19, 30], legend: 'Adult', color: '#f4a261' },
60
+ ]"
61
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
62
+ :height="220"
63
+ y-label="Doses (thousands)"
64
+ tooltip-trigger="hover"
65
+ />
66
+
67
+ <template #code>
68
+
69
+ ```vue
70
+ <BarChart
71
+ :series="[
72
+ { data: [10, 14, 9, 18], legend: 'Pediatric', color: '#0057b7' },
73
+ { data: [22, 28, 19, 30], legend: 'Adult', color: '#f4a261' },
74
+ ]"
75
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
76
+ :height="220"
77
+ y-label="Doses (thousands)"
78
+ tooltip-trigger="hover"
79
+ />
80
+ ```
81
+
82
+ </template>
83
+ </ComponentDemo>
84
+
85
+ ### Stacked series
86
+
87
+ <ComponentDemo>
88
+ <BarChart
89
+ :series="[
90
+ { data: [10, 14, 9, 18], legend: 'Pediatric', color: '#0057b7' },
91
+ { data: [22, 28, 19, 30], legend: 'Adult', color: '#f4a261' },
92
+ ]"
93
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
94
+ layout="stacked"
95
+ :height="220"
96
+ y-label="Doses (thousands)"
97
+ tooltip-trigger="hover"
98
+ />
99
+
100
+ <template #code>
101
+
102
+ ```vue
103
+ <BarChart
104
+ :series="[
105
+ { data: [10, 14, 9, 18], legend: 'Pediatric', color: '#0057b7' },
106
+ { data: [22, 28, 19, 30], legend: 'Adult', color: '#f4a261' },
107
+ ]"
108
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
109
+ layout="stacked"
110
+ :height="220"
111
+ y-label="Doses (thousands)"
112
+ tooltip-trigger="hover"
113
+ />
114
+ ```
115
+
116
+ </template>
117
+ </ComponentDemo>
118
+
119
+ ### Overlay series
120
+
121
+ `layout="overlay"` draws each series at full group width from the shared
122
+ baseline, painting later series on top of earlier ones. Use it to compare
123
+ a backdrop value (e.g. target, capacity, prior period) against a shorter
124
+ foreground value sharing the same axis.
125
+
126
+ Series render in the order they appear in `series`, so put the taller
127
+ backdrop first and the shorter foreground after. Use `opacity`, a
128
+ distinct color, or a per-series `blendMode` (see below) if bars might
129
+ overlap fully.
130
+
131
+ <ComponentDemo>
132
+ <BarChart
133
+ :series="[
134
+ { data: [40, 40, 40, 40], legend: 'Target', color: '#d4d4d8' },
135
+ { data: [22, 35, 28, 38], legend: 'Actual', color: '#0057b7' },
136
+ ]"
137
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
138
+ layout="overlay"
139
+ :height="220"
140
+ y-label="Doses (thousands)"
141
+ tooltip-trigger="hover"
142
+ />
143
+
144
+ <template #code>
145
+
146
+ ```vue
147
+ <BarChart
148
+ :series="[
149
+ { data: [40, 40, 40, 40], legend: 'Target', color: '#d4d4d8' },
150
+ { data: [22, 35, 28, 38], legend: 'Actual', color: '#0057b7' },
151
+ ]"
152
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
153
+ layout="overlay"
154
+ :height="220"
155
+ y-label="Doses (thousands)"
156
+ tooltip-trigger="hover"
157
+ />
158
+ ```
159
+
160
+ </template>
161
+ </ComponentDemo>
162
+
163
+ ### Blend mode
164
+
165
+ Set `blendMode` on a series to apply a CSS `mix-blend-mode` to every
166
+ bar in that series. Useful with `layout="overlay"` (or just two
167
+ overlapping grouped bars) to combine colors instead of one obscuring
168
+ the other. Common picks: `"multiply"` (darkens light fills where bars
169
+ overlap), `"screen"` (lightens dark fills), `"difference"` (high
170
+ contrast).
171
+
172
+ <ComponentDemo>
173
+ <BarChart
174
+ :series="[
175
+ { data: [22, 35, 28, 38], legend: 'Treatment A', color: '#ef4444', blendMode: 'multiply' },
176
+ { data: [30, 24, 36, 32], legend: 'Treatment B', color: '#3b82f6', blendMode: 'multiply' },
177
+ ]"
178
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
179
+ layout="overlay"
180
+ :height="220"
181
+ y-label="Cases avoided"
182
+ tooltip-trigger="hover"
183
+ />
184
+
185
+ <template #code>
186
+
187
+ ```vue
188
+ <BarChart
189
+ :series="[
190
+ {
191
+ data: [22, 35, 28, 38],
192
+ legend: 'Treatment A',
193
+ color: '#ef4444',
194
+ blendMode: 'multiply',
195
+ },
196
+ {
197
+ data: [30, 24, 36, 32],
198
+ legend: 'Treatment B',
199
+ color: '#3b82f6',
200
+ blendMode: 'multiply',
201
+ },
202
+ ]"
203
+ :categories="['Q1', 'Q2', 'Q3', 'Q4']"
204
+ layout="overlay"
205
+ :height="220"
206
+ y-label="Cases avoided"
207
+ tooltip-trigger="hover"
208
+ />
209
+ ```
210
+
211
+ </template>
212
+ </ComponentDemo>
213
+
214
+ ### Horizontal orientation
215
+
216
+ On touch devices the tooltip scrubs along the category axis: drag horizontally on a vertical (column) chart and vertically on a horizontal chart. A swipe in the other direction scrolls the page instead of being captured by the chart.
217
+
218
+ <ComponentDemo>
219
+ <BarChart
220
+ :data="[42, 31, 18, 12, 7]"
221
+ :categories="['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon']"
222
+ orientation="horizontal"
223
+ :height="220"
224
+ x-label="Cases"
225
+ tooltip-trigger="hover"
226
+ />
227
+
228
+ <template #code>
229
+
230
+ ```vue
231
+ <BarChart
232
+ :data="[42, 31, 18, 12, 7]"
233
+ :categories="['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon']"
234
+ orientation="horizontal"
235
+ :height="220"
236
+ x-label="Cases"
237
+ tooltip-trigger="hover"
238
+ />
239
+ ```
240
+
241
+ </template>
242
+ </ComponentDemo>
243
+
244
+ ### Value labels on bars
245
+
246
+ Set `bar-labels` to write values directly on the bars (pair with
247
+ `:value-axis="false"` for an axis-free look). Pass an options object to tune:
248
+
249
+ - `format` — a `NumberFormat` or `(value, ctx) => string` (`ctx` has
250
+ `categoryIndex` / `seriesIndex`); return `""` to drop a label.
251
+ - `align` — `"center"` (default), `"start"`, or `"end"` within the segment.
252
+ - `color` — auto-contrast per segment by default, or a fixed color.
253
+ - Small/overlapping labels overflow past the segment edge and are spread
254
+ apart (`overlap: "shift"`) or dropped (`overlap: "hide"`).
255
+
256
+ `category-header` / `value-header` title the two columns, and
257
+ `category-align="start"` left-aligns the category labels.
258
+
259
+ <ComponentDemo>
260
+ <BarChart
261
+ :series="[
262
+ { data: [99, 88, 50, 1], legend: 'High', color: '#3f1f5e' },
263
+ { data: [0.5, 10, 30, 20], legend: 'Medium', color: '#8a5fb0' },
264
+ { data: [0.5, 2, 20, 79], legend: 'Low', color: '#c9aee0' },
265
+ ]"
266
+ :categories="['Alpha', 'Beta', 'Gamma', 'Delta']"
267
+ title="Projected outbreak size by scenario"
268
+ :title-style="{ fontSize: 16 }"
269
+ orientation="horizontal"
270
+ layout="stacked"
271
+ :value-axis="false"
272
+ category-header="Scenario"
273
+ value-header="Proportion of simulations in each category"
274
+ category-align="start"
275
+ :height="260"
276
+ :chart-padding="{ left: 18, right: 64 }"
277
+ :tick-label-style="{ fontSize: 11, color: 'currentColor' }"
278
+ :bar-labels="{
279
+ align: 'start',
280
+ fontWeight: 600,
281
+ format: (v, { categoryIndex }) =>
282
+ v < 1
283
+ ? '<1%'
284
+ : categoryIndex === 0
285
+ ? `${Math.round(v)}%`
286
+ : String(Math.round(v)),
287
+ }"
288
+ />
289
+
290
+ <template #code>
291
+
292
+ ```vue
293
+ <BarChart
294
+ :series="[
295
+ { data: [99, 88, 50, 1], legend: 'High', color: '#3f1f5e' },
296
+ { data: [0.5, 10, 30, 20], legend: 'Medium', color: '#8a5fb0' },
297
+ { data: [0.5, 2, 20, 79], legend: 'Low', color: '#c9aee0' },
298
+ ]"
299
+ :categories="['Alpha', 'Beta', 'Gamma', 'Delta']"
300
+ title="Projected outbreak size by scenario"
301
+ :title-style="{ fontSize: 16 }"
302
+ orientation="horizontal"
303
+ layout="stacked"
304
+ :value-axis="false"
305
+ category-header="Scenario"
306
+ value-header="Proportion of simulations in each category"
307
+ category-align="start"
308
+ :height="260"
309
+ :chart-padding="{ left: 18, right: 64 }"
310
+ :tick-label-style="{ fontSize: 11, color: 'currentColor' }"
311
+ :bar-labels="{
312
+ align: 'start',
313
+ fontWeight: 600,
314
+ format: (v, { categoryIndex }) =>
315
+ v < 1
316
+ ? '<1%'
317
+ : categoryIndex === 0
318
+ ? `${Math.round(v)}%`
319
+ : String(Math.round(v)),
320
+ }"
321
+ />
322
+ ```
323
+
324
+ </template>
325
+ </ComponentDemo>
326
+
327
+ #### Small segments
328
+
329
+ A single proportion bar with two tiny tail segments (98% / 1% / 1%). The
330
+ dominant segment labels inside; the two slivers can't fit their text, so the
331
+ labels overflow to the right and the overlap pass spreads them apart instead
332
+ of letting them pile up.
333
+
334
+ <ComponentDemo>
335
+ <BarChart
336
+ :series="[
337
+ { data: [98], legend: 'Recovered', color: '#3f1f5e' },
338
+ { data: [1], legend: 'Hospitalized', color: '#8a5fb0' },
339
+ { data: [1], legend: 'Deceased', color: '#c9aee0' },
340
+ ]"
341
+ :categories="['Outcome']"
342
+ orientation="horizontal"
343
+ layout="stacked"
344
+ :value-axis="false"
345
+ :height="120"
346
+ :chart-padding="{ left: 60, right: 40 }"
347
+ :bar-labels="{ format: (v) => `${v}%` }"
348
+ />
349
+
350
+ <template #code>
351
+
352
+ ```vue
353
+ <BarChart
354
+ :series="[
355
+ { data: [98], legend: 'Recovered', color: '#3f1f5e' },
356
+ { data: [1], legend: 'Hospitalized', color: '#8a5fb0' },
357
+ { data: [1], legend: 'Deceased', color: '#c9aee0' },
358
+ ]"
359
+ :categories="['Outcome']"
360
+ orientation="horizontal"
361
+ layout="stacked"
362
+ :value-axis="false"
363
+ :height="120"
364
+ :chart-padding="{ left: 60, right: 40 }"
365
+ :bar-labels="{ format: (v) => `${v}%` }"
366
+ />
367
+ ```
368
+
369
+ </template>
370
+ </ComponentDemo>
371
+
372
+ ### Custom value tick format
373
+
374
+ Use `value-tick-format` to format the value-axis labels. `tooltip-value-format` controls the tooltip values independently; if omitted, the tooltip uses `value-tick-format`.
375
+
376
+ <ComponentDemo>
377
+ <BarChart
378
+ :data="[0.12, 0.34, 0.56, 0.78]"
379
+ :categories="['A', 'B', 'C', 'D']"
380
+ :value-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
381
+ :tooltip-value-format="(v) => `${(v * 100).toFixed(1)}%`"
382
+ :height="220"
383
+ y-label="Coverage"
384
+ tooltip-trigger="hover"
385
+ />
386
+
387
+ <template #code>
388
+
389
+ ```vue
390
+ <BarChart
391
+ :data="[0.12, 0.34, 0.56, 0.78]"
392
+ :categories="['A', 'B', 'C', 'D']"
393
+ :value-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
394
+ :tooltip-value-format="(v) => `${(v * 100).toFixed(1)}%`"
395
+ :height="220"
396
+ y-label="Coverage"
397
+ tooltip-trigger="hover"
398
+ />
399
+ ```
400
+
401
+ </template>
402
+ </ComponentDemo>
403
+
404
+ ### Date categories
405
+
406
+ When every entry of `categories` parses as a date (`YYYY-MM-DD` string
407
+ or `Date` instance), labels switch to date-aware formatting and the
408
+ chart thins them to clean date boundaries (week / month / year
409
+ depending on range). Bar positions stay ordinal — every category gets
410
+ a bar — only the labels are thinned.
411
+
412
+ <ComponentDemo>
413
+ <BarChart
414
+ :data="[12, 18, 24, 35, 41, 38, 29, 21, 14, 9, 7, 4]"
415
+ :categories="['2026-01-05','2026-01-12','2026-01-19','2026-01-26','2026-02-02','2026-02-09','2026-02-16','2026-02-23','2026-03-02','2026-03-09','2026-03-16','2026-03-23']"
416
+ :height="220"
417
+ y-label="% ED visits"
418
+ />
419
+
420
+ <template #code>
421
+
422
+ ```vue
423
+ <BarChart
424
+ :data="[12, 18, 24, 35, 41, 38, 29, 21, 14, 9, 7, 4]"
425
+ :categories="[
426
+ '2026-01-05',
427
+ '2026-01-12',
428
+ '2026-01-19',
429
+ '2026-01-26',
430
+ '2026-02-02',
431
+ '2026-02-09',
432
+ '2026-02-16',
433
+ '2026-02-23',
434
+ '2026-03-02',
435
+ '2026-03-09',
436
+ '2026-03-16',
437
+ '2026-03-23',
438
+ ]"
439
+ :height="220"
440
+ y-label="% ED visits"
441
+ />
442
+ ```
443
+
444
+ </template>
445
+ </ComponentDemo>
446
+
447
+ Use `date-format` to override the auto-picked preset. Same values as
448
+ LineChart's `x-tick-format` (e.g. `"iso"`, `"month-year"`, an
449
+ `Intl.DateTimeFormatOptions` object, or a `(ms, unit?) => string`
450
+ function).
451
+
452
+ ### Crowded categorical labels
453
+
454
+ Non-date categorical labels are also thinned when they don't all fit:
455
+ the chart estimates label width from character count and font size,
456
+ then strides through the categories so adjacent labels never overlap.
457
+ Every bar still renders — only the tick labels are skipped.
458
+
459
+ <ComponentDemo>
460
+ <BarChart
461
+ data-testid="thinned-bar-chart"
462
+ :data="[3, 5, 8, 12, 18, 24, 31, 27, 22, 16, 11, 7, 4, 2]"
463
+ :categories="['2.11', '2.33', '2.56', '2.78', '3.00', '3.22', '3.44', '3.67', '3.89', '4.11', '4.33', '4.56', '4.78', '5.00']"
464
+ :width="380"
465
+ :height="220"
466
+ x-label="R₀"
467
+ y-label="Frequency"
468
+ />
469
+
470
+ <template #code>
471
+
472
+ ```vue
473
+ <BarChart
474
+ :data="[3, 5, 8, 12, 18, 24, 31, 27, 22, 16, 11, 7, 4, 2]"
475
+ :categories="[
476
+ '2.11',
477
+ '2.33',
478
+ '2.56',
479
+ '2.78',
480
+ '3.00',
481
+ '3.22',
482
+ '3.44',
483
+ '3.67',
484
+ '3.89',
485
+ '4.11',
486
+ '4.33',
487
+ '4.56',
488
+ '4.78',
489
+ '5.00',
490
+ ]"
491
+ :height="220"
492
+ x-label="R₀"
493
+ y-label="Frequency"
494
+ />
495
+ ```
496
+
497
+ </template>
498
+ </ComponentDemo>
499
+
500
+ ### Logarithmic value axis
501
+
502
+ Set `value-scale-type="log"` to switch the value axis to base-10 log
503
+ scaling. Non-positive values collapse to the axis floor, and
504
+ `valueMin <= 0` is ignored. With `layout="stacked"`, individual segment
505
+ sizes are no longer proportional to their raw values, but the cumulative
506
+ top still represents the sum.
507
+
508
+ <ComponentDemo>
509
+ <BarChart
510
+ :data="[3, 24, 180, 1450, 9800]"
511
+ :categories="['Wk1', 'Wk2', 'Wk3', 'Wk4', 'Wk5']"
512
+ value-scale-type="log"
513
+ :height="220"
514
+ x-label="Week"
515
+ y-label="Cases"
516
+ />
517
+
518
+ <template #code>
519
+
520
+ ```vue
521
+ <BarChart
522
+ :data="[3, 24, 180, 1450, 9800]"
523
+ :categories="['Wk1', 'Wk2', 'Wk3', 'Wk4', 'Wk5']"
524
+ value-scale-type="log"
525
+ :height="220"
526
+ x-label="Week"
527
+ y-label="Cases"
528
+ />
529
+ ```
530
+
531
+ </template>
532
+ </ComponentDemo>
533
+
534
+ ### Summary line overlay
535
+
536
+ Layer a curve (KDE, rolling mean, target) on top of the bars with
537
+ `summary-lines`. Each line scales to **its own value extent** —
538
+ independent of the bar axis — so a probability-density curve in
539
+ `[0, 0.02]` and a histogram in `[0, 500]` can share the same chart.
540
+
541
+ <ComponentDemo>
542
+ <BarChart
543
+ :data="[3, 5, 8, 12, 18, 24, 31, 27, 22, 16, 11, 7, 4, 2]"
544
+ :categories="['2.11', '2.33', '2.56', '2.78', '3.00', '3.22', '3.44', '3.67', '3.89', '4.11', '4.33', '4.56', '4.78', '5.00']"
545
+ :summary-lines="[
546
+ {
547
+ data: [0.05, 0.10, 0.20, 0.40, 0.75, 1.10, 1.32, 1.20, 0.92, 0.60, 0.32, 0.16, 0.07, 0.03],
548
+ color: '#ef4444',
549
+ strokeWidth: 2,
550
+ legend: 'KDE',
551
+ },
552
+ ]"
553
+ :width="380"
554
+ :height="240"
555
+ x-label="R₀"
556
+ y-label="Frequency"
557
+ />
558
+
559
+ <template #code>
560
+
561
+ ```vue
562
+ <BarChart
563
+ :data="[3, 5, 8, 12, 18, 24, 31, 27, 22, 16, 11, 7, 4, 2]"
564
+ :categories="[
565
+ '2.11',
566
+ '2.33',
567
+ '2.56',
568
+ '2.78',
569
+ '3.00',
570
+ '3.22',
571
+ '3.44',
572
+ '3.67',
573
+ '3.89',
574
+ '4.11',
575
+ '4.33',
576
+ '4.56',
577
+ '4.78',
578
+ '5.00',
579
+ ]"
580
+ :summary-lines="[
581
+ {
582
+ data: [
583
+ 0.05, 0.1, 0.2, 0.4, 0.75, 1.1, 1.32, 1.2, 0.92, 0.6, 0.32, 0.16, 0.07,
584
+ 0.03,
585
+ ],
586
+ color: '#ef4444',
587
+ strokeWidth: 2,
588
+ legend: 'KDE',
589
+ },
590
+ ]"
591
+ :height="240"
592
+ x-label="R₀"
593
+ y-label="Frequency"
594
+ />
595
+ ```
596
+
597
+ </template>
598
+ </ComponentDemo>
599
+
600
+ Each line accepts `color`, `strokeWidth`, `dashed`, `opacity`,
601
+ `blendMode`, `dots`, and `dotRadius` for styling — same vocabulary as
602
+ `LineChart` series (both extend `LineMarkStyle`). Override the line's
603
+ extent with `valueMin` / `valueMax`. Pass `x: number[]` (in
604
+ category-index space — `0` is the first category center, fractional
605
+ values land between) to plot at custom positions; useful when the
606
+ summary samples are denser or sparser than the histogram bins.
607
+
608
+ ### Annotations
609
+
610
+ Pin callouts to specific bars with `annotations`. `x` is the category
611
+ index (fractional values land between categories — e.g. `x: 1.5` sits at
612
+ the boundary between categories 1 and 2). `y` is on the value axis. See
613
+ [`LineChart` → Annotations](./line-chart#annotations) for the full
614
+ `ChartAnnotation` shape.
615
+
616
+ <ComponentDemo>
617
+ <BarChart
618
+ :data="[12, 19, 7, 24, 16]"
619
+ :categories="['Mon', 'Tue', 'Wed', 'Thu', 'Fri']"
620
+ :annotations="[
621
+ { x: 3, y: 24, offset: { x: 18, y: -22 }, text: 'Peak day' },
622
+ ]"
623
+ :chart-padding="{ top: 32, right: 32 }"
624
+ :height="240"
625
+ x-label="Day"
626
+ y-label="Cases"
627
+ />
628
+
629
+ <template #code>
630
+
631
+ ```vue
632
+ <BarChart
633
+ :data="[12, 19, 7, 24, 16]"
634
+ :categories="['Mon', 'Tue', 'Wed', 'Thu', 'Fri']"
635
+ :annotations="[{ x: 3, y: 24, offset: { x: 18, y: -22 }, text: 'Peak day' }]"
636
+ :chart-padding="{ top: 32, right: 32 }"
637
+ :height="240"
638
+ x-label="Day"
639
+ y-label="Cases"
640
+ />
641
+ ```
642
+
643
+ </template>
644
+ </ComponentDemo>
645
+
646
+ `chart-padding` reserves extra space outside the plot so the annotation
647
+ label and pointer don't get clipped by the data area. Pass a number for
648
+ uniform padding or an object with `top` / `right` / `bottom` / `left`.
649
+
650
+ Set `pointer` to a rule value (`"ruleX"`, `"ruleY"`, `"ruleUp"`,
651
+ `"ruleDown"`, `"ruleFromLeft"`, `"ruleFromRight"`) to draw a line
652
+ through the anchor instead of the default curved connector. The first
653
+ two span the full plot; the latter four extend from one edge to the
654
+ anchor. `lineColor`, `lineWidth`, and `lineDash` style the line.
655
+
656
+ <ComponentDemo>
657
+ <BarChart
658
+ :data="[12, 19, 7, 24, 16]"
659
+ :categories="['Mon', 'Tue', 'Wed', 'Thu', 'Fri']"
660
+ :annotations="[
661
+ {
662
+ x: 0,
663
+ y: 15.6,
664
+ offset: { x: 6, y: -6 },
665
+ text: 'Avg 15.6',
666
+ pointer: 'ruleY',
667
+ lineDash: '4 3',
668
+ },
669
+ {
670
+ x: 3,
671
+ y: 20,
672
+ offset: { x: 8, y: 4 },
673
+ text: 'Target hit',
674
+ pointer: 'ruleFromLeft',
675
+ lineColor: '#0a7',
676
+ },
677
+ ]"
678
+ :chart-padding="{ top: 24, right: 24 }"
679
+ :height="240"
680
+ x-label="Day"
681
+ y-label="Cases"
682
+ />
683
+
684
+ <template #code>
685
+
686
+ ```vue
687
+ <BarChart
688
+ :data="[12, 19, 7, 24, 16]"
689
+ :categories="['Mon', 'Tue', 'Wed', 'Thu', 'Fri']"
690
+ :annotations="[
691
+ {
692
+ x: 0,
693
+ y: 15.6,
694
+ offset: { x: 6, y: -6 },
695
+ text: 'Avg 15.6',
696
+ pointer: 'ruleY',
697
+ lineDash: '4 3',
698
+ },
699
+ {
700
+ x: 3,
701
+ y: 20,
702
+ offset: { x: 8, y: 4 },
703
+ text: 'Target hit',
704
+ pointer: 'ruleFromLeft',
705
+ lineColor: '#0a7',
706
+ },
707
+ ]"
708
+ :chart-padding="{ top: 24, right: 24 }"
709
+ :height="240"
710
+ x-label="Day"
711
+ y-label="Cases"
712
+ />
713
+ ```
714
+
715
+ </template>
716
+ </ComponentDemo>
717
+
718
+ ## Accessibility
719
+
720
+ The chart's `<svg>` is exposed as a single labeled image so screen readers
721
+ announce one accessible name instead of wandering through the individual bars.
722
+ When the chart has a `title`, the `<svg>` gets `role="img"` and an `aria-label`
723
+ set to the title. The menu and download controls live outside the `<svg>`, so
724
+ they stay reachable regardless.
725
+
726
+ Set `ariaLabel` to give screen readers a fuller summary than the visible title
727
+ (it overrides `title` for the accessible name only):
728
+
729
+ ```vue
730
+ <BarChart
731
+ :data="cases"
732
+ :categories="regions"
733
+ title="Cases by region"
734
+ aria-label="Cases by region: North 120, South 80, West 45"
735
+ />
736
+ ```
737
+
738
+ Pass `role` to override the default `"img"` (e.g. `role="figure"`, or a role of
739
+ your own).
740
+
741
+ ## API
742
+
743
+ <!-- @include: ./_api/bar-chart.md -->