Skip to content

Bar caps

capType draws a decorative cap on the value end of every bar in a series — the quickest way to the popular rounded-bar look, with two more shapes beside it.

ts
// capType draws a decorative cap on the value end of every bar in a series:
// 'round' rounds the corners, 'curve' bulges a dome, 'point' rises to a peak.
// The shared capSize sits in seriesDefaults; each series picks its shape.
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'Cap Shapes' },
  categoryAxis: { property: 'quarter', type: 'string', scale: 'ordinal' },
  valueAxes: [{ id: 'VA0', min: 0 }],
  seriesDefaults: { renderer: 'bar', capSize: 10 },
  series: [
    { property: 'round', title: 'round', capType: 'round' },
    { property: 'curve', title: 'curve', capType: 'curve' },
    { property: 'point', title: 'point', capType: 'point' }
  ],
  seriesGroups: [{ id: 'caps' }]
};

export const data = [
  { quarter: 'Q1', round: 38, curve: 31, point: 26 },
  { quarter: 'Q2', round: 44, curve: 36, point: 33 },
  { quarter: 'Q3', round: 41, curve: 42, point: 30 },
  { quarter: 'Q4', round: 49, curve: 39, point: 37 }
];

How it works

  • capType picks the shape: round rounds the bar's end corners, curve bulges a quadratic dome, point rises to a triangular peak; null (the default) leaves the end flat. capSize sets the cap's extent in pixels.
  • The cap is part of the bar's shape, drawn at the value end and pointing the bar's way — negative bars cap downward, and on an inverted chart the caps sit on the bars' side ends. Fills, gradients and per-row colors apply to the cap like the rest of the bar.
  • When a bar is shorter than its cap, capExpand decides what gives: true (the default) keeps the cap at full size, false shrinks the cap to fit the bar. The Capped Bars demo in the gallery draws every shape both ways on an axis pinned well past the data, so the difference is easy to compare.

Capping a stack

On stacked bars, capping every segment looks broken — usually only the stack's outer end should be capped. Declare the cap on the stack instead of the series:

ts
// On a stack, capping every segment looks broken — the stack's outerCapType
// caps only its outer end instead. No per-series cap config needed: any
// series without its own capType wears the stack cap when it is the outer
// segment, so the cap follows legend filtering.
import type { MochartInputConfig } from '@mochart/core';

export const config: MochartInputConfig = {
  version: '1.0.0',
  title: { text: 'Revenue by Product' },
  categoryAxis: { property: 'quarter', type: 'string', scale: 'ordinal' },
  seriesDefaults: { renderer: 'bar' },
  series: [
    { property: 'starter', title: 'Starter' },
    { property: 'pro', title: 'Pro' },
    { property: 'enterprise', title: 'Enterprise' }
  ],
  seriesStacks: [{ id: 'revenue', outerCapType: 'round', outerCapSize: 8 }]
};

export const data = [
  { quarter: 'Q1', starter: 10, pro: 14, enterprise: 8 },
  { quarter: 'Q2', starter: 12, pro: 18, enterprise: 11 },
  { quarter: 'Q3', starter: 11, pro: 22, enterprise: 16 },
  { quarter: 'Q4', starter: 13, pro: 25, enterprise: 22 }
];
  • outerCapType (with outerCapSize and outerCapExpand) caps whichever series is the stack's outer segment at each category — no per-series cap config needed. Filter the top series in the legend and the cap moves to the segment that becomes outermost.
  • A stack mixing positive and negative values gets an outer cap on each end: the topmost positive segment and the bottommost negative one.
  • A series that sets its own capType keeps it even in a stack; add capOnlyStackOuter to draw that cap only where the series is the outer segment — for a cap that should differ from the stack-level one.

Grouped bars need no special handling — each series caps its own bars, as in the first example.

Released under the BSD-3-Clause License.