Chart panel
Frame a chart, report figure or map with a title, controls, legend and source information.
On this page
Processing time
Illustrative data · Monday through Sunday
- Service
- Comparison
Code
import { LineChart } from "@bosunkit/components/line-chart";
import { ChartLegend } from "@bosunkit/components/chart-legend";
import { ChartPanel } from "@bosunkit/components/chart-panel";
import type { ChartConfig } from "@bosunkit/components/chart-container";
import { ReferenceLine } from "recharts";
import type { ReactElement } from "react";
export const description: string =
"Illustrative processing times over a week, with a missing Wednesday and a reference at eight milliseconds.";
interface Sample {
readonly day: string;
readonly service: number | null;
readonly comparison: number | null;
}
const data: readonly Sample[] = [
{ day: "Mon", service: 6, comparison: 8 },
{ day: "Tue", service: 5, comparison: 7 },
{ day: "Wed", service: null, comparison: 7 },
{ day: "Thu", service: 4, comparison: 6 },
{ day: "Fri", service: 3, comparison: 5 },
{ day: "Sat", service: 4, comparison: 5 },
{ day: "Sun", service: 2, comparison: 4 },
];
// These are supplied display strings for the fixed, illustrative fixture. A consumer passes its quantity formatter.
const values: Readonly<Record<number, string>> = {
0: "0 ms",
1: "1 ms",
2: "2 ms",
3: "3 ms",
4: "4 ms",
5: "5 ms",
6: "6 ms",
7: "7 ms",
8: "8 ms",
9: "9 ms",
10: "10 ms",
};
const writeValue: (value: number) => string = (value: number): string => values[value] ?? "";
const writeDay: (value: string | number) => string = (value: string | number): string =>
typeof value === "string" ? value : "";
const config: ChartConfig<Sample> = {
service: { label: "Service", formatValue: writeValue },
comparison: { label: "Comparison", formatValue: writeValue },
};
export default function WeeklyLatency(): ReactElement {
return (
<ChartPanel
title="Processing time"
description="Illustrative data · Monday through Sunday"
legend={<ChartLegend config={config} label="Processing time series" />}
footer="Milliseconds per request · illustrative observations"
>
<LineChart
data={data}
categoryKey="day"
config={config}
series={["service", "comparison"]}
formatCategory={writeDay}
formatAxisValue={writeValue}
valueDomain={[0, 10]}
label="Illustrative processing times, Monday through Sunday"
categoryLabel="Day"
dataTableLabel="View processing times"
missingValueText="Not measured"
>
<ReferenceLine y={8} label={{ value: "Reference · 8 ms", position: "top" }} />
</LineChart>
</ChartPanel>
);
}
The chart panel names a region by its title. It places actions in the header, controls above the drawing, a legend below it and source information in the footer. The drawing and its data belong to its children.
Use
Loading, empty and error states occupy the plot's space. Empty and error states use caller-supplied messages and remove the plot. The chart container supplies its own definite height; the panel's minimum plot height does not size a percentage-height chart. A standalone legend receives its registry explicitly. A map, analytical chart or instrument trend can use the same frame.
Examples
Composition
Processing time
Illustrative data · Monday through Sunday
- Service
- Comparison
Code
import { LineChart } from "@bosunkit/components/line-chart";
import { ChartLegend } from "@bosunkit/components/chart-legend";
import { ChartPanel } from "@bosunkit/components/chart-panel";
import type { ChartConfig } from "@bosunkit/components/chart-container";
import { ReferenceLine } from "recharts";
import type { ReactElement } from "react";
export const description: string =
"Illustrative processing times over a week, with a missing Wednesday and a reference at eight milliseconds.";
interface Sample {
readonly day: string;
readonly service: number | null;
readonly comparison: number | null;
}
const data: readonly Sample[] = [
{ day: "Mon", service: 6, comparison: 8 },
{ day: "Tue", service: 5, comparison: 7 },
{ day: "Wed", service: null, comparison: 7 },
{ day: "Thu", service: 4, comparison: 6 },
{ day: "Fri", service: 3, comparison: 5 },
{ day: "Sat", service: 4, comparison: 5 },
{ day: "Sun", service: 2, comparison: 4 },
];
// These are supplied display strings for the fixed, illustrative fixture. A consumer passes its quantity formatter.
const values: Readonly<Record<number, string>> = {
0: "0 ms",
1: "1 ms",
2: "2 ms",
3: "3 ms",
4: "4 ms",
5: "5 ms",
6: "6 ms",
7: "7 ms",
8: "8 ms",
9: "9 ms",
10: "10 ms",
};
const writeValue: (value: number) => string = (value: number): string => values[value] ?? "";
const writeDay: (value: string | number) => string = (value: string | number): string =>
typeof value === "string" ? value : "";
const config: ChartConfig<Sample> = {
service: { label: "Service", formatValue: writeValue },
comparison: { label: "Comparison", formatValue: writeValue },
};
export default function WeeklyLatency(): ReactElement {
return (
<ChartPanel
title="Processing time"
description="Illustrative data · Monday through Sunday"
legend={<ChartLegend config={config} label="Processing time series" />}
footer="Milliseconds per request · illustrative observations"
>
<LineChart
data={data}
categoryKey="day"
config={config}
series={["service", "comparison"]}
formatCategory={writeDay}
formatAxisValue={writeValue}
valueDomain={[0, 10]}
label="Illustrative processing times, Monday through Sunday"
categoryLabel="Day"
dataTableLabel="View processing times"
missingValueText="Not measured"
>
<ReferenceLine y={8} label={{ value: "Reference · 8 ms", position: "top" }} />
</LineChart>
</ChartPanel>
);
}
Unavailable
Daily work
Monday through Friday
Code
import { ChartPanel } from "@bosunkit/components/chart-panel";
import type { ReactElement } from "react";
export const description: string = "An unavailable dataset has a specific message and no stale plot.";
export default function Unavailable(): ReactElement {
return (
<ChartPanel
title="Daily work"
description="Monday through Friday"
state="error"
stateMessage="The report could not be loaded. Your saved report is unchanged. Try opening it again."
/>
);
}
State and evidence around the drawing
Use the title to state the subject, the description to define the comparison, and the footer for source, period and aggregation. Keep a chart's unit and time reference visible when inspection is closed. A useful panel can contain a diagram or map as well as an analytical chart.
Distinguish an initial load from a refresh of known data. A successful query with no observations is different from a failed request. Supply the appropriate state and recovery action without changing the meaning of the window's label. Keep the source table and important conclusions accessible in a report or print view.
Props
appearance="analytical" uses the analytical surface, header divider and plot insets. It gives comparison
charts the reference dashboard's framing while the drawing, palette, labels and source values remain caller-supplied.
| Prop | Type | Default | Description |
|---|---|---|---|
| appearance | "default" | "analytical" | undefined | "default" | Default kit frame, or an analytical dashboard frame with a separated header and blue-reference roles. |
| titlerequired | ReactNode | – | The panel's title, as display text; it names the panel, which is then a region. |
| description | ReactNode | undefined | – | A line under the title saying what the chart shows and over what window. |
| headingLevel | NestedHeadingLevel | undefined | 3 | The level of the title's heading element, so the panel sits in the page's outline; 3 by default. |
| actions | ReactNode | undefined | – | Controls at the header's end: an icon button that opens the chart's page, a menu, a link. |
| controls | ReactNode | undefined | – | The toolbar between the header and the plot: a time range select, series filters, a granularity switch. |
| legend | ReactNode | undefined | – | The legend under the plot: the series' names and colors, or the map key. |
| footer | ReactNode | undefined | – | A row under the plot and the legend, set off by a rule: the source, or a time with its reference. |
| state | ChartPanelState | undefined | "ready" | What the plot shows. ready (the default) draws children; loading draws a placeholder of the plot's own
height; empty and error draw stateMessage in its place, the error in a message band. |
| stateMessage | ReactNode | undefined | – | The words shown instead of the plot when the state is empty or error; translated by the caller. |
| plotMinHeight | number | string | undefined | "10em" | The plot's smallest height: pixels, or any CSS length. 10em by default, so a responsive chart has room. |
| children | ReactNode | undefined | – | The chart drawing, with its axes and marks. |
| className | string | undefined | – | Classes added to the root's own. |
| testId | string | undefined | – | Becomes data-testid on the root; the parts are ${testId}--title, --controls, --plot, --legend and
--footer. |
| ref | Ref<HTMLElement> | undefined | – | The root element. |
Processing time
Illustrative data · Monday through Sunday
- Service
- Comparison
Keep a gap and describe the missing measurement in the source table.
Related
- Data visualization: scales, missing measurements and comparable evidence.
- Chart container: responsive drawing and registry scope.
- Sparkline: compact trends with operational integrity and forecast information.