Components
Chart
A chart of rows, assembled from parts as Flux's is, and drawn as SVG in C# with no chart library. Move the pointer over one: the cursor, the tooltip, the summary and a pie's slice follow it in the browser, with no round trip.
Drawn and behaving as Flux UI's chart does, measured against its live docs.
Line
A line, its axes, a cursor and a tooltip that reads the row under the pointer.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartExample : Component
{
// The numbers on Flux's own page.
private static readonly Visit[] Visits =
[
.. new[] { 171, 227, 269, 223, 249, 251, 300, 246, 162, 115, 176, 144, 184, 269, 259, 267 }
.Select((visitors, day) => new Visit(new DateOnly(2026, 1, 1).AddDays(day), visitors)),
];
protected override Component? Render() =>
Ui.Chart.Value(Visits).Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartLine.Field((Visit v) => v.Visitors).Class("text-pink-500 dark:text-pink-400"),
Ui.ChartAxis.X.Field((Visit v) => v.Day)[Ui.ChartAxisLine, Ui.ChartAxisTick],
Ui.ChartAxis.Y[Ui.ChartAxisGrid, Ui.ChartAxisTick],
Ui.ChartCursor
],
Ui.ChartTooltip[
Ui.ChartTooltipHeading.Field((Visit v) => v.Day),
Ui.ChartTooltipValue.Field((Visit v) => v.Visitors).Label("Visitors")
]
];
private sealed record Visit(DateOnly Day, int Visitors);
}Line with points
A dot on every row, on a time axis, with the value axis written as a unit.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartPointsExample : Component
{
private static readonly Reading[] Readings =
[
.. new[] { 268, 243, 236, 201, 228, 251, 231, 267, 202, 206, 280, 268, 265, 215, 254, 237, 253, 266, 257, 297, 269 }
.Select((memory, minute) => new Reading(new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Unspecified).AddMinutes(minute), memory)),
];
protected override Component? Render() =>
Ui.Chart.Value(Readings).Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartLine.Field((Reading r) => r.Memory).Class("text-pink-500"),
Ui.ChartPoint.Field((Reading r) => r.Memory).Class("text-pink-400"),
Ui.ChartAxis.X.Field((Reading r) => r.At)[Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.Y.Format(new() { Style = Ui.ChartFormatStyle.Unit, Unit = "megabyte" })[Ui.ChartAxisGrid, Ui.ChartAxisTick]
]
];
private sealed record Reading(DateTime At, int Memory);
}Area
The area under a straight line, with the value axis on the right in compact dollars.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartAreaExample : Component
{
// A price that climbs faster every minute: worked out, so the drawing is the same on every visit.
private static readonly Price[] Prices =
[
.. Enumerable.Range(0, 21)
.Select(minute => new Price(new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Unspecified).AddMinutes(minute), 200 + (minute * minute * 7))),
];
protected override Component? Render() =>
Ui.Chart.Value(Prices).Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartLine.Field((Price p) => p.Stock).Class("text-blue-500 dark:text-blue-400").Curve(Ui.ChartCurve.None),
Ui.ChartArea.Field((Price p) => p.Stock).Class("text-blue-200/50 dark:text-blue-400/30").Curve(Ui.ChartCurve.None),
Ui.ChartAxis.Y.Position(Ui.Position.Right).TickPrefix("$")
.Format(new() { Notation = Ui.ChartFormatNotation.Compact, MaximumFractionDigits = 1 })[Ui.ChartAxisGrid, Ui.ChartAxisTick],
Ui.ChartAxis.X.Field((Price p) => p.At)[Ui.ChartAxisTick, Ui.ChartAxisLine]
]
];
private sealed record Price(DateTime At, double Stock);
}Multiple lines
A line and points per series, a percent axis from 0 to 1, and a legend under the drawing.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartMultipleLinesExample : Component
{
private static readonly Social[] Networks =
[
new(new(2021, 6, 1), 0.26, 0.21, 0.31), new(new(2022, 6, 1), 0.19, 0.14, 0.35), new(new(2023, 6, 1), 0.22, 0.09, 0.59),
new(new(2024, 6, 1), 0.11, 0.16, 0.43), new(new(2025, 6, 1), 0.18, 0.13, 0.36),
];
protected override Component? Render() =>
Ui.Chart.Value(Networks)[
Ui.ChartViewport.Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartLine.Field((Social s) => s.Twitter).Class("text-blue-500").Curve(Ui.ChartCurve.None),
Ui.ChartPoint.Field((Social s) => s.Twitter).Class("text-blue-500").R(6).StrokeWidth(3),
Ui.ChartLine.Field((Social s) => s.Facebook).Class("text-red-500").Curve(Ui.ChartCurve.None),
Ui.ChartPoint.Field((Social s) => s.Facebook).Class("text-red-500").R(6).StrokeWidth(3),
Ui.ChartLine.Field((Social s) => s.Instagram).Class("text-green-500").Curve(Ui.ChartCurve.None),
Ui.ChartPoint.Field((Social s) => s.Instagram).Class("text-green-500").R(6).StrokeWidth(3),
Ui.ChartAxis.X.Field((Social s) => s.Day)[Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.Y.TickStart(0).TickEnd(1)
.Format(new() { Style = Ui.ChartFormatStyle.Percent, MaximumFractionDigits = 0 })[Ui.ChartAxisGrid, Ui.ChartAxisTick]
]
],
Div.Class("flex justify-center gap-4 pt-4")[
Ui.ChartLegend.Key("instagram").Label("Instagram")[Ui.ChartLegendIndicator.Class("bg-green-400")],
Ui.ChartLegend.Key("twitter").Label("Twitter")[Ui.ChartLegendIndicator.Class("bg-blue-400")],
Ui.ChartLegend.Key("facebook").Label("Facebook")[Ui.ChartLegendIndicator.Class("bg-red-400")]
]
];
private sealed record Social(DateOnly Day, double Twitter, double Facebook, double Instagram);
}Bar
A bar per row, about eight ticks along the bottom, and a cursor that shades the row's band.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartBarExample : Component
{
private static readonly Visit[] Visits =
[
.. new[] { 171, 227, 269, 223, 249, 251, 300, 246, 162, 115, 176, 144, 184, 269, 259, 267 }
.Select((visitors, day) => new Visit(new DateOnly(2026, 1, 1).AddDays(day), visitors)),
];
protected override Component? Render() =>
Ui.Chart.Value(Visits).Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartBar.Field((Visit v) => v.Visitors).Class("text-blue-500").Radius("0").Width("85%"),
Ui.ChartAxis.X.Field((Visit v) => v.Day).TickCount(8)[Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.Y.Format(new() { UseGrouping = true })[Ui.ChartAxisGrid, Ui.ChartAxisTick],
Ui.ChartCursor.Type(Ui.ChartCursorType.Area)
],
Ui.ChartTooltip[
Ui.ChartTooltipHeading.Field((Visit v) => v.Day),
Ui.ChartTooltipValue.Field((Visit v) => v.Visitors).Label("Visitors")
]
];
private sealed record Visit(DateOnly Day, int Visitors);
}Horizontal
Horizontal() puts the rows down the Y axis: bars on their side.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartHorizontalExample : Component
{
private static readonly Sale[] Sales =
[
new("Beauty", 342), new("Books", 356), new("Clothes", 432), new("Garden", 398), new("Pets", 487), new("Sports", 548), new("Toys", 643),
];
protected override Component? Render() =>
Ui.Chart.Horizontal().Value(Sales).Class("aspect-2/1")[
Ui.ChartSvg[
Ui.ChartBar.Field((Sale s) => s.Online).Class("text-blue-500").Radius("4 0").Width("70%"),
Ui.ChartAxis.Y.Field((Sale s) => s.Category)[Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.X[Ui.ChartAxisGrid, Ui.ChartAxisTick],
Ui.ChartCursor.Type(Ui.ChartCursorType.Area)
],
Ui.ChartTooltip[
Ui.ChartTooltipHeading.Field((Sale s) => s.Category),
Ui.ChartTooltipValue.Field((Sale s) => s.Online).Label("Orders")
]
];
private sealed record Sale(string Category, int Online);
}Grouped bars
Bars side by side in each row's slot.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartGroupedBarsExample : Component
{
private static readonly Sale[] Sales =
[
new("Beauty", 342, 215, 108), new("Books", 356, 256, 215), new("Clothes", 432, 284, 176), new("Garden", 398, 190, 143),
new("Pets", 487, 301, 122), new("Sports", 548, 327, 190), new("Toys", 643, 412, 236),
];
protected override Component? Render() =>
Ui.Chart.Value(Sales)[
Ui.ChartViewport.Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartGroup[
Ui.ChartBar.Field((Sale s) => s.Online).Class("text-blue-600"),
Ui.ChartBar.Field((Sale s) => s.Retail).Class("text-blue-500"),
Ui.ChartBar.Field((Sale s) => s.Wholesale).Class("text-blue-300")
],
Ui.ChartAxis.X.Field((Sale s) => s.Category)[Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.Y[Ui.ChartAxisGrid, Ui.ChartAxisTick]
]
],
Div.Class("flex justify-center gap-4 pt-4")[
Ui.ChartLegend.Key("online").Label("Online")[Ui.ChartLegendIndicator.Class("bg-blue-600")],
Ui.ChartLegend.Key("retail").Label("Retail")[Ui.ChartLegendIndicator.Class("bg-blue-500")],
Ui.ChartLegend.Key("wholesale").Label("Wholesale")[Ui.ChartLegendIndicator.Class("bg-blue-300")]
]
];
private sealed record Sale(string Category, int Online, int Retail, int Wholesale);
}Stacked bars
Bars on top of one another, the last one rounded.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartStackedBarsExample : Component
{
private static readonly Sale[] Sales =
[
new("Beauty", 342, 215, 108), new("Books", 356, 256, 215), new("Clothes", 432, 284, 176), new("Garden", 398, 190, 143),
new("Pets", 487, 301, 122), new("Sports", 548, 327, 190), new("Toys", 643, 412, 236),
];
protected override Component? Render() =>
Ui.Chart.Value(Sales)[
Ui.ChartViewport.Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartStack.Width("65%")[
Ui.ChartBar.Field((Sale s) => s.Online).Class("text-blue-600"),
Ui.ChartBar.Field((Sale s) => s.Retail).Class("text-blue-400"),
Ui.ChartBar.Field((Sale s) => s.Wholesale).Class("text-blue-300").Radius("4 0")
],
Ui.ChartAxis.X.Field((Sale s) => s.Category)[Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.Y[Ui.ChartAxisGrid, Ui.ChartAxisTick]
]
],
Div.Class("flex justify-center gap-4 pt-4")[
Ui.ChartLegend.Key("online").Label("Online")[Ui.ChartLegendIndicator.Class("bg-blue-600")],
Ui.ChartLegend.Key("retail").Label("Retail")[Ui.ChartLegendIndicator.Class("bg-blue-400")],
Ui.ChartLegend.Key("wholesale").Label("Wholesale")[Ui.ChartLegendIndicator.Class("bg-blue-300")]
]
];
private sealed record Sale(string Category, int Online, int Retail, int Wholesale);
}Pie and donut
A pie, a donut, and a donut with a figure in its hole. The slice under the pointer is marked.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartPieExample : Component
{
private static readonly Share[] Shares = [new("Subscriptions", 52), new("Services", 28), new("Training", 20)];
protected override Component? Render() =>
Div.Class("grid grid-cols-3 gap-6")[
Ui.Chart.Key("pie").Value(Shares)[
Ui.ChartViewport.Class("aspect-square")[
Ui.ChartSvg[Ui.ChartPie.Field((Share s) => s.Value).LabelField((Share s) => s.Label)]
]
],
Ui.Chart.Key("donut").Value(Shares)[
Ui.ChartViewport.Class("aspect-square")[
Ui.ChartSvg[Ui.ChartPie.Field((Share s) => s.Value).LabelField((Share s) => s.Label).InnerRadius("60%").Radius(4)]
]
],
Ui.Chart.Key("centre").Value(Shares)[
Ui.ChartViewport.Class("aspect-square")[
Ui.ChartSvg[Ui.ChartPie.Field((Share s) => s.Value).LabelField((Share s) => s.Label).InnerRadius("60%").Radius(4)],
Div.Class("pointer-events-none absolute inset-0 grid place-items-center")[
Div.Class("text-center")[Ui.Heading.Lg["$128k"], Ui.Text["Revenue"]]
]
]
]
];
private sealed record Share(string Label, int Value);
}Revenue
Slice colours
ColorField lets each row choose its hue, with a legend beside the donut.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartSliceColorsExample : Component
{
private static readonly Share[] Shares =
[
new("Subscriptions", 52, Ui.Color.Blue, "bg-blue-500"),
new("Services", 28, Ui.Color.Emerald, "bg-emerald-500"),
new("Training", 20, Ui.Color.Amber, "bg-amber-500"),
];
protected override Component? Render() =>
Ui.Card.Class("max-w-md")[
Ui.Chart.Value(Shares).Class("flex items-center gap-8")[
Ui.ChartViewport.Class("aspect-square w-36 shrink-0")[
Ui.ChartSvg[
Ui.ChartPie.Field((Share s) => s.Value).LabelField((Share s) => s.Label).ColorField((Share s) => s.Color)
.InnerRadius("60%").Radius(4).Class("dark:stroke-zinc-800")
]
],
Div.Class("flex-1")[
Shares.Select(share => Div.Key(share.Label).Class("flex items-center justify-between")[
Ui.ChartLegend.Label(share.Label)[Ui.ChartLegendIndicator.Class(share.Dot)],
Ui.Text.Sm.Class("tabular-nums")[$"{share.Value}%"]
])
]
]
];
private sealed record Share(string Label, int Value, Ui.Color Color, string Dot);
}52%
28%
20%
Live summary
Figures that read the row under the pointer, and the latest row when it leaves.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartSummaryExample : Component
{
private static readonly UiChartFormat Dollars = new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" };
// Yesterday's figure is today's, nudged by the hour: worked out, so the drawing is the same on every visit.
private static readonly Hour[] Today =
[
.. new[] { 299, 598, 1247, 1896, 2145, 2394, 2643, 2892, 3041, 3190, 3239 }
.Select((sales, hour) => new Hour(new DateTime(2026, 1, 1, 9, 0, 0, DateTimeKind.Unspecified).AddHours(hour), sales, sales + (hour % 3 * 150) - 100)),
];
protected override Component? Render() =>
Ui.Card[
Ui.Chart.Value(Today).Class("grid gap-6")[
Ui.ChartSummary.Class("flex gap-12")[
Div[
Ui.Text["Today"],
Ui.Heading.Xl.Class("mt-2 tabular-nums")[Ui.ChartSummaryValue.Field((Hour h) => h.Sales).Format(Dollars)],
Ui.Text.Class("mt-2 tabular-nums")[
Ui.ChartSummaryValue.Field((Hour h) => h.At)
.Format(new() { Hour = Ui.ChartFormatPart.Numeric, Minute = Ui.ChartFormatPart.Numeric, Hour12 = true })
]
],
Div[
Ui.Text["Yesterday"],
Ui.Heading.Lg.Class("mt-2 tabular-nums")[Ui.ChartSummaryValue.Field((Hour h) => h.Yesterday).Format(Dollars)]
]
],
Ui.ChartViewport.Class("aspect-3/1")[
Ui.ChartSvg[
Ui.ChartLine.Field((Hour h) => h.Yesterday).Class("text-zinc-300 dark:text-white/40").StrokeDasharray("4 4").Curve(Ui.ChartCurve.None),
Ui.ChartLine.Field((Hour h) => h.Sales).Class("text-sky-500 dark:text-sky-400").Curve(Ui.ChartCurve.None),
Ui.ChartAxis.X.Field((Hour h) => h.At)[Ui.ChartAxisGrid, Ui.ChartAxisTick, Ui.ChartAxisLine],
Ui.ChartAxis.Y[Ui.ChartAxisTick],
Ui.ChartCursor
]
]
]
];
private sealed record Hour(DateTime At, decimal Sales, decimal Yesterday);
}Today
Yesterday
Sparkline and dashboard stat
Bare numbers need no field; Gutter("0") draws to the edges.
namespace Rask.Site.Features.UiDocs.Examples;
public sealed partial class ChartSparklineExample : Component
{
protected override Component? Render() =>
Div.Class("flex items-start gap-8")[
Ui.Chart.Key("sparkline").Value([15, 18, 16, 19, 22, 25, 28, 25, 29, 28, 32, 35]).Class("aspect-3/1 w-20")[
Ui.ChartSvg.Gutter("0")[Ui.ChartLine.Class("text-green-500 dark:text-green-400")]
],
Ui.Card.Key("stat").Class("min-w-48 overflow-hidden")[
Ui.Text["Revenue"],
Ui.Heading.Xl.Class("mt-2 tabular-nums")["$12,345"],
Ui.Chart.Value([10, 12, 11, 13, 15, 14, 16, 18, 17, 19, 21, 20]).Class("-mx-6 -mb-6 h-12")[
Ui.ChartSvg.Gutter("4 0 0 0")[
Ui.ChartLine.Class("text-sky-200 dark:text-sky-400"),
Ui.ChartArea.Class("text-sky-100 dark:text-sky-400/30")
]
]
]
];
}Revenue
Behaviour
Drawn in C#
No chart library: the scales, the ticks and every path are computed during the render, to the numbers Flux's own layout arrives at, for the box the chart has in the browser (scripts/flux/parity-chart.mjs compares the two drawings' geometry, and with --pointer what each does under a pointer). What Flux's own script does after that, measuring and following the pointer, is the runtime's plot hook, by attribute.
The rows
Flux's chart takes an array of rows and its parts name a column with a string. Ui.Chart.Value(rows) takes the typed list, and each part takes a selector whose lambda states the row type once, .Field((Visit v) => v.Visitors), because a part is built before the chart it goes into.
A number of any numeric type plots without a cast; a DateTime, DateOnly or DateTimeOffset on the index axis makes it a time axis; anything else is a name. A chart of bare numbers needs no field at all: Ui.Chart.Value([15, 18, 16])[Ui.ChartSvg.Gutter("0")[Ui.ChartLine]].
Axes
The value axis starts at zero (or the lowest value below it) and steps by a round quarter of its span; TickCount, TickStart, TickEnd, TickValues, TickPrefix, TickSuffix and Position(Ui.Position.Right) are Flux's.
A time axis ticks at the pace of its rows and writes itself for its reach (9:17 AM, 9 AM, Tue 9 AM, Mar 10, Mar, 2026). Labels that would touch give way as Flux's do: dates drop every other one, names turn 45°.
Drawn for its box
As Flux's, the chart fills the box its class gives it (aspect-3/1, h-64) and is drawn for that box: the browser measures the drawing (the runtime's data-rask-measure hook) and the chart is drawn again in its units, when it first appears, 100ms after its box stops changing (a window resized, a phone turned), and when a hidden chart is shown at a new size; a hidden chart keeps its drawing. Its 12px labels are 12px at every width, and the ticks that fit are worked out again.
The first render happens before anything is measured, so it draws nothing: an empty box of the size its class gives it, as Flux's own first paint is, and the drawing arrives with the measurement. Every chart on a page is measured in the same browser task, and the events of one task are answered with one render: a Server page of sixty charts is one frame out and one patch back; in WebAssembly it never leaves the browser. A page prerendered for a WebAssembly app shows the empty boxes until the runtime has started.
How numbers and dates are written
Flux's :format is the options of Intl.NumberFormat and Intl.DateTimeFormat; UiChartFormat carries them under Intl's names, written with .NET formatting in the reader's culture: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" }, new() { Notation = Ui.ChartFormatNotation.Compact, MaximumFractionDigits = 1 }, new() { Month = Ui.ChartFormatPart.Short, Day = Ui.ChartFormatPart.Numeric }.
Carried: style (decimal, currency, percent, unit), currency, unit, notation (standard, compact, scientific), minimumFractionDigits, maximumFractionDigits, useGrouping, dateStyle, timeStyle, weekday, year, month, day, hour, minute, second, hour12. A date's parts are written in the order English writes them.
Not carried: compactDisplay: long, currencyDisplay, currencySign, signDisplay, unitDisplay, significant-digit and integer-digit limits, roundingMode, timeZone, timeZoneName, era, fractionalSecondDigits, dayPeriod, hourCycle, calendar, numberingSystem.
Under the pointer
Everything Flux's chart does under the pointer is done in the browser by the runtime's plot hook: no handler, no round trip per move. The row nearest the pointer along the index axis is the active one while the pointer is inside the plot. One cursor moves to it (a dashed line; Ui.ChartCursorType.Area covers the row's band), and one tooltip moves beside it, 15px from the row and from the pointer, flipped to the other side where it would pass the drawing's right or bottom edge. Its heading and values, and every Ui.ChartSummaryValue, read that row; a summary goes back to the latest row when the pointer leaves. The row's Ui.ChartPoints carry data-active.
On a pie the slice under the pointer carries data-active and the others data-inactive (.Class("transition-opacity data-inactive:opacity-40")), the tooltip follows the pointer, and a Ui.ChartTooltipIndicator takes the slice's colour.
Each part is rendered once with what it reads for every row (data-rask-plot-text), so fifty rows cost fifty short lines, not fifty tooltips. node scripts/flux/parity-chart.mjs --pointer walks a pointer over Flux's page and the kit's and compares.
Labels are measured in Inter
Flux sizes a chart's gutters by measuring its tick labels in the browser. The kit carries Inter's advance widths and kerning (UiChartInter, generated by scripts/flux/inter-metrics.mjs) and adds them up as Chromium does. In another face the labels still fit; the gutters are those Inter would have needed.
Reference
Ui.Chart
The chart: its rows, and the parts that draw them. Sized by its class, aspect-3/1 or h-64.
Step | Takes | What it does |
|---|---|---|
.Value(…) | a list of rows, or of numbers | The rows, one point, bar or slice each: Flux's wire:model and :value. |
.Horizontal() | bool | Puts the rows down the Y axis and their values along the X axis: bars on their side. |
Ui.ChartSvg
The drawing: the lines, areas, points, bars, pies and axes inside it.
Step | Takes | What it does |
|---|---|---|
.Gutter(…) | string | The space kept clear inside each edge, as a CSS padding: "12 0 12 8". 8 all round when unset; "0" for a sparkline. |
Ui.ChartViewport
The drawing's own box, when a legend or a summary shares the chart.
No steps of its own: what goes inside it is its content.
Ui.ChartLine
A line through one value of every row.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | What it reads from a row. The row itself when the chart holds bare numbers. |
.Curve(…) | Ui.ChartCurveSmooth None Each is a step of its own too, unless an HTML tag has its name. | How the points are joined. Smooth when unset. |
.StrokeDasharray(…) | string | The line's dashes: "4 4". |
Ui.ChartArea
The area under a line, filled.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | What it reads from a row. The row itself when the chart holds bare numbers. |
.Curve(…) | Ui.ChartCurveSmooth None Each is a step of its own too, unless an HTML tag has its name. | How the points are joined. Smooth when unset. |
Ui.ChartPoint
A dot on every row's value. The hovered row's carry data-active.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | What it reads from a row. |
.R(…) | Double | The dot's radius, in pixels. 4 when unset. |
.StrokeWidth(…) | Double | The ring in the surface colour that lifts a dot off its line. |
Ui.ChartBar
A bar for every row: alone, or in a group or a stack.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | What it reads from a row. |
.Radius(…) | string | How round its corners are: "4", or "4 0" for the value end and then the base. |
.Width(…) | string | How much of its slot it fills, as a percentage or in pixels: "85%". |
Ui.ChartGroup
Bars side by side in each row's slot.
Step | Takes | What it does |
|---|---|---|
.Width(…) | string | How much of a row's slot the group fills: "90%". |
Ui.ChartStack
Bars one on top of another in each row's slot.
Step | Takes | What it does |
|---|---|---|
.Width(…) | string | How much of a row's slot the stack fills: "65%". |
Ui.ChartPie
A slice per row, or a donut. The hovered slice carries data-active, the others data-inactive.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | The number that sets each slice's size. |
.LabelField(…) | a selector: (Visit v) => v.Visitors | What each slice is called, in the tooltip. |
.ColorField(…) | a selector: (Visit v) => v.Visitors | A Ui.Color each row chooses for its slice. The built-in palette in turn when unset. |
.InnerRadius(…) | string | The donut's hole, in pixels or as a share of the radius: "60%". |
.Radius(…) | Double | How round each slice's corners are, in pixels. |
Ui.ChartAxis
An axis, holding its ticks, grid, line and marks. .X and .Y say which.
Step | Takes | What it does |
|---|---|---|
.Axis(…) | Ui.ChartAxisAxisX Y Each is a step of its own too, unless an HTML tag has its name. | Which axis it is. |
.Field(…) | a selector: (Visit v) => v.Visitors | What names each row along the index axis. A date or time makes it a time axis. |
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How the tick labels are written: Intl's options, under Intl's names. |
.Position(…) | Ui.PositionDefault Top Right Bottom Left Each is a step of its own too, unless an HTML tag has its name. | Which side of the plot it sits on: Right for a value axis on the right. |
.TickCount(…) | int | About how many ticks. Five on a value axis; every row on a band axis. |
.TickStart(…) | Double | Where the value axis starts. Zero, or the lowest value below it, when unset. |
.TickEnd(…) | Double | Where the value axis ends. The tick just past the highest value when unset. |
.TickValues(…) | a list of numbers | The ticks themselves, in place of the round ones the axis would choose. |
.TickPrefix(…) | string | Written before every tick label: "$". |
.TickSuffix(…) | string | Written after every tick label: "MB". |
Ui.ChartAxisTick
The axis's labels.
Step | Takes | What it does |
|---|---|---|
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How they are written. The axis's own format when unset. |
Ui.ChartAxisGrid
A line across the plot at every tick.
Step | Takes | What it does |
|---|---|---|
.StrokeWidth(…) | Double | How thick the lines are. |
.StrokeDasharray(…) | string | Their dashes: "4 4". |
Ui.ChartAxisLine
The axis's own line along the plot's edge.
Step | Takes | What it does |
|---|---|---|
.StrokeWidth(…) | Double | How thick it is. |
Ui.ChartAxisMark
A short mark at every tick.
Step | Takes | What it does |
|---|---|---|
.Position(…) | Ui.PositionDefault Top Right Bottom Left Each is a step of its own too, unless an HTML tag has its name. | Which side of the plot they sit on. The axis's own when unset. |
.StrokeWidth(…) | Double | How thick they are. |
Ui.ChartZeroLine
A line at zero, where values run below it.
Step | Takes | What it does |
|---|---|---|
.StrokeWidth(…) | Double | How thick it is. |
Ui.ChartCursor
What marks the row under the pointer: one, moved by the browser.
Step | Takes | What it does |
|---|---|---|
.Type(…) | Ui.ChartCursorTypeLine Area Each is a step of its own too, unless an HTML tag has its name. | A dashed line through the row, or its whole band shaded. A line when unset. |
.StrokeWidth(…) | Double | How thick the line is. |
.StrokeDasharray(…) | string | Its dashes: "4 4". |
Ui.ChartTooltip
The box beside the row under the pointer: one, moved by the browser.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | The field it shows, when it holds no parts of its own. |
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How that field is written. |
Ui.ChartTooltipHeading
The tooltip's first line: the row's name or date.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | What it shows. |
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How it is written. |
Ui.ChartTooltipValue
A value of the row under the pointer, with its label.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | The number shown. |
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How it is written. |
.Label(…) | string | What comes before the number: a series' name. |
.LabelField(…) | a selector: (Visit v) => v.Visitors | A label read from the row instead: the hovered slice's name, on a pie. |
.Prefix(…) | string | Written before the number: "$". |
.Suffix(…) | string | Written after the number: "%". |
Ui.ChartTooltipIndicator
A dot beside a value, in the series' colour or the hovered slice's.
No steps of its own: what goes inside it is its content.
Ui.ChartSummary
Figures beside the chart that read the row under the pointer, and the latest row otherwise.
No steps of its own: what goes inside it is its content.
Ui.ChartSummaryValue
One figure of a summary.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | What it shows. |
.Fallback(…) | string | What it shows when there is no row to read. |
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How it is written. |
Ui.ChartLegend
One entry of a legend: a series' name and its indicator.
Step | Takes | What it does |
|---|---|---|
.Field(…) | a selector: (Visit v) => v.Visitors | The field the entry stands for. |
.Label(…) | string | The series' name. |
.Format(…) | a UiChartFormat: new() { Style = Ui.ChartFormatStyle.Currency, Currency = "USD" } | How the field's value is written. |
Ui.ChartLegendIndicator
The legend entry's dot; its class gives the colour.
No steps of its own: what goes inside it is its content.