Skip to main content

The chart extension

mc-semantic-ui-ext-chart brings both halves of chart: the UiChart node type and the two painters that draw it — one for the browser, one for server-side rendering.

That pairing is the rule the project follows: a node type and the ability to render it belong in the same place. The core owns only what it can actually draw, so it never promises a picture it cannot produce, and never has to depend on a charting library. chart is therefore not part of the core vocabulary — add this module and the node appears in the Java model, in Jackson, in the browser renderer and in SSR at once.

Live — four chart types from one data set. Hover a bar or a segment for its value; those tooltips are native SVG <title>s, not JavaScript.

What you get

Node typechart (UiChart), contributed by this module
TypesBAR, LINE, AREA, PIE, DONUT
Outputplain SVG — no canvas, no charting library, no runtime dependency
Works without JavaScriptyes, when rendered server-side

The diagram extension is built the same way, and is the model to copy if you write your own.

Install

<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-semantic-ui-ext-chart</artifactId>
<version>0.2.2</version>
</dependency>

Nothing else to configure. The module ships templates/sui/chart.hbs plus the Handlebars helper it needs, contributed through SuiHelperContributor — found either as a Spring bean or via ServiceLoader, so it works in a plain-Java app with no Spring on the classpath.

@GetMapping("/dashboard")
public UiPage dashboard() {
var chart = new UiChart();
chart.setId("revenue");
chart.setTitle("Revenue");
chart.setChartType(UiChart.ChartType.BAR);
chart.setData(quarterlyRevenue()); // labels + one series
return UiPage.of("/dashboard", chart);
}
A chart that survives JavaScript being off

The server-rendered output is static SVG with <title> tooltips — no script tag anywhere. That makes it the rare chart that still works in an email client, a PDF export, or a hardened browser.

The node

FieldTypeMeaning
idStringNode id — also the DOM id and the patch target.
titleStringOptional heading rendered above the chart (<h2>).
chartTypeLINE · BAR · PIE · DONUT · AREAWhich chart to draw.
dataUiChart.ChartDataThe payload.
cssClassStringExtra CSS class on the wrapper <div>.

UiChart.ChartData and its nested Series:

FieldTypeMeaning
data.labelsList<String>Category labels — the x axis, or the pie slice names.
data.seriesList<ChartData.Series>One or more series.
series[].nameStringSeries name, for legends and tooltips.
series[].valuesList<Number>The values, positionally aligned with labels.

There are no colour, axis, legend or scale fields. Anything of that kind is the painter's business, not the model's.

Building one

var data = new UiChart.ChartData();
data.setLabels(List.of("Q1", "Q2", "Q3", "Q4"));

var revenue = new UiChart.ChartData.Series();
revenue.setName("Revenue");
revenue.setValues(List.of(24, 38, 30, 45));
data.setSeries(List.of(revenue));

UiChart.of("chart-revenue", "Revenue by quarter", UiChart.ChartType.BAR, data);

data is intentionally minimal. Labels plus named numeric series is the common denominator every charting library accepts. If your chart needs more (stacking, dual axes, time scales), carry it in your own extension node type rather than stretching UiChart.

Charts nest. A chart is a plain node, so it fits anywhere a node fits — including a tree-node's content slot or a detail panel.

Both renderers draw the same picture

The painter exists twice — ChartPainter.java and chart/extension.ts — because the project renders from both sides. They are held to byte-identical output: every chart type is rendered through both and diffed.

Three formatting rules exist only to keep that true, and each is pinned by a test because each one actually broke once:

RuleWhy
Whole numbers print without .0Java would write 30.0 where JS writes 30 — visible in tooltips
Negative zero is collapsedThe first pie segment starts at -0.0: Java prints -0.00, JS prints 0.00
Decimals always use a pointA German default locale would produce 12,5 and break the SVG

Swapping the painter

install() is one renderer.register("chart", …) call. Registering your own handler afterwards replaces it, which is how you swap in a charting library or a different look:

installChart(renderer);
renderer.register("chart", (node) => `<div class="sui-chart" id="${node.id}">…</div>`);

The handler receives the node and returns an HTML string, exactly like the built-in renderers — see adding a node type of your own; the mechanism is identical, except that chart already has a Java model, so you only supply the drawing half.

Styling

Colours come from CSS variables with literal fallbacks, so a chart restyles from your stylesheet and still renders standalone:

:root {
--sui-chart-1: #0f766e;
--sui-chart-2: #b91c1c;
/* … up to --sui-chart-6 */
}

Layout (size, legend placement, the empty state) lives in /sui-ext/chart/chart.css — override the .sui-chart* classes to change it.

See also