ComponentAdded in v15.1

Waterfall Chart

How a figure gets from one value to another, one change at a time.

Installation

Import the class, and @use the entry point in your global styles: without it the component renders unstyled.

import { Component } from '@angular/core';
import { WrWaterfallChart } from 'ngwr/charts/waterfall-chart';

@Component({ imports: [WrWaterfallChart] })
export class MyComponent {}

Basic

A change floats from the running total. A total is a bar from zero. Up, down and total each have their own colour, sign and direction.

<wr-waterfall-chart
  ariaLabel="Profit bridge"
  [steps]="[
    { label: 'Opening', value: 4200, total: true },
    { label: 'Sales', value: 1800 },
    { label: 'Refunds', value: -350 },
    { label: 'Payroll', value: -900 },
    { label: 'Closing', value: 4750, total: true }
  ]"
/>

Totals

A total shows the running total, and its value is checked rather than drawn: in dev mode, a value the steps above do not add up to warns. A total before every change opens the chart at its value.

<wr-waterfall-chart [steps]="months" />
months: WrWaterfallStep[] = [
  { label: 'Start', value: 1200, total: true }, // opens the chart
  { label: 'Jan', value: 300 },
  { label: 'Feb', value: -150 },
  { label: 'Mar', value: 420 },
  { label: 'Q1', value: 1770, total: true }, // checked: 1200 + 300 − 150 + 420
  { label: 'Apr', value: -80 },
  { label: 'May', value: 260 },
  { label: 'Jun', value: 190 },
  { label: 'H1', value: 2140, total: true },
];

Below zero

The value axis always includes zero. A running total below it hangs under the zero line.

<wr-waterfall-chart [steps]="cash" />

Colours

increaseColor, decreaseColor and totalColor take any CSS colour. Success, danger and primary by default.

<wr-waterfall-chart totalColor="var(--wr-color-on-surface-muted)" [steps]="bridge" />

Number format

Numbers follow LOCALE_ID. valueFormat replaces it, and is told where each figure goes: 'label' past a bar, 'tick' on the axis, 'value' in the tooltip, the names and the data table. So the drawing can go compact and the rest stay exact. Every figure arrives as its magnitude, and the chart writes the sign. A figure too wide for its column is left out, never cut.

<wr-waterfall-chart [steps]="bridge" [valueFormat]="format" />
const usd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 });
const compactUsd = new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', notation: 'compact' });

// Compact past the bars ('label'), whole on the axis and in the tooltip, names and table.
// Every figure arrives as its magnitude; the chart writes + or − in front.
format = (value: number, where: WrWaterfallValueContext): string =>
  (where === 'label' ? compactUsd : usd).format(value);

Quieter

showValues, showGrid and showConnectors each turn one layer off. Keep the figures or the connectors: with both off, only colour tells up from down. The names, the tooltip and the data table keep every figure.

<wr-waterfall-chart [steps]="bridge" [showValues]="false" [showGrid]="false" />

Data table

dataTable renders every figure as a table only screen readers reach: a row per step, with its change and the running total. Nothing changes on screen.

<wr-waterfall-chart ariaLabel="Profit bridge" dataTable [steps]="bridge" />
Profit bridge
StepChangeRunning total
Opening4,200
Sales+1,8006,000
Services+6506,650
Refunds−3506,300
Payroll−9005,400
Rent−4005,000
Closing5,000

Accessibility

PartBehaviour
ChartA role="group", named by ariaLabel. No tab stop.
StepsOne role="img" each, named with the change and the running total.
Up, down, total Told apart by direction, by a + or − sign and by a heavier total label, not only colour. Turning off both showValues and showConnectors leaves only colour.
Zero changeA neutral hairline, printed 0. Not an increase.
TooltipPointer only. Escape closes it.
Forced coloursBars keep their colours. Lines take system colours.

API

