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:
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:
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:
| Getter | Draws on | View interface |
|---|---|---|
paneViews | Main chart pane | IPrimitivePaneView |
priceAxisPaneViews | Price scale pane | IPrimitivePaneView |
timeAxisPaneViews | Time scale pane | IPrimitivePaneView |
priceAxisViews | Labels on the price scale | ISeriesPrimitiveAxisView |
timeAxisViews | Labels on the time scale | ISeriesPrimitiveAxisView |
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.
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.