Skip to content

Fountain (Jet d'Eau) API ​

One number per column (the big dot), the real range around it (the fountain, from low to high) and the measurements themselves (the small dots), all on one y-axis. Categorical x = snapshot; temporal or numeric x = trend. See the Fountain demo and its reading key.

Import ​

ts
import "@michi-vz/wc/fountain-chart";
// <michi-vz-fountain-chart> is now defined
ts
import { mountFountainChart } from "@michi-vz/core";

const chart = mountFountainChart(el, props);
ts
import { FountainChart } from "@michi-vz/react/fountain-chart";
ts
import { FountainChart } from "@michi-vz/vue/fountain-chart";
ts
import { fountainChart } from "@michi-vz/svelte/fountain-chart";
ts
import { bindChart, applyFountainChartProps } from "@michi-vz/angular/fountain-chart";
// needs CUSTOM_ELEMENTS_SCHEMA on the component that hosts <michi-vz-fountain-chart>

Props ​

PropTypeDefaultDescription
timelineboolean | TimelinePeriodConfig-Opt-in "play through years" (cumulative): the marks draw UP TO the active period and extend as the timeline steps; `interpolate` sweeps smoothly between years, `false` jump-cuts. Headless controller via `chart.timeline()` plus the built-in play button + scrubber. Off by default; wins over `progressiveDraw` when both are set. The reveal always shows the whole active jet, fountain and small dots included, and a jet's value labels appear with it; undrawn jets cannot be hovered. Trend mode only. Not drawn by the "webgpu" renderer (an ignored-option warning).
progressiveDrawboolean | ProgressiveDrawConfig-Opt-in reveal animation: wipes the marks in left to right on mount (a clip reveal; axes and titles stay put). `true` uses defaults (1200 ms, easeInOutCubic); a config tunes durationMs, easing, autoplay, and replayOnUpdate (`tipLabel` is LineChart-only and ignored here). Off by default; respects prefers-reduced-motion (renders fully drawn instantly) and `replay()` re-runs it. Jets the wipe has not reached cannot be hovered. Not drawn by the "webgpu" renderer (an ignored-option warning).
dataSet*FountainDataItem[]-Array of jets; each item renders one fountain
titlestring-Optional chart title rendered above the plot
xAxisDataTypeFountainXAxisType-How the x-axis is parsed: a temporal/numeric type renders TREND mode (jets at their dates, the x range inset by half a column on each side, one tick per period); "band" (or omitted) renders SNAPSHOT mode (one column per label)
yAxisDomain[number, number]-Explicit [min, max] for the value (y) axis, used as given (not rounded). The auto domain includes 0, every value, low, high and reference line, plus 10% headroom, rounded to nice ticks. Data outside a user domain is clamped to the plot edge and small dots outside it are not drawn (an `out-of-domain` warning).
xAxisFormat(d: number | string) => string-Formats an x tick value into its display label
yAxisFormat(d: number | string) => string-Formats a y value: the tick labels and the numbers in the value labels and the tooltip (default: the locale's number format)
ticksnumber5Approximate number of axis ticks to generate (default 5)
tickValuesArray<number | Date>-Explicit x tick values, overriding the per-period ticks (trend mode)
showRangebooleantrueDraw the fountain: the range [low, high] as a bell (default true). `false` draws the stem and the big dot only; the small dots need the fountain to sit in, so they hide too.
showSamplesbooleantrueDraw the small dots, one per sample, when items carry `samples` (default true)
showValueLabelsbooleantruePrint value labels under each x label (default true): bold "usual 30", then "<low word> 22" and "<high word> 55" (see `endLabels`), "only N <sampleWord>" under 10 samples, and per reference line with a `goodSide` a bold "17 of 20" plus its `countLabel`. The chart reserves bottom margin for them. On narrow columns the text shrinks, then the end lines go, before a label would overlap a neighbour; when even the usual line cannot fit, when the x labels have to tilt, or where two jets share a column, the value labels are left out (a `layout-overflow` warning).
driftbooleanfalseThe Geneva look: the top of every fountain leans downwind, the same way for every jet, so it means nothing (default false: readers found it confusing)
yAxisTitlestring-Title drawn rotated beside the y-axis, e.g. "minutes (higher = slower)"
endLabels[string, string]-Words for the low and high ends in the value labels and tooltip (default ["lowest", "highest"]; e.g. ["best", "worst"], ["cheapest", "dearest"])
referenceLinesFountainReferenceLine[]-Horizontal reference lines (a promise, a limit, a budget). With `goodSide`, each jet with samples counts its small dots on the good side.
labelsFountainLabels-UI words for localisation (English defaults "usual", "of", "only", "forecast")
readingGuideboolean | string-A reading guide under the plot (default false), on one line when it fits, else wrapped between its rules (at each " · "), never inside one. `true` prints the default ("Small dot = one measurement · Big dot = the usual one · Dots close together = steady · Tall fountain = changes a lot · Few dots = just a guess") with only the rules for marks the chart draws: no small-dot rules without small dots (no samples, showSamples or showRange off, forecasts only), no "Tall fountain" rule without a fountain. A string replaces it and is printed as given.
sampleWordstring-PLURAL noun for the samples in the value labels and tooltip, e.g. "days", "orders" (default "measurements"). Plural on purpose: there is no pluralising logic, and one string is easy to localise.
showTrendLineboolean-Draw a dashed grey line through the big dots, left to right (default true in trend mode with one series; false with several series, where one line would zig-zag between them, and in snapshot mode; set it true to join an ordered sequence of categories, e.g. hours)
tooltipFormatter(d: FountainDataItem & { value: number }, jet?: FountainTooltipJet) => string-Returns custom tooltip HTML for a hovered or pinned jet (sanitized before it is inserted). Default: the label (with its period in trend mode), "usual 30", "<low word> 22 · <high word> 55", "20 <sampleWord>" and a count per reference line with a goodSide, numbers formatted like the y-axis. Click or tap pins the tooltip; clicking the pinned jet or empty space, or Escape, unpins. The first argument is the item with its resolved `value` (the median of its samples when it gives none), so `d.value` is always a number; a formatter typed `(d: FountainDataItem) => string` still fits. The second is the jet as drawn (its range, samples, reference counts, period and the default lines), so a custom tooltip needs no re-derivation.
isLoadingboolean-Show the loading overlay; with nothing drawn yet the axes and marks wait for data, while a refetch keeps the stale jets on screen.
isNodataboolean | ((dataSet: FountainDataItem[] | null | undefined) => boolean)-No-data override: boolean, or a predicate on the data; default = an empty dataSet. With no data the chart draws the no-data overlay instead of axes and marks.
noDataLabelstring-Text for the vanilla default no-data overlay (ignored when suppressed).
suppressDefaultOverlayboolean-A framework wrapper sets this to render its OWN loading/no-data node instead.
onHighlightItem(labels: string[]) => void-Called when the hovered, pinned or cleared label changes (only on a change: moving within one jet does not re-fire; leaving every jet fires [])
style"jet" | "plume"-Deprecated ignored since core 1.29; emits an ignored-option warning. There is one look now: stem, fountain, small dots, big dot.
frothLayersnumber-Deprecated ignored since core 1.29; emits an ignored-option warning
bloomExponentnumber-Deprecated ignored since core 1.29; emits an ignored-option warning
stemFractionnumber-Deprecated ignored since core 1.29; emits an ignored-option warning
showDropletsboolean-Deprecated ignored since core 1.29; emits an ignored-option warning
showMistboolean-Deprecated ignored since core 1.29; emits an ignored-option warning
Common props - shared by every chart (14)
PropTypeDefaultDescription
widthnumber900Chart width in pixels
heightnumber480Chart height in pixels
marginMargin{ top: 50, right: 40, bottom: 50, left: 60 }Inner margins (top/right/bottom/left, in px); default 8 (36 top with a title)
colorsstring[]-Categorical palette for rings without an explicit colour or colorsMapping entry
colorsMappingRecord<string, string>-Explicit label -> colour map; takes precedence over the palette and per-item colours
highlightItemsstring[]-Labels to emphasise (active styling); others keep their base opacity
disabledItemsstring[]-Labels to hide entirely (ring + track removed; remaining rings keep their radii order)
renderer"svg" | "canvas" | "webgpu""svg"Render as inline SVG (default) or to a canvas / WebGPU layer; getContext() is identical either way
localestring-BCP-47 locale used for number formatting
skipColorMappingDispatchbooleanfalseExternal-CSS mode: unmapped labels resolve to transparent and onColorMappingGenerated is not emitted, so arc colours come from your CSS via the data-label-safe contract
enableTransitionsbooleantrueAnimate opacity/arc changes with CSS transitions (SVG renderer; default true)
onColorMappingGenerated(mapping: Record<string, string>) => void-Called with the resolved label -> colour map after the chart assigns colours
onChartDataProcessed(context: ChartContext) => void-Called with the renderer-agnostic ChartContext whenever the data is (re)processed
onDataWarning(warnings: DataWarning[]) => void-Called with any non-fatal data warnings (out-of-range values, duplicate labels, ...)

Two modes, one data shape

Set xAxisDataType: "band" (or omit it) for snapshot mode: one column per label. Give a temporal or numeric xAxisDataType plus a date on each item for trend mode: the jets sit along the x-axis, and with one series a dashed line joins the big dots. A forecast: true item gets a dashed stem and outline, a lighter fill and a hollow big dot, with no small dots.

New in core 1.29 ​

PropTypeDefaultWhat it does
showRangebooleantrueDraw the fountain, the range [low, high]. false draws the stem and the big dot only; the small dots hide too.
showSamplesbooleantrueDraw one small dot per sample, when items carry samples.
showValueLabelsbooleantruePrint under each x label: bold "usual 30", "<low word> 22", "<high word> 55", "only N <sampleWord>" under 10 samples, and per reference line with a goodSide a bold "17 of 20" plus its countLabel.
driftbooleanfalseThe Geneva look: the top of every fountain bends the same way. It carries no data.
yAxisTitlestringnoneTitle drawn rotated beside the y-axis, e.g. "minutes (higher = slower)".
endLabels[string, string]["lowest", "highest"]Words for the low and the high end in the value labels and the tooltip.
referenceLinesFountainReferenceLine[]noneDashed lines in the theme's attention colour, labelled at the right end. See below.
labelsFountainLabelsEnglishThe chart's other words, for localisation. See below.
readingGuideboolean | stringfalseA key under the plot, wrapped between its rules (at each " · ") when it does not fit on one line. true prints the default, naming only the marks the chart draws (no small-dot rules without small dots, no "Tall fountain" without a fountain); a string replaces it.
sampleWordstring"measurements"Plural noun for the samples ("days", "orders"). Plural on purpose: there is no pluralising logic.

showTrendLine now defaults per mode: true in trend mode with one series; false with several series, where one line would zig-zag between them, and in snapshot mode (set it true to join an ordered row of categories).

Data item: FountainDataItem ​

FieldTypeWhat it is
labelstringThe column (snapshot) or the series name (trend). Drives the colour and the data-label hook.
codestringOptional stable id carried into the context; not displayed.
valuenumberThe big dot. Optional when samples are given: then their median. With no finite value and no samples the jet is skipped.
lownumberThe base of the fountain.
highnumberThe top of the fountain.
spreadnumberShorthand for an even range: low = value - spread, high = value + spread.
samplesnumber[]Real measurements, one small dot each, drawn at their exact height inside the fountain.
forecastbooleanA predicted period: dashed stem and outline, lighter fill, hollow big dot, no small dots and no counts.
colorstringPer-item colour. Resolution per jet: colorsMapping[label], then color, then the label's palette slot.
datenumber | stringThe x position in trend mode; an item without a usable date is skipped there.
predictedbooleanDeprecated: use forecast. Still honoured.
certaintybooleanDeprecated: certainty: false is forecast: true. Still honoured.
densitynumberDeprecated and ignored (an ignored-option warning).
leannumberDeprecated and ignored (an ignored-option warning).

The range comes from the first of: low/high, then spread, then the lowest and highest sample; with none, the jet has no fountain. A missing end falls back along the same chain. Samples outside an explicit range, and a value outside the range, widen the range and send a warning. Negative values are allowed: the y domain includes 0 and every low, and the stem runs down from the baseline.

Reference line: FountainReferenceLine ​

FieldTypeWhat it is
valuenumberWhere the line sits, in y units. Always inside the automatic y domain.
labelstringPrinted at the right end of the line (wrapped; the chart reserves right margin).
goodSide"below" | "above"Which side is good. When set, every jet with samples counts them: "below" counts the samples at or below the line, "above" those at or above it.
countLabelstringWords after the count, e.g. "on time", "passed". Default "below the line" or "above the line".

Words: FountainLabels ​

FieldDefaultWhere it shows
usual"usual"Before the big dot's value: "usual 30".
of"of"Between a count and its total: "17 of 20".
only"only"Before a small sample count: "only 5 days".
forecast"forecast"After a forecast jet's x label and in its tooltip: "Fri (forecast)".

Theme tokens ​

The chart reads these CSS custom properties from its host element (or any ancestor), in every renderer:

TokenDefaultWhat it colours
--michi-vz-surface#fffThe background the chart sits on: the thin ring round each small dot and the ring round a big dot, which keep them apart from the marks under them. On a dark theme, set it to your page's background.
--michi-vz-attention#c0392bThe reference lines, their labels and the counts under the columns.
--michi-vz-lake#9cc3ddThe band at 0 (the lake).
--michi-vz-inkcurrentColorThe trend line, the bold "usual 30" line and the title.
--michi-vz-muted#666The other value labels, the y-axis title, the reading guide and the axis labels.
--michi-vz-gridlightgrayThe thin rule above the reading guide.
--michi-vz-font-family, --michi-vz-font-sizeinherited, 12pxEvery word the chart prints.

A forecast's hollow big dot is a ring with nothing painted inside (the marks under it are cut away), so it stays hollow on any background without a token.

css
/* The charts on a dark page */
.dark .charts {
  --michi-vz-surface: #1b1b1f;
  --michi-vz-ink: #e3e3e3;
  --michi-vz-muted: #a0a0a0;
}

Events ​

The web component dispatches these bubbling CustomEvents (the engine exposes the same via the on* callbacks in the table above):

EventDetailFires when
michi-vz:highlightstring[]the hovered jet changes (its label)
michi-vz:colormappingRecord<string, string>a colour mapping is generated
michi-vz:dataprocessedChartContextdata is (re)processed
michi-vz:datawarningDataWarning[]input warnings are detected (see Warnings)

getContext() ​

mountFountainChart(el, props).getContext() returns a renderer-agnostic FountainChartContext:

  • mode: "snapshot" for a categorical (band) x, "trend" for a temporal or numeric x.
  • xAxis: { type, domain }, the column labels in snapshot mode or [min, max] in trend mode. yAxis: { domain }.
  • jets: one entry per drawn jet (in x order in trend mode):
FieldWhat it is
label, code, colorThe jet's label, its optional id and its resolved colour.
valueThe big dot.
low, highThe base and the top of the fountain; null without a range.
rangehigh - low; null without a range.
rangeRatiorange / |value|: how big the range is next to the number. null when the value is 0 or there is no range.
sampleCountNumber of small dots.
referenceCountsOne { value, goodSide, count, total, countLabel } per reference line with a goodSide; [] for a forecast or a jet without samples.
predictedtrue for a forecast jet.
xPositionThe raw date in trend mode, null in snapshot mode.
spreadDeprecated: (high - low) / 2, 0 without a range. Use range.
spreadRatioDeprecated: spread / |value|, 0 when not computable. Use rangeRatio.
upperBoundDeprecated: high (or the value without a range). Use high.
leanDeprecated: always null.
  • stats:
    • jetCount: number of drawn jets.
    • tallest: { label, value } of the largest value, or null.
    • widestRange: { label, range } of the widest range, or null when no jet has one.
    • frothiest: deprecated. { label, spreadRatio } of the jet with the largest rangeRatio. Use widestRange or jets[].rangeRatio.
    • trendSlope: least-squares slope of the values per period (trend mode, one series); otherwise null.
    • valueRange: [min, max] of the values, or null.
    • predictedCount: number of forecast jets.
  • legendData: every label of the whole dataSet with its colour, in first-seen order; disabled labels stay, flagged disabled: true. In trend mode only when there is more than one series.
  • summary: one sentence in plain words, e.g. Fountain chart "How long is my commute, really?" with 4 jets. Highest usual value: Bus at 40. Widest range: Car, from 22 to 55.
  • a11yTable: headers Label, Usual, the two endLabels, Samples, and one column per reference line with a goodSide (headed by its countLabel, cells like "17 of 20"); trend mode adds Period first. A forecast jet's label gets "(forecast)" after it: its trend row reads ["Year 4", "Battery (forecast)", …].

See LLM context for how to use the context in prompts and reports.

Warnings ​

onDataWarning (and the michi-vz:datawarning event) receives DataWarning[], each { type, message, label? }. The chart never redraws data silently: every repair is reported.

typeWhenWhat the chart does
non-finite-valueAn item has no finite value and no samples, or some samples are not finite.Skips the jet (it stays out of the stats), or drops those samples. A missing value with samples uses their median.
range-excludes-valuelow/high (or spread) leave the value out.Widens the range to include the value.
sample-outside-rangeA sample lies outside an explicit range.Widens the range to include it.
inverted-rangelow is above high, or spread is negative.Swaps the ends (uses the spread's size).
missing-dateTrend mode, but the item has no usable date.Skips the item (the chart stays in trend mode).
duplicate-dateTwo jets share one date in trend mode.Draws them on top of each other.
duplicate-labelA label repeats in snapshot mode.Its jets share one column.
out-of-domainA value, range end or sample is outside a user yAxisDomain, or a reference line is.Clamps the drawing to the plot; small dots and lines outside it are not drawn.
ignored-optionA removed prop is set, or an item carries density or lean.Ignores it.
empty-datasetThe dataSet is empty.Shows the no-data overlay ("No data available", your noDataLabel, or your own with suppressDefaultOverlay) instead of axes and marks. isNodata: false draws the empty axes.
layout-overflowEach jet gets under 24 px, or the value labels do not fit (narrow columns, rotated x labels, jets sharing a column, or a chart too short for them).Draws the jets anyway and leaves out the value labels that do not fit, the end words first. Widen the chart, show fewer jets or aggregate.

Deprecations ​

All of these still work in core 1.29 and will be removed in a later release. See Migrating from core 1.28.

  • Props, ignored with an ignored-option warning: style, frothLayers, bloomExponent, stemFraction, showDroplets, showMist. On the web component, fountainStyle (fountain-style).
  • Item fields: predicted and certainty are honoured; use forecast. density and lean are ignored with a warning.
  • Context fields: jets[].spread, jets[].spreadRatio, jets[].upperBound and jets[].lean (always null); stats.frothiest. Use range, rangeRatio, high and stats.widestRange.

Source ​

Props are typed as FountainChartProps in @michi-vz/core.