@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,1267 @@
1
+ # LineChart
2
+
3
+ A responsive SVG line chart with support for multiple series, axis labels, and custom styling.
4
+
5
+ ## Examples
6
+
7
+ ### Single series
8
+
9
+ <ComponentDemo>
10
+ <LineChart :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]" :height="200" x-label="Days" y-label="Cases" tooltip-trigger="hover" />
11
+
12
+ <template #code>
13
+
14
+ ```vue
15
+ <LineChart
16
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
17
+ :height="200"
18
+ x-label="Days"
19
+ y-label="Cases"
20
+ tooltip-trigger="hover"
21
+ />
22
+ ```
23
+
24
+ </template>
25
+ </ComponentDemo>
26
+
27
+ ### x/y
28
+
29
+ Pass paired `x` and `y` arrays to plot points at specific x positions.
30
+ `y` is equivalent to `data` (both names are accepted), and they both
31
+ take typed arrays. For multi-series
32
+ charts, set `x` and `y` (or `data`) on each `Series`.
33
+
34
+ <ComponentDemo>
35
+ <LineChart
36
+ :x="[0, 1, 2, 5, 10, 20, 50]"
37
+ :y="[0, 2, 5, 12, 22, 30, 38]"
38
+ :height="200"
39
+ x-label="Days (log-ish)"
40
+ y-label="Cases"
41
+ tooltip-trigger="hover"
42
+ />
43
+
44
+ <template #code>
45
+
46
+ ```vue
47
+ <LineChart
48
+ :x="[0, 1, 2, 5, 10, 20, 50]"
49
+ :y="[0, 2, 5, 12, 22, 30, 38]"
50
+ :height="200"
51
+ x-label="Days"
52
+ y-label="Cases"
53
+ tooltip-trigger="hover"
54
+ />
55
+ ```
56
+
57
+ </template>
58
+ </ComponentDemo>
59
+
60
+ When `x` is omitted, `y`/`data` values are plotted at indices 0, 1, 2, etc.
61
+
62
+ ### Dates
63
+
64
+ Pass ISO date strings (`YYYY-MM-DD`) or `Date` objects as `x` and the
65
+ chart auto-detects a date axis: ticks anchor to year / month / week /
66
+ day / hour boundaries depending on the visible range, and labels
67
+ format themselves accordingly. Numeric `x` arrays keep their existing
68
+ behavior — auto-detection is content-driven and never promotes plain
69
+ numbers.
70
+
71
+ <ComponentDemo>
72
+ <LineChart
73
+ :x="['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']"
74
+ :y="[4, 9, 18, 32, 41, 38, 27, 18, 11, 6]"
75
+ :height="220"
76
+ y-label="% ED visits"
77
+ />
78
+
79
+ <template #code>
80
+
81
+ ```vue
82
+ <LineChart
83
+ :x="[
84
+ '2026-01-05',
85
+ '2026-01-12',
86
+ '2026-01-19',
87
+ '2026-01-26',
88
+ '2026-02-02',
89
+ '2026-02-09',
90
+ '2026-02-16',
91
+ '2026-02-23',
92
+ '2026-03-02',
93
+ '2026-03-09',
94
+ ]"
95
+ :y="[4, 9, 18, 32, 41, 38, 27, 18, 11, 6]"
96
+ :height="220"
97
+ y-label="% ED visits"
98
+ />
99
+ ```
100
+
101
+ </template>
102
+ </ComponentDemo>
103
+
104
+ Override the format via `x-tick-format`. Presets: `"iso"`,
105
+ `"iso-datetime"`, `"year"`, `"month-year"`, `"month-day"`, `"day"`,
106
+ `"time"`, `"datetime"`, `"medium"`. You can also pass an
107
+ `Intl.DateTimeFormatOptions` literal, or a function `(ms, unit?) =>
108
+ string` for full control.
109
+
110
+ <ComponentDemo>
111
+ <LineChart
112
+ :x="['2026-01-05', '2026-01-12', '2026-01-19', '2026-01-26', '2026-02-02']"
113
+ :y="[4, 9, 18, 32, 41]"
114
+ x-tick-format="iso"
115
+ :height="220"
116
+ y-label="% ED visits"
117
+ />
118
+
119
+ <template #code>
120
+
121
+ ```vue
122
+ <LineChart
123
+ :x="['2026-01-05', '2026-01-12', '2026-01-19', '2026-01-26', '2026-02-02']"
124
+ :y="[4, 9, 18, 32, 41]"
125
+ x-tick-format="iso"
126
+ :height="220"
127
+ y-label="% ED visits"
128
+ />
129
+ ```
130
+
131
+ </template>
132
+ </ComponentDemo>
133
+
134
+ By default the chart parses bare `YYYY-MM-DD` (and offset-less
135
+ `YYYY-MM-DDTHH:mm:ss`) as UTC and renders tick labels in UTC. Set
136
+ `timezone="local"` to interpret offset-less strings in the browser's
137
+ timezone instead. Strings that include an explicit offset (`Z` or
138
+ `+05:00`) are always parsed exactly as written.
139
+
140
+ > **Annotations on a date axis.** `ChartAnnotation.x` is always in the
141
+ > chart's resolved coordinate space — that's **epoch-ms** when the axis
142
+ > is in date mode. Pass `Date.UTC(2026, 0, 15)`, `new Date("2026-01-15").getTime()`,
143
+ > or `Date.parse("2026-01-15T00:00:00Z")`. Passing a small integer like
144
+ > `0` will place the annotation at 1970-01-01 (off-screen).
145
+ >
146
+ > **`xLabels` on a date axis.** When both `x: [...date strings]` and
147
+ > `xLabels` are supplied, the date axis wins — `xLabels` is ignored.
148
+ > Date strings carry their own labeling.
149
+
150
+ ### Title
151
+
152
+ The `title` prop accepts `\n` to break across lines. Use `titleStyle`
153
+ to override `fontSize`, `lineHeight`, `color`, `fontWeight`, and
154
+ `align` (`"left" | "center" | "right"`, default `"left"`). Top padding
155
+ grows automatically for additional lines.
156
+
157
+ <ComponentDemo>
158
+ <LineChart
159
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
160
+ :height="220"
161
+ :title="'Daily ED visits\nInfluenza-like illness, last 11 days'"
162
+ :title-style="{ fontSize: 16, lineHeight: 20, color: '#0057b7' }"
163
+ x-label="Days"
164
+ y-label="Cases"
165
+ />
166
+
167
+ <template #code>
168
+
169
+ ```vue
170
+ <LineChart
171
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
172
+ :height="220"
173
+ :title="'Daily ED visits\nInfluenza-like illness, last 11 days'"
174
+ :title-style="{ fontSize: 16, lineHeight: 20, color: '#0057b7' }"
175
+ x-label="Days"
176
+ y-label="Cases"
177
+ />
178
+ ```
179
+
180
+ </template>
181
+ </ComponentDemo>
182
+
183
+ ### Font sizes
184
+
185
+ Every text element on the chart has its own style prop and default size (in px). The text-styling props (`axisLabelStyle`, `tickLabelStyle`, `legendStyle`) take a `LabelStyle` — `{ fontSize?, color?, fontWeight? }` — and `titleStyle` adds `lineHeight` and `align`. Unset fields fall back to the defaults below.
186
+
187
+ | Chart part | Prop / field | Type | Default size |
188
+ | ------------------------------------------- | ------------------------------------ | ------------ | -----------: |
189
+ | Title | `titleStyle` | `TitleStyle` | 14 |
190
+ | Axis labels (`xLabel` / `yLabel`) | `axisLabelStyle` | `LabelStyle` | 13 |
191
+ | Axis tick labels (the numbers on each axis) | `tickLabelStyle` | `LabelStyle` | 10 |
192
+ | Inline legend | `legendStyle` | `LabelStyle` | 11 |
193
+ | Area section label | `areaSection.inlineLabelStyle` | `LabelStyle` | 11 |
194
+ | Area section description | `areaSection.inlineDescriptionStyle` | `LabelStyle` | 11 |
195
+ | Annotation text | `annotation.fontSize` | `number` | 13 |
196
+
197
+ These are single styles applied to both axes — there's no separate x vs y font size. The same props (except the LineChart-only area-section fields) exist on `BarChart`, since both compose `ChartCommonProps`.
198
+
199
+ <ComponentDemo>
200
+ <LineChart
201
+ :series="[
202
+ { data: [0, 12, 28, 45, 60, 55, 40, 25, 12], color: '#0057b7', legend: 'No interventions' },
203
+ { data: [0, 8, 18, 30, 40, 35, 25, 14, 6], color: '#ef4444', legend: 'Masking + distancing' },
204
+ ]"
205
+ :height="240"
206
+ title="Daily ED visits"
207
+ x-label="Days"
208
+ y-label="Cases"
209
+ :title-style="{ fontSize: 18 }"
210
+ :axis-label-style="{ fontSize: 15, fontWeight: 700 }"
211
+ :tick-label-style="{ fontSize: 13 }"
212
+ :legend-style="{ fontSize: 14 }"
213
+ />
214
+
215
+ <template #code>
216
+
217
+ ```vue
218
+ <LineChart
219
+ :series="[
220
+ {
221
+ data: [0, 12, 28, 45, 60, 55, 40, 25, 12],
222
+ color: '#0057b7',
223
+ legend: 'No interventions',
224
+ },
225
+ {
226
+ data: [0, 8, 18, 30, 40, 35, 25, 14, 6],
227
+ color: '#ef4444',
228
+ legend: 'Masking + distancing',
229
+ },
230
+ ]"
231
+ :height="240"
232
+ title="Daily ED visits"
233
+ x-label="Days"
234
+ y-label="Cases"
235
+ :title-style="{ fontSize: 18 }"
236
+ :axis-label-style="{ fontSize: 15, fontWeight: 700 }"
237
+ :tick-label-style="{ fontSize: 13 }"
238
+ :legend-style="{ fontSize: 14 }"
239
+ />
240
+ ```
241
+
242
+ </template>
243
+ </ComponentDemo>
244
+
245
+ ### Multiple series
246
+
247
+ <ComponentDemo>
248
+ <LineChart
249
+ :series="[
250
+ { data: [0, 10, 25, 45, 60, 55, 40, 20, 8], color: '#fb7e38', strokeWidth: 3 },
251
+ { x: [0, 1, 3, 4, 6, 7, 8], y: [0, 5, 20, 28, 18, 10, 4], color: '#0057b7', strokeWidth: 3 },
252
+ ]"
253
+ :height="200"
254
+ x-label="Weeks"
255
+ y-label="Incidence"
256
+ />
257
+
258
+ <template #code>
259
+
260
+ ```vue
261
+ <LineChart
262
+ :series="[
263
+ {
264
+ data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
265
+ color: '#fb7e38',
266
+ strokeWidth: 3,
267
+ },
268
+ {
269
+ x: [0, 1, 3, 4, 6, 7, 8],
270
+ y: [0, 5, 20, 28, 18, 10, 4],
271
+ color: '#0057b7',
272
+ strokeWidth: 3,
273
+ },
274
+ ]"
275
+ :height="200"
276
+ x-label="Weeks"
277
+ y-label="Incidence"
278
+ />
279
+ ```
280
+
281
+ </template>
282
+ </ComponentDemo>
283
+
284
+ ### Legend
285
+
286
+ Set `legend` on a series to add an entry to the inline legend strip above the plot. When the items don't all fit on one row at the chart's current width, the legend wraps to additional rows and the plot area shrinks to keep the legend clear of the data. Use `showInLegend: false` to keep a series off the legend (e.g. when its `legend` string is reused as a CSV column header) and `showInTooltip: false` to omit it from the hover tooltip.
287
+
288
+ <ComponentDemo>
289
+ <LineChart
290
+ :series="[
291
+ { data: [0, 12, 28, 45, 60, 55, 40, 25, 12], color: '#0057b7', legend: 'No interventions' },
292
+ { data: [0, 10, 22, 38, 50, 45, 32, 18, 8], color: '#fb7e38', legend: 'School closures' },
293
+ { data: [0, 8, 18, 30, 40, 35, 25, 14, 6], color: '#ef4444', legend: 'Masking + distancing' },
294
+ { data: [0, 6, 14, 24, 32, 28, 20, 10, 4], color: '#10b981', legend: 'Vaccination only' },
295
+ { data: [0, 4, 10, 16, 22, 19, 13, 7, 3], color: '#6366f1', legend: 'Vaccination + masking' },
296
+ { data: [0, 3, 7, 11, 15, 13, 9, 5, 2], color: '#a855f7', legend: 'All interventions combined' },
297
+ ]"
298
+ :height="240"
299
+ x-label="Weeks"
300
+ y-label="Incidence"
301
+ />
302
+
303
+ <template #code>
304
+
305
+ ```vue
306
+ <LineChart
307
+ :series="[
308
+ { data: scenarioA, color: '#0057b7', legend: 'No interventions' },
309
+ { data: scenarioB, color: '#fb7e38', legend: 'School closures' },
310
+ { data: scenarioC, color: '#ef4444', legend: 'Masking + distancing' },
311
+ { data: scenarioD, color: '#10b981', legend: 'Vaccination only' },
312
+ { data: scenarioE, color: '#6366f1', legend: 'Vaccination + masking' },
313
+ { data: scenarioF, color: '#a855f7', legend: 'All interventions combined' },
314
+ ]"
315
+ :height="240"
316
+ x-label="Weeks"
317
+ y-label="Incidence"
318
+ />
319
+ ```
320
+
321
+ </template>
322
+ </ComponentDemo>
323
+
324
+ ### Tooltip
325
+
326
+ Hover over the chart to see a tooltip with values at each data point. Set `tooltip-trigger="hover"` to enable the built-in tooltip with crosshair and highlight dots. Use the `#tooltip` slot for custom content. Pass `tooltip-value-format` to control how numeric values render (e.g. percentages, currency); it falls back to `y-tick-format` when omitted.
327
+
328
+ On touch devices, drag **horizontally** across the chart to scrub the tooltip between points; a **vertical** swipe scrolls the page instead of getting captured by the chart.
329
+
330
+ <ComponentDemo>
331
+ <LineChart
332
+ :series="[
333
+ { data: [0, 10, 25, 45, 60, 55, 40, 20, 8], color: '#fb7e38', strokeWidth: 3 },
334
+ { data: [0, 5, 12, 20, 28, 25, 18, 10, 4], color: '#0057b7', strokeWidth: 3 },
335
+ ]"
336
+ :x-tick-format="(_, i) => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'][i]"
337
+ :height="200"
338
+ x-label="Month"
339
+ y-label="Incidence"
340
+ tooltip-trigger="hover"
341
+ />
342
+
343
+ <template #code>
344
+
345
+ ```vue
346
+ <LineChart
347
+ :series="[
348
+ {
349
+ data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
350
+ color: '#fb7e38',
351
+ strokeWidth: 3,
352
+ },
353
+ {
354
+ data: [0, 5, 12, 20, 28, 25, 18, 10, 4],
355
+ color: '#0057b7',
356
+ strokeWidth: 3,
357
+ },
358
+ ]"
359
+ :x-tick-format="(_, i) => months[i]"
360
+ :height="200"
361
+ x-label="Month"
362
+ y-label="Incidence"
363
+ tooltip-trigger="hover"
364
+ />
365
+ ```
366
+
367
+ </template>
368
+ </ComponentDemo>
369
+
370
+ ### Custom axis ticks
371
+
372
+ Control tick placement with `x-ticks` and `y-ticks`. Pass a **number** for a fixed interval (in data units, respecting `xMin`) or an **array** of explicit values. Use `x-tick-format` / `y-tick-format` to customize labels.
373
+
374
+ <ComponentDemo>
375
+ <LineChart
376
+ :data="[0, 0.12, 0.28, 0.45, 0.61, 0.74, 0.83, 0.89, 0.93, 0.96, 0.97, 0.98, 0.99, 0.99, 1.0]"
377
+ :x-ticks="7"
378
+ :y-ticks="[0, 0.5, 1]"
379
+ :y-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
380
+ :x-tick-format="(v) => `day ${v}`"
381
+ :height="220"
382
+ x-label="Time"
383
+ y-label="Coverage"
384
+ x-grid
385
+ y-grid
386
+ />
387
+
388
+ <template #code>
389
+
390
+ ```vue
391
+ <LineChart
392
+ :data="coverage"
393
+ :x-ticks="7"
394
+ :y-ticks="[0, 0.5, 1]"
395
+ :y-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
396
+ :x-tick-format="(v) => `day ${v}`"
397
+ :height="220"
398
+ x-label="Time"
399
+ y-label="Coverage"
400
+ x-grid
401
+ y-grid
402
+ />
403
+ ```
404
+
405
+ </template>
406
+ </ComponentDemo>
407
+
408
+ ### Logarithmic y-axis
409
+
410
+ Set `y-scale-type="log"` to switch the y axis to base-10 log scaling. Useful
411
+ when data spans several orders of magnitude (e.g. epidemic case counts in
412
+ early exponential growth). Non-positive values collapse to the axis
413
+ floor, and `yMin <= 0` is ignored.
414
+
415
+ <ComponentDemo>
416
+ <LineChart
417
+ :data="[1, 3, 8, 22, 60, 165, 450, 1230, 3350]"
418
+ y-scale-type="log"
419
+ :height="220"
420
+ x-label="Day"
421
+ y-label="Cases"
422
+ y-grid
423
+ />
424
+
425
+ <template #code>
426
+
427
+ ```vue
428
+ <LineChart
429
+ :data="[1, 3, 8, 22, 60, 165, 450, 1230, 3350]"
430
+ y-scale-type="log"
431
+ :height="220"
432
+ x-label="Day"
433
+ y-label="Cases"
434
+ y-grid
435
+ />
436
+ ```
437
+
438
+ </template>
439
+ </ComponentDemo>
440
+
441
+ ### Dashed baseline
442
+
443
+ <ComponentDemo>
444
+ <LineChart
445
+ :series="[
446
+ { data: [0, 10, 25, 45, 60, 55, 40, 20, 8], color: '#999', dashed: true, strokeWidth: 2 },
447
+ { data: [0, 5, 12, 20, 28, 25, 18, 10, 4], color: '#2563eb', strokeWidth: 2 },
448
+ ]"
449
+ :height="200"
450
+ />
451
+
452
+ <template #code>
453
+
454
+ ```vue
455
+ <LineChart
456
+ :series="[
457
+ {
458
+ data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
459
+ color: '#999',
460
+ dashed: true,
461
+ strokeWidth: 2,
462
+ },
463
+ {
464
+ data: [0, 5, 12, 20, 28, 25, 18, 10, 4],
465
+ color: '#2563eb',
466
+ strokeWidth: 2,
467
+ },
468
+ ]"
469
+ :height="200"
470
+ />
471
+ ```
472
+
473
+ </template>
474
+ </ComponentDemo>
475
+
476
+ ### Outline
477
+
478
+ Set `outline: true` on a series to draw a page-colored stroke behind the
479
+ line. This is useful when lines overlap, cross dense areas, or sit on a
480
+ busy background — the outline keeps each series visually distinct.
481
+
482
+ Override the outline's color with `outlineColor` (any CSS color; defaults
483
+ to the page background `var(--color-bg-0, #fff)`) and its thickness with
484
+ `outlineWidth` (extra width added to the line's `strokeWidth`, split evenly
485
+ per side; defaults to `4`).
486
+
487
+ <ComponentDemo>
488
+ <LineChart
489
+ :series="[
490
+ { data: [0, 10, 25, 45, 60, 55, 40, 20, 8], color: '#fb7e38', strokeWidth: 3, outline: true },
491
+ { data: [0, 12, 22, 40, 58, 58, 42, 22, 10], color: '#0057b7', strokeWidth: 3, outline: true },
492
+ ]"
493
+ :height="200"
494
+ />
495
+
496
+ <template #code>
497
+
498
+ ```vue
499
+ <LineChart
500
+ :series="[
501
+ {
502
+ data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
503
+ color: '#fb7e38',
504
+ strokeWidth: 3,
505
+ outline: true,
506
+ },
507
+ {
508
+ data: [0, 12, 22, 40, 58, 58, 42, 22, 10],
509
+ color: '#0057b7',
510
+ strokeWidth: 3,
511
+ outline: true,
512
+ },
513
+ ]"
514
+ :height="200"
515
+ />
516
+ ```
517
+
518
+ </template>
519
+ </ComponentDemo>
520
+
521
+ ### Many trajectories with low opacity
522
+
523
+ <ComponentDemo>
524
+ <LineChart
525
+ :series="Array.from({ length: 20 }, (_, i) => ({
526
+ data: Array.from({ length: 50 }, (_, t) => Math.max(0, 30 * Math.sin(t / 8) + (Math.random() - 0.5) * 15 + i * 0.5)),
527
+ color: '#0057b7',
528
+ }))"
529
+ :height="250"
530
+ :line-opacity="0.15"
531
+ x-label="Days"
532
+ y-label="Incidence"
533
+ />
534
+
535
+ <template #code>
536
+
537
+ ```vue
538
+ <LineChart
539
+ :series="trajectories"
540
+ :height="250"
541
+ :line-opacity="0.15"
542
+ x-label="Days"
543
+ y-label="Incidence"
544
+ />
545
+ ```
546
+
547
+ </template>
548
+ </ComponentDemo>
549
+
550
+ ### Blend mode
551
+
552
+ Set `blendMode` on a `Series` to apply a CSS `mix-blend-mode` to that
553
+ series' line (and dots, if enabled). Useful when two thick or
554
+ high-contrast lines overlap — `"multiply"` darkens the crossing point
555
+ on light backgrounds, `"screen"` lightens on dark, `"difference"`
556
+ inverts. The white `outline`, if any, is unaffected.
557
+
558
+ <ComponentDemo>
559
+ <LineChart
560
+ :series="[
561
+ {
562
+ data: Array.from({ length: 30 }, (_, t) => 20 + 15 * Math.sin(t / 4)),
563
+ color: '#ef4444',
564
+ strokeWidth: 3,
565
+ blendMode: 'multiply',
566
+ legend: 'Strain A',
567
+ },
568
+ {
569
+ data: Array.from({ length: 30 }, (_, t) => 20 + 15 * Math.cos(t / 4)),
570
+ color: '#3b82f6',
571
+ strokeWidth: 3,
572
+ blendMode: 'multiply',
573
+ legend: 'Strain B',
574
+ },
575
+ ]"
576
+ :height="240"
577
+ x-label="Day"
578
+ y-label="Incidence"
579
+ />
580
+
581
+ <template #code>
582
+
583
+ ```vue
584
+ <LineChart
585
+ :series="[
586
+ {
587
+ data: strainA,
588
+ color: '#ef4444',
589
+ strokeWidth: 3,
590
+ blendMode: 'multiply',
591
+ legend: 'Strain A',
592
+ },
593
+ {
594
+ data: strainB,
595
+ color: '#3b82f6',
596
+ strokeWidth: 3,
597
+ blendMode: 'multiply',
598
+ legend: 'Strain B',
599
+ },
600
+ ]"
601
+ :height="240"
602
+ x-label="Day"
603
+ y-label="Incidence"
604
+ />
605
+ ```
606
+
607
+ </template>
608
+ </ComponentDemo>
609
+
610
+ ### Grid lines
611
+
612
+ <ComponentDemo>
613
+ <LineChart
614
+ :series="[
615
+ { data: [0, 10, 25, 45, 60, 55, 40, 20, 8], color: '#fb7e38', strokeWidth: 3 },
616
+ { data: [0, 5, 12, 20, 28, 25, 18, 10, 4], color: '#0057b7', strokeWidth: 3 },
617
+ ]"
618
+ :height="200"
619
+ x-label="Weeks"
620
+ y-label="Incidence"
621
+ x-grid
622
+ y-grid
623
+ />
624
+
625
+ <template #code>
626
+
627
+ ```vue
628
+ <LineChart
629
+ :series="[
630
+ {
631
+ data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
632
+ color: '#fb7e38',
633
+ strokeWidth: 3,
634
+ },
635
+ {
636
+ data: [0, 5, 12, 20, 28, 25, 18, 10, 4],
637
+ color: '#0057b7',
638
+ strokeWidth: 3,
639
+ },
640
+ ]"
641
+ :height="200"
642
+ x-label="Weeks"
643
+ y-label="Incidence"
644
+ x-grid
645
+ y-grid
646
+ />
647
+ ```
648
+
649
+ </template>
650
+ </ComponentDemo>
651
+
652
+ ### Dots
653
+
654
+ <ComponentDemo>
655
+ <LineChart
656
+ :series="[
657
+ { data: [0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2], color: '#0057b7', strokeWidth: 2, dots: true, dotRadius: 4, dotFill: '#fff', dotStroke: '#0057b7' },
658
+ ]"
659
+ :height="200"
660
+ x-label="Days"
661
+ y-label="Cases"
662
+ />
663
+
664
+ <template #code>
665
+
666
+ ```vue
667
+ <LineChart
668
+ :series="[
669
+ {
670
+ data: [0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2],
671
+ color: '#0057b7',
672
+ strokeWidth: 2,
673
+ dots: true,
674
+ dotRadius: 4,
675
+ dotFill: '#fff',
676
+ dotStroke: '#0057b7',
677
+ },
678
+ ]"
679
+ :height="200"
680
+ x-label="Days"
681
+ y-label="Cases"
682
+ />
683
+ ```
684
+
685
+ </template>
686
+ </ComponentDemo>
687
+
688
+ ### Confidence band
689
+
690
+ Use the `areas` prop to fill a band between two y-series — useful for
691
+ confidence intervals or min/max envelopes around a mean line. Each `Area`
692
+ takes parallel `upper` and `lower` arrays (and an optional `x` array, just
693
+ like `Series`). Set `legend` on an `Area` to include the band in the inline
694
+ legend; use `showInLegend: false` to hide a legend label without removing
695
+ the field from shared config. Set `blendMode` on an `Area` to apply a CSS
696
+ `mix-blend-mode` to its fill so overlapping bands combine their colors
697
+ (e.g. `"multiply"`) instead of the later one obscuring the earlier.
698
+
699
+ <ComponentDemo>
700
+ <LineChart
701
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
702
+ :areas="[
703
+ {
704
+ upper: [2, 8, 14, 22, 30, 38, 36, 28, 19, 11, 7],
705
+ lower: [0, 1, 3, 9, 15, 22, 21, 13, 6, 1, 0],
706
+ color: '#0057b7',
707
+ opacity: 0.15,
708
+ legend: '95% interval',
709
+ },
710
+ ]"
711
+ :height="220"
712
+ x-label="Days"
713
+ y-label="Cases"
714
+ tooltip-trigger="hover"
715
+ />
716
+
717
+ <template #code>
718
+
719
+ ```vue
720
+ <LineChart
721
+ :data="mean"
722
+ :areas="[
723
+ {
724
+ upper: ci95Hi,
725
+ lower: ci95Lo,
726
+ color: '#0057b7',
727
+ opacity: 0.15,
728
+ legend: '95% interval',
729
+ },
730
+ ]"
731
+ :height="220"
732
+ x-label="Days"
733
+ y-label="Cases"
734
+ tooltip-trigger="hover"
735
+ />
736
+ ```
737
+
738
+ </template>
739
+ </ComponentDemo>
740
+
741
+ ### Area sections
742
+
743
+ Highlight a range of a series line by filling the area between the line and the x-axis. Labels are rendered below the chart and automatically stack when they overlap.
744
+
745
+ <ComponentDemo>
746
+ <LineChart
747
+ :series="[
748
+ { data: [0, 2, 5, 12, 25, 45, 70, 100, 130, 155, 170], color: '#000', strokeWidth: 1, legend: 'No interventions' },
749
+ { data: [0, 0, 0, 2, 8, 20, 40, 65, 90, 110, 120], color: '#999', strokeWidth: 1, dashed: true, legend: 'Interventions' },
750
+ ]"
751
+ :area-sections="[
752
+ { startIndex: 2, endIndex: 7, color: '#6366f1', strokeWidth: 0, legend: 'inline', label: 'Day 2–7', description: 'Rapid growth phase' },
753
+ { seriesIndex: 0, startIndex: 5, endIndex: 9, color: '#f43f5e', label: 'Day 5–9', description: 'Mitigation period' },
754
+ ]"
755
+ :height="250"
756
+ x-label="Days"
757
+ y-label="Cumulative count"
758
+ tooltip-trigger="hover"
759
+ :menu="false"
760
+ />
761
+
762
+ <template #code>
763
+
764
+ ```vue
765
+ <LineChart
766
+ :series="[
767
+ {
768
+ data: [0, 2, 5, 12, 25, 45, 70, 100, 130, 155, 170],
769
+ color: '#000',
770
+ strokeWidth: 1,
771
+ legend: 'No interventions',
772
+ },
773
+ {
774
+ data: [0, 0, 0, 2, 8, 20, 40, 65, 90, 110, 120],
775
+ color: '#999',
776
+ strokeWidth: 1,
777
+ dashed: true,
778
+ legend: 'Interventions',
779
+ },
780
+ ]"
781
+ :area-sections="[
782
+ {
783
+ startIndex: 2,
784
+ endIndex: 7,
785
+ color: '#6366f1',
786
+ strokeWidth: 0,
787
+ legend: 'inline',
788
+ label: 'Day 2–7',
789
+ description: 'Rapid growth phase',
790
+ },
791
+ {
792
+ seriesIndex: 0,
793
+ startIndex: 5,
794
+ endIndex: 9,
795
+ color: '#f43f5e',
796
+ label: 'Day 5–9',
797
+ description: 'Mitigation period',
798
+ },
799
+ ]"
800
+ :height="250"
801
+ x-label="Days"
802
+ y-label="Cumulative count"
803
+ tooltip-trigger="hover"
804
+ />
805
+ ```
806
+
807
+ </template>
808
+ </ComponentDemo>
809
+
810
+ ### Annotations
811
+
812
+ Pin callouts to data points with `annotations`. Each annotation anchors at
813
+ `(x, y)` in data coordinates (the same x-space as the chart axis, so it
814
+ respects `xMin` and explicit `x` values), with a pixel
815
+ `offset: { x, y }` for the label position. Text supports `\n` for line
816
+ breaks. A curved
817
+ pointer line connects the anchor to the label, and the label gets an
818
+ outline stroke matching the background so it stays legible over series
819
+ lines.
820
+
821
+ <ComponentDemo>
822
+ <LineChart
823
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
824
+ :annotations="[
825
+ { x: 5, y: 30, offset: { x: 24, y: -28 }, text: 'Peak\nDay 5' },
826
+ { x: 0, y: 0, offset: { x: 28, y: -22 }, text: 'Onset' },
827
+ ]"
828
+ :chart-padding="{ top: 40, right: 24 }"
829
+ :height="240"
830
+ x-label="Days"
831
+ y-label="Cases"
832
+ />
833
+
834
+ <template #code>
835
+
836
+ ```vue
837
+ <LineChart
838
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
839
+ :annotations="[
840
+ { x: 5, y: 30, offset: { x: 24, y: -28 }, text: 'Peak\nDay 5' },
841
+ { x: 0, y: 0, offset: { x: 28, y: -22 }, text: 'Onset' },
842
+ ]"
843
+ :chart-padding="{ top: 40, right: 24 }"
844
+ :height="240"
845
+ x-label="Days"
846
+ y-label="Cases"
847
+ />
848
+ ```
849
+
850
+ </template>
851
+ </ComponentDemo>
852
+
853
+ Use `chart-padding` to reserve room outside the plot so annotations (or
854
+ any other overlay) don't clip the data area. It accepts a number (same on
855
+ all sides) or an object with `top`, `right`, `bottom`, `left`.
856
+
857
+ Annotation text supports a small set of inline markers:
858
+
859
+ - `**bold**` — bold
860
+ - `_italic_` — italic
861
+ - `\n` — line break
862
+
863
+ Markers compose (`**_bold italic_**`).
864
+
865
+ <ComponentDemo>
866
+ <LineChart
867
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
868
+ :annotations="[
869
+ { x: 5, y: 30, offset: { x: 24, y: -28 }, text: '**Peak**\n_Day 5_' },
870
+ ]"
871
+ :chart-padding="{ top: 40, right: 24 }"
872
+ :height="240"
873
+ x-label="Days"
874
+ y-label="Cases"
875
+ />
876
+
877
+ <template #code>
878
+
879
+ ```vue
880
+ <LineChart
881
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
882
+ :annotations="[
883
+ { x: 5, y: 30, offset: { x: 24, y: -28 }, text: '**Peak**\n_Day 5_' },
884
+ ]"
885
+ :chart-padding="{ top: 40, right: 24 }"
886
+ :height="240"
887
+ x-label="Days"
888
+ y-label="Cases"
889
+ />
890
+ ```
891
+
892
+ </template>
893
+ </ComponentDemo>
894
+
895
+ Multi-line callouts attach to whichever edge of the text faces the anchor:
896
+ text **above** the point connects to its bottom edge, text **below**
897
+ connects to its top, and text to the side connects to its near vertical
898
+ edge — so the pointer never cuts through the lines. The demo below anchors
899
+ the same two-line label at one point and fans it out in every direction.
900
+
901
+ <ComponentDemo>
902
+ <LineChart
903
+ :data="[2, 10, 7, 6, 8, 4, 9]"
904
+ :annotations="[
905
+ { x: 3, y: 6, offset: { x: 0, y: -86 }, text: 'Cluster\ndetected' },
906
+ { x: 3, y: 6, offset: { x: 62, y: -62 }, text: 'Cluster\ndetected' },
907
+ { x: 3, y: 6, offset: { x: 96, y: 0 }, text: 'Cluster\ndetected' },
908
+ { x: 3, y: 6, offset: { x: 62, y: 62 }, text: 'Cluster\ndetected' },
909
+ { x: 3, y: 6, offset: { x: 0, y: 86 }, text: 'Cluster\ndetected' },
910
+ { x: 3, y: 6, offset: { x: -62, y: 62 }, text: 'Cluster\ndetected' },
911
+ { x: 3, y: 6, offset: { x: -96, y: 0 }, text: 'Cluster\ndetected' },
912
+ { x: 3, y: 6, offset: { x: -62, y: -62 }, text: 'Cluster\ndetected' },
913
+ ]"
914
+ :chart-padding="{ top: 70, right: 120, bottom: 50, left: 120 }"
915
+ :height="340"
916
+ x-label="Days"
917
+ y-label="Cases"
918
+ />
919
+
920
+ <template #code>
921
+
922
+ ```vue
923
+ <LineChart
924
+ :data="[2, 10, 7, 6, 8, 4, 9]"
925
+ :annotations="[
926
+ { x: 3, y: 6, offset: { x: 0, y: -86 }, text: 'Cluster\ndetected' },
927
+ { x: 3, y: 6, offset: { x: 62, y: -62 }, text: 'Cluster\ndetected' },
928
+ { x: 3, y: 6, offset: { x: 96, y: 0 }, text: 'Cluster\ndetected' },
929
+ { x: 3, y: 6, offset: { x: 62, y: 62 }, text: 'Cluster\ndetected' },
930
+ { x: 3, y: 6, offset: { x: 0, y: 86 }, text: 'Cluster\ndetected' },
931
+ { x: 3, y: 6, offset: { x: -62, y: 62 }, text: 'Cluster\ndetected' },
932
+ { x: 3, y: 6, offset: { x: -96, y: 0 }, text: 'Cluster\ndetected' },
933
+ { x: 3, y: 6, offset: { x: -62, y: -62 }, text: 'Cluster\ndetected' },
934
+ ]"
935
+ :chart-padding="{ top: 70, right: 120, bottom: 50, left: 120 }"
936
+ :height="340"
937
+ x-label="Days"
938
+ y-label="Cases"
939
+ />
940
+ ```
941
+
942
+ </template>
943
+ </ComponentDemo>
944
+
945
+ ```ts
946
+ interface ChartAnnotation {
947
+ x: number; // anchor in data coords (x-axis)
948
+ y: number; // anchor in data coords (y-axis)
949
+ text: string; // label text; \n produces line breaks
950
+ offset: { x: number; y: number }; // pixel offset from anchor to label
951
+ color?: string; // text / pointer color (default: currentColor)
952
+ fontSize?: number; // default: 13 (matches axis labels)
953
+ fontWeight?: string | number; // default: "normal"
954
+ outlineColor?: string; // background-matched outline (default: var(--color-bg-0, #fff))
955
+ outlineWidth?: number; // default: 3
956
+ align?: "left" | "center" | "right"; // default: derived from offset[0] sign
957
+ lineColor?: string; // connector-line color override (default: color)
958
+ lineWidth?: number; // default: 1
959
+ lineDash?: string | number | readonly number[]; // SVG stroke-dasharray
960
+ // default: "curved"
961
+ // "ruleX" / "ruleY" span the full plot on the named axis;
962
+ // "ruleUp" / "ruleDown" / "ruleFromLeft" / "ruleFromRight" run from an edge to the anchor.
963
+ pointer?:
964
+ | "curved"
965
+ | "straight"
966
+ | "none"
967
+ | "ruleX"
968
+ | "ruleY"
969
+ | "ruleUp"
970
+ | "ruleDown"
971
+ | "ruleFromLeft"
972
+ | "ruleFromRight";
973
+ arrow?: boolean; // triangle marker at the anchor end (default: true)
974
+ }
975
+ ```
976
+
977
+ ### Rules
978
+
979
+ Set `pointer` to one of the rule values to replace the curved /
980
+ straight connector with a straight line through the anchor:
981
+
982
+ - `"ruleX"` — vertical line spanning the plot height at the annotation's `x`.
983
+ - `"ruleY"` — horizontal line spanning the plot width at the annotation's `y`.
984
+ - `"ruleUp"` — vertical from the bottom edge up to the anchor.
985
+ - `"ruleDown"` — vertical from the top edge down to the anchor.
986
+ - `"ruleFromLeft"` — horizontal from the left edge in to the anchor.
987
+ - `"ruleFromRight"` — horizontal from the right edge in to the anchor.
988
+
989
+ `lineColor`, `lineWidth`, and `lineDash` style the line. The label is
990
+ positioned from the anchor as usual via `offset`.
991
+
992
+ <ComponentDemo>
993
+ <LineChart
994
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
995
+ :annotations="[
996
+ {
997
+ x: 5,
998
+ y: 30,
999
+ offset: { x: 8, y: 14 },
1000
+ text: 'Peak',
1001
+ pointer: 'ruleX',
1002
+ lineDash: '4 3',
1003
+ },
1004
+ {
1005
+ x: 5,
1006
+ y: 30,
1007
+ offset: { x: -8, y: -6 },
1008
+ text: 'Max',
1009
+ align: 'right',
1010
+ pointer: 'ruleFromLeft',
1011
+ lineDash: '4 3',
1012
+ },
1013
+ ]"
1014
+ :chart-padding="{ top: 24, right: 24 }"
1015
+ :height="240"
1016
+ x-label="Days"
1017
+ y-label="Cases"
1018
+ />
1019
+
1020
+ <template #code>
1021
+
1022
+ ```vue
1023
+ <LineChart
1024
+ :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
1025
+ :annotations="[
1026
+ {
1027
+ x: 5,
1028
+ y: 30,
1029
+ offset: { x: 8, y: 14 },
1030
+ text: 'Peak',
1031
+ pointer: 'ruleX',
1032
+ lineDash: '4 3',
1033
+ },
1034
+ {
1035
+ x: 5,
1036
+ y: 30,
1037
+ offset: { x: -8, y: -6 },
1038
+ text: 'Max',
1039
+ align: 'right',
1040
+ pointer: 'ruleFromLeft',
1041
+ lineDash: '4 3',
1042
+ },
1043
+ ]"
1044
+ :chart-padding="{ top: 24, right: 24 }"
1045
+ :height="240"
1046
+ x-label="Days"
1047
+ y-label="Cases"
1048
+ />
1049
+ ```
1050
+
1051
+ </template>
1052
+ </ComponentDemo>
1053
+
1054
+ ### Chart menu
1055
+
1056
+ The chart menu (top-right) leads with Fullscreen and then Save as SVG,
1057
+ Save as PNG, and Download CSV. Fullscreen grows the chart to fill the browser
1058
+ window so the plot has more room; while expanded the menu trigger is replaced
1059
+ by a close (✕) button — click it or press <kbd>Esc</kbd> to return to the
1060
+ inline size. Set `menu="false"` to hide the trigger entirely.
1061
+
1062
+ While expanded the chart is teleported to `<body>` so it reliably covers the
1063
+ viewport even when an ancestor uses `transform`, `filter`, `contain`, or
1064
+ establishes a stacking context. If your app doesn't mount at the document root
1065
+ (e.g. inside a shadow root or a dedicated overlay container), point
1066
+ `fullscreenTarget` at a CSS selector or element to teleport there instead.
1067
+
1068
+ ### Custom CSV download
1069
+
1070
+ By default, the Download CSV menu item exports the chart series as CSV. Use
1071
+ the `csv` prop to supply your own content (for example, to include original
1072
+ dates, categorical labels, or extra columns that aren't plotted). Use
1073
+ `filename` to control the download filename (shared by SVG, PNG and CSV).
1074
+
1075
+ Pass `download-link` to also render a plain text link below the chart — set
1076
+ it to `true` for the default label, or pass a string to customize it. Use
1077
+ `download-button` instead to render a styled `<button>` (with the class
1078
+ `line-chart-download-button`, available for custom CSS) in place of the
1079
+ link.
1080
+
1081
+ <ComponentDemo>
1082
+ <LineChart
1083
+ :data="[10, 22, 35, 48]"
1084
+ :height="200"
1085
+ filename="weekly-cases"
1086
+ :csv="'week,cases\n2024-W01,10\n2024-W02,22\n2024-W03,35\n2024-W04,48'"
1087
+ x-label="Week"
1088
+ y-label="Cases"
1089
+ download-link="Download weekly cases (CSV)"
1090
+ />
1091
+
1092
+ <template #code>
1093
+
1094
+ ```vue
1095
+ <LineChart
1096
+ :data="[10, 22, 35, 48]"
1097
+ :height="200"
1098
+ filename="weekly-cases"
1099
+ :csv="`week,cases
1100
+ 2024-W01,10
1101
+ 2024-W02,22
1102
+ 2024-W03,35
1103
+ 2024-W04,48`"
1104
+ x-label="Week"
1105
+ y-label="Cases"
1106
+ download-link="Download weekly cases (CSV)"
1107
+ />
1108
+ ```
1109
+
1110
+ </template>
1111
+ </ComponentDemo>
1112
+
1113
+ `csv` also accepts a function, which is useful for deferring serialization
1114
+ until the user clicks Download:
1115
+
1116
+ ```vue
1117
+ <LineChart :data="cases" :csv="() => buildCsv(cases, dates)" />
1118
+ ```
1119
+
1120
+ ## Accessibility
1121
+
1122
+ The chart's `<svg>` is exposed as a single labeled image so screen readers
1123
+ announce one accessible name instead of wandering through the individual marks.
1124
+ When the chart has a `title`, the `<svg>` gets `role="img"` and an `aria-label`
1125
+ set to the title. The menu and download controls live outside the `<svg>`, so
1126
+ they stay reachable regardless.
1127
+
1128
+ Set `ariaLabel` to give screen readers a fuller summary than the visible title
1129
+ (it overrides `title` for the accessible name only):
1130
+
1131
+ ```vue
1132
+ <LineChart
1133
+ :data="cases"
1134
+ title="Daily ED visits"
1135
+ aria-label="Daily ED visits over 11 days, rising from 12 to a peak of 48"
1136
+ />
1137
+ ```
1138
+
1139
+ Pass `role` to override the default `"img"` (e.g. `role="figure"`, or a role of
1140
+ your own).
1141
+
1142
+ ## Props
1143
+
1144
+ | Prop | Type | Required | Default |
1145
+ |------|------|----------|---------|
1146
+ | `width` | `number` | No | — |
1147
+ | `height` | `number` | No | — |
1148
+ | `title` | `string` | No | — |
1149
+ | `titleStyle` | `TitleStyle` | No | — |
1150
+ | `role` | `string` | No | — |
1151
+ | `ariaLabel` | `string` | No | — |
1152
+ | `axisLabelStyle` | `LabelStyle` | No | — |
1153
+ | `tickLabelStyle` | `LabelStyle` | No | — |
1154
+ | `legendStyle` | `LabelStyle` | No | — |
1155
+ | `xLabel` | `string` | No | — |
1156
+ | `yLabel` | `string` | No | — |
1157
+ | `debounce` | `number` | No | — |
1158
+ | `menu` | `boolean \| string` | No | `true` |
1159
+ | `tooltipData` | `ArrayLike&lt;unknown&gt;` | No | — |
1160
+ | `tooltipTrigger` | `"hover" \| "click"` | No | — |
1161
+ | `tooltipClamp` | `"none" \| "chart" \| "window"` | No | `"window"` |
1162
+ | `tooltipValueFormat` | `NumberFormat` | No | — |
1163
+ | `csv` | `string \| (() =&gt; string)` | No | — |
1164
+ | `filename` | `string` | No | — |
1165
+ | `downloadLink` | `boolean \| string` | No | — |
1166
+ | `downloadButton` | `boolean \| string` | No | — |
1167
+ | `fullscreenTarget` | `string \| HTMLElement` | No | — |
1168
+ | `annotations` | `readonly ChartAnnotation[]` | No | — |
1169
+ | `chartPadding` | `ChartPadding` | No | — |
1170
+ | `y` | `LineChartData` | No | — |
1171
+ | `data` | `LineChartData` | No | — |
1172
+ | `x` | `LineChartXInput` | No | — |
1173
+ | `series` | `Series[]` | No | — |
1174
+ | `areas` | `Area[]` | No | — |
1175
+ | `areaSections` | `AreaSection[]` | No | — |
1176
+ | `lineOpacity` | `number` | No | `1` |
1177
+ | `yMin` | `number` | No | — |
1178
+ | `yScaleType` | `"linear" \| "log"` | No | `"linear"` |
1179
+ | `xMin` | `number` | No | — |
1180
+ | `xTicks` | `number \| number[]` | No | — |
1181
+ | `yTicks` | `number \| number[]` | No | — |
1182
+ | `xTickFormat` | `NumberFormat \| ((value: number, index: number) =&gt; string) \| DateFormat` | No | — |
1183
+ | `timezone` | `DateTimezone` | No | — |
1184
+ | `yTickFormat` | `NumberFormat` | No | — |
1185
+ | `xLabels` | `string[]` | No | — |
1186
+ | `xGrid` | `boolean` | No | — |
1187
+ | `yGrid` | `boolean` | No | — |
1188
+
1189
+
1190
+ ### Data
1191
+
1192
+ `data`, `series[].data`, and `areas[].upper`/`lower` accept a plain
1193
+ `number[]` or any standard numeric typed array (`Float64Array`,
1194
+ `Int32Array`, etc.). This lets you pass the output of
1195
+ `ModelOutput.column()` directly — no `Array.from(...)` copy is needed:
1196
+
1197
+ ```vue
1198
+ <LineChart :data="outputs.series.column('values')" />
1199
+ ```
1200
+
1201
+ ```ts
1202
+ type LineChartData =
1203
+ | readonly number[]
1204
+ | Float64Array
1205
+ | Float32Array
1206
+ | Int32Array
1207
+ | Uint32Array
1208
+ | Int16Array
1209
+ | Uint16Array
1210
+ | Int8Array
1211
+ | Uint8Array
1212
+ | Uint8ClampedArray;
1213
+ ```
1214
+
1215
+ ### Series
1216
+
1217
+ ```ts
1218
+ interface Series {
1219
+ y?: LineChartData; // y-values (preferred)
1220
+ data?: LineChartData; // y-values (alternative name; one of y/data must be set)
1221
+ x?: LineChartData; // optional parallel x-values
1222
+ color?: string;
1223
+ dashed?: boolean;
1224
+ strokeWidth?: number;
1225
+ opacity?: number;
1226
+ line?: boolean;
1227
+ outline?: boolean; // page-colored stroke drawn behind the line
1228
+ outlineColor?: string; // outline stroke color (default: var(--color-bg-0, #fff))
1229
+ outlineWidth?: number; // extra width added to strokeWidth (default: 4)
1230
+ dots?: boolean;
1231
+ dotRadius?: number;
1232
+ dotFill?: string;
1233
+ dotStroke?: string;
1234
+ }
1235
+ ```
1236
+
1237
+ ### Area
1238
+
1239
+ ```ts
1240
+ interface Area {
1241
+ upper: LineChartData;
1242
+ lower: LineChartData;
1243
+ x?: LineChartData; // optional parallel x-values
1244
+ color?: string;
1245
+ opacity?: number;
1246
+ legend?: string; // inline legend label
1247
+ showInLegend?: boolean; // default true when legend is set
1248
+ blendMode?: BlendMode; // CSS mix-blend-mode for the fill
1249
+ }
1250
+ ```
1251
+
1252
+ ### AreaSection
1253
+
1254
+ ```ts
1255
+ interface AreaSection {
1256
+ seriesIndex?: number; // omit for full-height fill
1257
+ startIndex: number;
1258
+ endIndex: number;
1259
+ color?: string;
1260
+ opacity?: number; // default: 0.15
1261
+ label?: string;
1262
+ description?: string;
1263
+ strokeWidth?: number; // default: 2
1264
+ dashed?: boolean;
1265
+ legend?: "inline" | "below" | false; // default: "below"
1266
+ }
1267
+ ```