NameDescriptionTypeDefault
stepsThe steps, in order. A step without total is a change to the running total; a step with it is a bar from zero showing the running total. See {@link WrWaterfallStep} for what a total's value does.readonly WrWaterfallStep[][]
ariaLabelAccessible name of the chart, and the data table's caption. Each step names itself, so say what the chart shows. Falls back to waterfallChart.label ("Waterfall chart").string | nullnull
increaseColorThe colour of a change up. Any CSS colour, var(--wr-…) included.string'var(--wr-color-success)'
decreaseColorThe colour of a change down. Any CSS colour.string'var(--wr-color-danger)'
totalColorThe colour of a total. Any CSS colour.string'var(--wr-color-primary)'
heightThe plot's height in px, at least 80.number240
showGridShow the gridlines and the value axis' tick labels.booleantrue
showValuesPrint each step's figure past the end of its bar: a change with its sign, over the bar when it runs up and under it when it runs down, and a total with no +. Compact from a thousand up (+1.2K) by default; with valueFormat, whatever it writes for 'label', so a formatter can go compact here and stay exact everywhere else. A figure is printed whole or not at all: one wider than its column and a quarter of the gap on either side — which keeps it clear of its neighbours' — is left out rather than cut, since +$1,… is not a figure and −$9… reads as −$9. The tooltip, the names and the data table carry every figure in full. The sign is one of the two cues besides colour that tell a change up from a change down; the connectors are the other. Off together with showConnectors, colour is the only one left on screen.booleantrue
showConnectorsDraw the thin line that carries each running total across the gap to the next bar, which starts from it. None leads into a total that starts a running total of its own — one before every change, at a value the line would not meet. A change up leaves the line at its bottom and a change down at its top, so the line is one of the two cues besides colour that tell them apart; the signed figures are the other. Off together with showValues, colour is the only one left on screen.booleantrue
tooltipShow a tooltip with the step's change and the running total after it on hover. Pointer only — each step's accessible name already carries both.booleantrue
dataTableRender the chart's figures as a table only assistive technology reaches, beside the drawing: a row per step, headed by its label, with its change (empty on a total) and the running total after it, each written as the tooltip writes it. Each step's accessible name already carries both figures; the table is for a reader who wants to move through them cell by cell, with the column headings read out. It is clipped to nothing: it takes no room, draws nothing and holds no tab stop.booleanfalse
valueFormatWrites every number the chart shows: the figures on the drawing, the axis ticks, the tooltip, the accessible names and the data table. Every figure is handed over as its MAGNITUDE, never below zero, and the chart writes the sign in front: + or − (U+2212 MINUS SIGN) on a change, − on a running total, a total or a tick below zero. So one formatter writes every figure, and one minus sign appears throughout. It is told where the figure goes (see {@link WrWaterfallValueContext}): 'label' past a bar, where a compact form fits a narrow column; 'tick' on the value axis; 'value' in the tooltip, the names and the data table, which a reader goes to for the exact figure. A (value) => string written for another chart fits too, and writes all three alike. null uses Intl.NumberFormat in LOCALE_ID: compact past the bars from a thousand up, compact ticks (1.2K, 3.4M) unless the full numbers are shorter, and the exact figure everywhere else.((value: number, context: WrWaterfallValueContext) => string) | nullnull

Types

interface WrWaterfallStep {
  label: string;
  value: number;
  total?: boolean;
}

type WrWaterfallValueContext = 'label' | 'tick' | 'value';
NameDescriptionTypeDefault
WrWaterfallStepOne step: a change, or a total.interface—
labelrequiredThe step name: under the bar, tooltip, data table.string—
valuerequiredThe change. Zero, or not a number, is a neutral hairline. On a total, the expected total: checked, not drawn. A total before every change opens the chart at it.number—
totalDraw a bar from zero to the running total.booleanfalse
WrWaterfallValueContextWhere valueFormat is writing: 'label' past a bar, 'tick' on the axis, 'value' in the tooltip, the names and the data table.'label' | 'tick' | 'value'—

CSS variables

Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/charts/waterfall-chart's own element.

VariableDefaultDeclared on
--wr-waterfall-chart-active-bgcolor-mix(in srgb, var(--wr-color-on-surface) 6%, transparent).wr-waterfall-chart
--wr-waterfall-chart-bar-radiuscalc(var(--wr-border-radius-sm) / 3).wr-waterfall-chart
--wr-waterfall-chart-baseline-colorvar(--wr-border-base).wr-waterfall-chart +1 variant override
--wr-waterfall-chart-colorvar(--wr-color-on-surface).wr-waterfall-chart
--wr-waterfall-chart-connector-colorvar(--wr-color-on-surface-muted).wr-waterfall-chart +1 variant override
--wr-waterfall-chart-connector-width1px.wr-waterfall-chart
--wr-waterfall-chart-flat-colorvar(--wr-color-on-surface-muted).wr-waterfall-chart +1 variant override
--wr-waterfall-chart-font-familyvar(--wr-font-family-base).wr-waterfall-chart
--wr-waterfall-chart-gapvar(--wr-space-sm).wr-waterfall-chart
--wr-waterfall-chart-grid-colorcolor-mix(in srgb, var(--wr-border-base) 70%, transparent).wr-waterfall-chart +1 variant override
--wr-waterfall-chart-label-colorvar(--wr-color-on-surface-muted).wr-waterfall-chart
--wr-waterfall-chart-label-font-sizevar(--wr-text-xs).wr-waterfall-chart
--wr-waterfall-chart-labels-margin-topvar(--wr-space-sm).wr-waterfall-chart
--wr-waterfall-chart-plot-inset-yvar(--wr-space-sm).wr-waterfall-chart
--wr-waterfall-chart-tick-colorvar(--wr-color-on-surface-muted).wr-waterfall-chart
--wr-waterfall-chart-tick-font-sizevar(--wr-text-xs).wr-waterfall-chart
--wr-waterfall-chart-tick-gapvar(--wr-space-xs).wr-waterfall-chart
--wr-waterfall-chart-tick-line-heightvar(--wr-text-xs-leading).wr-waterfall-chart
--wr-waterfall-chart-total-font-weightvar(--wr-font-weight-medium).wr-waterfall-chart
--wr-waterfall-chart-value-colorvar(--wr-color-on-surface).wr-waterfall-chart
--wr-waterfall-chart-value-font-sizevar(--wr-text-xs).wr-waterfall-chart
--wr-waterfall-chart-value-gapvar(--wr-space-xs).wr-waterfall-chart
--wr-waterfall-chart-value-line-heightvar(--wr-text-xs-leading).wr-waterfall-chart

Dependencies

Built onPopover

See also