Pie and donut
Setting chart.type to 'pie' renders the series as pie slices instead of an x/y plot. The createPie helper builds the pieces from labelled values: every slice is its own series, so the legend, focus and filtering behave exactly like the other chart types.
// createPie turns labelled values into pie pieces: every slice is its own
// series (so the legend lists the slices and clicking one filters it),
// and the data is a single row holding every slice value.
import { createPie } from '@mochart/core';
import type { MochartInputConfig } from '@mochart/core';
const pie = createPie(
[
{ label: 'Subscriptions', value: 420 },
{ label: 'Services', value: 210 },
{ label: 'Hardware', value: 140 },
{ label: 'Licensing', value: 75 },
{ label: 'Support', value: 65 },
{ label: 'Other', value: 30 }
],
// valuePercent puts each slice's share next to its value in the tooltip,
// e.g. "420 (44.7%)"
{ valueFormat: ',.0f', tooltipValueType: 'valuePercent' }
);
export const config: MochartInputConfig = {
version: '1.0.0',
title: { text: 'Revenue by Product (fictional, $k)' },
// chart.type 'pie' swaps the axis plot for the radial plot.
chart: pie.chart,
pie: pie.pie,
categoryAxis: pie.categoryAxis,
series: pie.series
};
export const data = pie.data;How it works
createPie(items, options)returns config fragments like the other chart-type helpers —chart(setting the type),pie,categoryAxis(naming the single category property) and oneseriesentry per slice — plus thedata, the clampedtotaland each slice'sfractions. The data is a single row:{ category: 'all', slice0: 420, slice1: 210, ... }(categoryValuerenames'all').computePieFractions(values)returns just the total and fractions.- Slices are series. Hovering a legend entry focuses its slice and clicking one filters it — the remaining slices grow to fill the circle, animated with the usual
animationtiming. To focus from the slice itself, set the series'focusOnHoverorfocusOnClick; anonSliceClickcallback reports slice clicks (see Interaction). Slice colors come from thecolorPaletteby series index, or from an explicit per-itemcolor. - On first load the pie sweeps in from the start angle over
animation.initialDuration(slice labels appear once the sweep settles). SettingfocusOffsetFraction"explodes" the focused slice away from the center, animated by the focus tween — try hovering the legend on the donut below. - Clicking the chart opens the tooltip with one row per slice. In pie mode
tooltip.snapToCategorydefaults tofalse, so the tooltip anchors at the click point, andtooltip.showCategorydefaults tofalse— a pie has a single category, so its value would head every tooltip. SetshowCategory: truewith a meaningfulcategoryValueif you want that line back. - The category and value axes still exist structurally (the category property and value domains feed the data model and animations) but default to
visible: falsein pie mode. The crosshair does not apply. - Values must be non-negative:
createPieclamps negatives to 0, and a zero-value slice simply doesn't render. Only the first data row is rendered.
Donut and slice labels
An inner radius via pie.innerRadiusFraction turns the pie into a donut — the helper's donut shorthand sets it to 0.6, and its own innerRadiusFraction option picks the exact value — and pie.label.visible puts value, percent or title labels on the slices.
// The donut option adds an inner radius, and tooltipValueType 'percent' makes the
// tooltip show each slice's share instead of its raw value. The chart computes
// those percentages from the current slice shares, so — like the percent slice
// labels below — they renormalize as slices are filtered.
import { createPie } from '@mochart/core';
import type { MochartInputConfig } from '@mochart/core';
const donut = createPie(
[
{ label: 'Chrome', value: 62 },
{ label: 'Safari', value: 20 },
{ label: 'Edge', value: 6 },
{ label: 'Firefox', value: 5 },
{ label: 'Opera', value: 3 },
{ label: 'Other', value: 4 }
],
{ donut: true, tooltipValueType: 'percent' }
);
export const config: MochartInputConfig = {
version: '1.0.0',
title: { text: 'Browser Market Share (fictional)' },
chart: donut.chart,
// label.visible puts percent labels at the slice centroids (slices thinner
// than label.minFraction hide theirs), and focusOffsetFraction explodes
// the hovered slice away from the center.
pie: { ...donut.pie, label: { visible: true, type: 'percent' }, focusOffsetFraction: 0.05 },
categoryAxis: donut.categoryAxis,
series: donut.series
};
export const data = donut.data;label.typepicks the label content: a single part ('value','percent'— the default — or'title') or a combination —'valuePercent'for420 (45%),'percentValue'for45% (420),'titleValue'forSubscriptions: 420and'titlePercent'forSubscriptions: 45%.label.valueFormatandlabel.percentFormatformat the two numeric parts independently (percent parts format the fraction, so specifiers like'.1%'apply).label.radiusFractionplaces the labels between the inner and outer radius (default 0.5, midway), and slices thinner thanlabel.minFractionhide their labels. Label colors reuse the per-serieslabel.textStyle— each slice is a series, so a slice's label is styled by its own series entry.- When slices are filtered via the legend, percent labels renormalize against the remaining slices — set
label.adjustForFilteringtofalseto keep every slice's share of the full total instead. tooltip.valueTypedoes the same for the tooltip rows:'value'(the default),'percent', or the'valuePercent'/'percentValue'combinations. The value part keeps its per-series formatting (valueFormat,valuePrefix,valueSuffix) — the helper'svalueFormatoption stamps one format onto every slice's series; the percent part is formatted bytooltip.percentFormat. The helper'stooltipValueTypeoption forwards straight to it.- Tooltip percentages are computed from the same slice shares as the labels, so they renormalize as slices are filtered — set
tooltip.adjustForFilteringtofalseto keep every slice's share of the full total (the tooltip equivalent oflabel.adjustForFiltering). A filtered slice's own row shows the usualfilteredValueCharacterplaceholder in place of both parts. - Geometry knobs:
startAnglerotates the first slice's starting edge,padAngleopens a gap between slices,cornerRadiusrounds the slice corners, andouterRadiusFractionshrinks the pie inside the plot.
Half pies and gauges
endAngle defaults to startAngle + 360 (a full circle, so rotating with startAngle alone never truncates the pie); setting it explicitly confines the slices to a partial span. With startAngle: -90 and endAngle: 90 the pie becomes a half-donut gauge — an endAngle smaller than startAngle runs counterclockwise.
// startAngle/endAngle confine the slices to a partial span — here a half
// donut — and the pie center can carry a label plus a live total that counts
// along with value changes and filtering.
import { createPie } from '@mochart/core';
import type { MochartInputConfig } from '@mochart/core';
const gauge = createPie(
[
{ label: 'Promoters', value: 540 },
{ label: 'Passives', value: 280 },
{ label: 'Detractors', value: 180 }
],
// percentValue pairs each segment's share with its response count, e.g.
// "54.0% (540)"
{ tooltipValueType: 'percentValue' }
);
export const config: MochartInputConfig = {
version: '1.0.0',
title: { text: 'Customer Sentiment (fictional survey)' },
chart: gauge.chart,
pie: {
...gauge.pie,
startAngle: -90,
endAngle: 90,
innerRadiusFraction: 0.55,
// a small gap and rounded corners separate the segments
padAngle: 1,
cornerRadius: 3,
label: {
visible: true,
type: 'title'
},
// the center total tracks the unfiltered slices, so clicking a legend
// entry counts it down; the negative Y offset lifts it off the gauge
// pivot into the hole
centerLabel: { text: 'responses' },
centerTotal: {
visible: true,
format: ',.0f'
},
centerOffsetYFraction: -0.25
},
categoryAxis: gauge.categoryAxis,
series: gauge.series
};
export const data = gauge.data;centerLabelputs a text line at the circle center, andcenterTotal.visibleadds the live total of the unfiltered slice values, formatted bycenterTotal.format— it counts along with value tweens and filtering (click a legend entry). SetcenterTotal.adjustForFilteringtofalseto keep the full total while slices are filtered.- The center content sits at the circle center (the gauge pivot);
centerOffsetXFractionandcenterOffsetYFractionnudge it by fractions of the outer radius — the example's-0.25lifts it into the hole. - The center text is styled by
centerLabel.textStyleandcenterTotal.textStyle, both defaulting tofillColor: 'currentColor'so the text follows the host page's CSScolor. It can also be restyled directly: CSS wins over the presentation attribute, so targeting.mochart-pie-center textworks (the demo dark theme does exactly this). - The layout fits the configured span's bounding box into the plot, so a half pie uses the space its missing half would waste (and the radius grows accordingly) instead of staying centered in an empty square. The span comes from the config, so the fit holds still while values animate.