Skip to content

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

Render context
MemberDescription
itemsVisible, non-whitespace items in time order, each { x, item } with x in absolute bitmap pixels.
bar_spacingCurrent 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.
dprThe device pixel ratio.
pane_width, pane_height, pane_left, pane_topPane geometry in bitmap pixels.
rect, rect_frame, round_rectFilled, framed, and rounded rectangles.
hline, vline, polylineLines with a width and line style.
area_fillA vertical gradient between a polyline and a base y.
circle, triangleFilled shapes, circles with an optional border.
textText 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 color field on an item colors the last-price line and label for that item.
  • data() returns your raw items.