WaterfallControl draws a bridge: from an opening amount, through the changes that make it up,
to a result. Premium → expected loss → costs → technical result is the typical one; gross → ceded →
net, or plan → variances → actual, are others. Never draw this as hand-built SVG in Controls.Html —
compose the control.
Controls.Waterfall(
WaterfallStep.Total("Our premium", 262_500),
WaterfallStep.Delta("Expected loss", -157_500),
WaterfallStep.Delta("External cost", -26_250),
WaterfallStep.Delta("Internal cost", -13_125),
WaterfallStep.Total("Technical result", 65_625))
.WithCurrency("EUR")
.WithFormat("N0")
.WithHeight("280px")
Steps: a total is a LEVEL, a delta is a CHANGE
| Kind | Amount means |
Drawn as |
|---|---|---|
WaterfallStepKind.Total ("total") |
the level itself | a bar standing on zero; the running level continues FROM it (a subtotal resets it) |
WaterfallStepKind.Delta ("delta", the default) |
the signed change | a bar hanging from the running level, its value printed with its sign |
The caller states which a step is — the control never infers "the last bar must be the sum". The
last step, when it is a total, is the result and is toned by its sign (result-positive /
result-negative); deltas are increase / decrease, other totals total. Both vocabularies are
open string constants. A step whose kind the layout does not know is never given a meaning: it is
left out of the running level, not drawn, and reported in WaterfallLayout.Unrecognized (the view
names it under the chart). A blank kind is the default, a delta.
Geometry is the control's, not the view's
WaterfallControl.Layout(steps) is pure and unit-tested (FigureControlsTest): it returns every
bar's From / To, its BottomPercent / HeightPercent on an axis that spans every level reached
and always includes zero, the LevelPercent its connector runs at, and ZeroPercent for the
baseline. A present-but-tiny amount keeps a visible sliver, grown from the bar's anchor in the direction of
its sign (a tiny loss stays below zero). When that anchor sits on the axis edge, the axis gains a
hair of headroom on that side rather than clamping the bar away. An exact zero draws nothing. It returns
null — and the view says "Nothing to bridge." in the viewer's language — for no steps, a
non-finite amount, an axis that overflows the double range, or every level at zero. See
Authoring for every renderer for why the arithmetic lives here.
Binding
Steps, Currency, Format and Height are all object: hand the rows over directly, or bind
them to a live data section with a JsonPointerReference — a template returns at once and the
projection feeds it (Data Binding):
Controls.Waterfall(new JsonPointerReference("waterfall"))
.WithCurrency(new JsonPointerReference("currency"))
AnalysisRows.Resolve<WaterfallStep> reads both forms. Values are formatted with the .NET numeric
Format (default N0) in the viewer's locale; the Blazor renderer ships in the analysis view pack
(MeshWeaver.Blazor.Analysis, AddAnalysisViews).