Series
Custom series
Define your own series type. The engine maps time and autoscales; your view draws each item.
How custom series work
A custom series is a series type you define. The engine owns its time mapping, so it shares the time scale, logical ranges, and coordinates with built-in series. Your view owns the item shape and records draw commands for each frame. Those commands render at the series' place in the paint order and look identical on WebGPU and Canvas2D.
Experimental
Custom series are an experimental API. Their types may change in a minor release before 1.0.
The pane view
custom_series_pane_view
interface custom_series_pane_view {
// Price values for autoscale. The last element drives the last-price line and label.
price_value_builder(item: any): number[];
// Optional. Default: an item with only `time` is whitespace.
is_whitespace?(item: any): boolean;
// Engine series options merged under the caller's options.
default_options?: Record<string, unknown>;
// Record this frame's drawing. Synchronous; do not call chart APIs here.
render(ctx: custom_series_render_context): void;
// Release anything the view holds when the series is removed.
destroy?(): void;
}The render context
| Member | Description |
|---|---|
items | Visible, non-whitespace items in time order, each { x, item } with x in absolute bitmap pixels. |
bar_spacing | Current bar spacing in CSS pixels. Multiply by dpr for bitmap widths. |
price_to_y(price) | Bitmap y for a price on this series' scale, or null when the scale has no range. |
dpr | The device pixel ratio. |
pane_width, pane_height, pane_left, pane_top | Pane geometry in bitmap pixels. |
rect, rect_frame, round_rect | Filled, framed, and rounded rectangles. |
hline, vline, polyline | Lines with a width and line style. |
area_fill | A vertical gradient between a polyline and a base y. |
circle, triangle | Filled shapes, circles with an optional border. |
text | Text anchored at x and its vertical center, with color, size, font, weight, and align. |
Example: lollipop series
Lollipop series
const lollipops = chart.add_custom_series({
price_value_builder: (item) => [item.value],
render(ctx) {
const base = ctx.price_to_y(0);
for (const { x, item } of ctx.items) {
const y = ctx.price_to_y(item.value);
if (y === null || base === null) continue;
ctx.vline(x, base, y, "#787b86", ctx.dpr, "solid");
ctx.circle(x, y, 4 * ctx.dpr, item.value >= 0 ? "#26a69a" : "#ef5350");
}
},
});
lollipops.set_data([
{ time: 1735689600, value: 2.4 },
{ time: 1735776000, value: -1.1 },
{ time: 1735862400, value: 3.8 },
]);Data rules
- Items are
{ time, ...yourFields }. Times follow the same UTC-seconds rules as built-in series. - Out-of-order items are sorted and duplicate times keep the last item, the same repair built-in series get.
- An optional
colorfield on an item colors the last-price line and label for that item. data()returns your raw items.