Skip to main content
Version: Next

Series primitives

Series primitives are extensions attached to a specific series. They can draw anywhere the series itself can appear: on the main pane, and on the price and time scales. Drawing tools, annotations, and custom axis labels are typically built as series primitives. For pane-bound primitives, see Pane primitives.

Attaching a primitive

Series primitives are defined by implementing the ISeriesPrimitive interface. The interface defines the views and renderers that draw on the chart with the CanvasRenderingContext2D API.

Create an instance of your primitive and attach it to a series with the attachPrimitive method:

javascript
class MyCustomPrimitive {
/* Class implementing the ISeriesPrimitive interface */
}

// Create an instantiated series primitive
const myCustomPrimitive = new MyCustomPrimitive();

const chart = createChart(document.getElementById('container'));
const lineSeries = chart.addSeries(LineSeries);

const data = [
{ time: 1642425322, value: 123 },
/* ... more data */
];
lineSeries.setData(data);

// Attach the primitive to the series
lineSeries.attachPrimitive(myCustomPrimitive);

To remove a primitive from a series, use the detachPrimitive method:

javascript
lineSeries.detachPrimitive(myCustomPrimitive);

How a primitive works

A primitive is built from three kinds of objects, each with one job:

  • the primitive itself owns the state — what to draw;
  • its views turn that state into coordinates — where to draw;
  • each view's renderer puts pixels on the canvas — the drawing itself.

When the chart needs to redraw, the library first lets the views recompute their coordinates, then collects them from the primitive and calls each view's renderer. This split lets the chart redraw frequently without recomputing, and recompute without recreating anything. The sections below describe each part of this cycle in detail.

Views

The primary purpose of a series primitive is to provide one, or more, views to the library which contain the state and logic required to draw on the chart panes.

The library invokes the following getter methods (if defined) to collect the primitive's views for each area of the chart:

GetterDraws onView interface
paneViewsMain chart paneIPrimitivePaneView
priceAxisPaneViewsPrice scale paneIPrimitivePaneView
timeAxisPaneViewsTime scale paneIPrimitivePaneView
priceAxisViewsLabels on the price scaleISeriesPrimitiveAxisView
timeAxisViewsLabels on the time scaleISeriesPrimitiveAxisView

Pane views draw with the CanvasRenderingContext2D API; axis views define labels on the corresponding scale.

Below is a visual example showing the various sections of the chart where a Primitive can draw.

 

IPrimitivePaneView

A pane view implements the IPrimitivePaneView interface. Its main job is to return a renderer that draws on the chart canvas. The renderer is a separate object implementing the IPrimitivePaneRenderer interface.

A view can also define a zOrder value that controls where in the visual stack its drawing appears: below the series, at the same level, or on top of everything. See PrimitivePaneViewZOrder for the available values.

Renderers should provide a draw method which will be given a CanvasRenderingTarget2D target on which it can draw. Additionally, a renderer can optionally provide a drawBackground method for drawing beneath other elements on the same zOrder. See the Canvas rendering target page for more details on CanvasRenderingTarget2D.

Interactive demo of zOrder layers

Below is an interactive demo chart illustrating where each zOrder is drawn relative to the existing chart elements such as the grid, series, and crosshair.

 

ISeriesPrimitiveAxisView

The ISeriesPrimitiveAxisView interface can be used to define a label on the price or time axis. This interface provides several methods to define the appearance and position of the label, such as the coordinate method, which should return the desired coordinate for the label on the axis. It also defines optional methods to set the fixed coordinate, text, text color, background color, and visibility of the label.

Lifecycle methods

A primitive can implement two optional lifecycle methods: attached and detached. They are the primitive's side of the attach/detach cycle: when your code calls attachPrimitive or detachPrimitive on a series, the library invokes the corresponding method in response. Use them to set up and clean up whatever the primitive needs, such as external objects or event handlers.

attached

This method is called when the primitive is attached to a chart. The attached method is invoked with a single argument containing properties for the chart, series, and a callback to request an update. The chart and series properties are references to the chart API and the series API instances for convenience purposes so that they don't need to be manually provided within the primitive's constructor (if needed by the primitive).

The requestUpdate callback allows the primitive to notify the chart that it should be updated and redrawn.

detached

This method is called when the primitive is detached from a chart. This can be used to remove any external objects or event handlers that were created during the attached lifecycle method.

Updating views

Your primitive should update the views in the updateAllViews method such that when the renderers are invoked, they can draw with the latest information. The library invokes this method when it wants to update and redraw the chart. If you would like to notify the library that it should trigger an update then you can use the requestUpdate callback provided by the attached lifecycle method.

Extending the autoscale info

The autoscaleInfo method can be provided to extend the base autoScale information of the series. This can be used to ensure that the chart is automatically scaled correctly to include all the graphics drawn by the primitive.

Whenever the chart needs to calculate the vertical visible range of the series within the current time range then it will invoke this method. This method can be omitted and the library will use the normal autoscale information for the series. If the method is implemented then the returned values will be merged with the base autoscale information to define the vertical visible range.

warning

This method will be invoked very often during scrolling and zooming of the chart, thus it is recommended that this method is either simple to execute, or makes use of optimizations such as caching to ensure that the chart remains responsive.