Custom drawer
Use a custom Drawer to render any canvas entity on the chart. Add the drawer using DrawingManager#addDrawer(drawer, name).
Static Line
This example shows how to draw a static vertical line on the chart.
import React, { useCallback } from 'react';import { DemoChart } from '../../../../src/components/DemoChart';import { Drawer } from '@devexperts/dxcharts-lite/dist/chart/drawers/drawing-manager';import { CanvasElement } from '@devexperts/dxcharts-lite/dist/chart/canvas/canvas-bounds-container';import { ChartBootstrap } from '../../../../src/utils/chart.model';class LineDrawer implements Drawer {constructor(private chart: ChartBootstrap) {}draw() {const canvasModel = this.chart.mainCanvasModel;const ctx = canvasModel.ctx;const chartBounds = this.chart.bounds.getBounds(CanvasElement.CHART);ctx.save();ctx.beginPath();ctx.strokeStyle = 'red';const lineX = chartBounds.x + 300;ctx.moveTo(lineX, chartBounds.y);ctx.lineTo(lineX, chartBounds.y + chartBounds.height);ctx.stroke();ctx.restore();}getCanvasIds(): Array<string> {return [this.chart.mainCanvasModel.canvasId];}}export const CustomDrawer = () => {const onChartCreated = useCallback((chart: ChartBootstrap) => {const lineDrawer = new LineDrawer(chart);chart.drawingManager.addDrawer(lineDrawer, 'drawer');}, []);return <DemoChart onChartCreated={onChartCreated} />;};
Result: A vertical line appears on the chart.
Use _chart.mainCanvasModel_ to access the chart canvas context and draw on it.
Convert timestamp to X coordinate
To get the X pixel position for a specific time (for example, to draw a vertical line at a timestamp), use ChartComponent#toXFromTimestamp:
const x = chart.toXFromTimestamp(timestamp);
Access the chart instance from ChartBootstrap (for example via chart.chartComponent).
Redraw a specific canvas
After updating custom drawer content, trigger a redraw for a specific canvas only:
chart.bus.fireDraw([canvasId]);
This is more performant than redrawing the entire chart. Custom drawers should return their canvas IDs from getCanvasIds().
Bind To Candle
To draw a vertical line from the bottom of the chart to a candle’s close price:
- Use
ChartModel#toXandChartModel#toYfor dynamic x/y coordinates. - Use
CanvasBoundsContainerto get updated layout bounds for all chart areas (chart, Y-axis, X-axis, studies, etc.).
import React, { useCallback } from 'react';import { DemoChart } from '../../../../src/components/DemoChart';import { CanvasElement } from '@devexperts/dxcharts-lite/dist/chart/canvas/canvas-bounds-container';import { lastOf } from '@devexperts/dxcharts-lite/dist/chart/utils/array.utils';import { clipToBounds } from '@devexperts/dxcharts-lite/dist/chart/utils/canvas/canvas-drawing-functions.utils';import { ChartBootstrap } from '../../../../src/utils/chart.model';import { Drawer } from '@devexperts/dxcharts-lite/dist/chart/drawers/drawing-manager';import { Candle } from '@devexperts/dxcharts-lite/dist/chart/model/candle.model';class LineCandleDrawer implements Drawer {constructor(private chart: ChartBootstrap) {}draw() {// chart dataconst canvasModel = this.chart.mainCanvasModel;const chartModel = this.chart.chartModel;// get chart bounds to correctly calculate X and Yconst chartBounds = this.chart.bounds.getBounds(CanvasElement.CHART);// candle dataconst candle: Candle | undefined = lastOf(chartModel.mainCandleSeries.dataPoints);const drawerX = chartModel.toX(candle?.idx ?? 0);const drawerY = chartModel.toY(candle?.close ?? 0);const ctx = canvasModel?.ctx;ctx.save();clipToBounds(ctx, chartBounds);ctx.beginPath();ctx.strokeStyle = 'red';ctx.moveTo(drawerX, 0);ctx.lineTo(drawerX, drawerY);ctx.stroke();ctx.restore();}getCanvasIds(): Array<string> {return [this.chart.mainCanvasModel.canvasId];}}export const CustomDrawerCandle = () => {const onChartCreated = useCallback((chart: ChartBootstrap) => {const drawer = new LineCandleDrawer(chart);chart.drawingManager.addDrawer(drawer, 'drawer');}, []);return <DemoChart onChartCreated={onChartCreated} />;};
Result: A vertical line that follows the last candle's close price.
Draw multiple lines
This example draws multiple horizontal lines—each from the Y-axis to a target candle.
import React, { useCallback } from 'react';import { DemoChart } from '../../../../src/components/DemoChart';import { Drawer } from '@devexperts/dxcharts-lite/dist/chart/drawers/drawing-manager';import { CanvasElement } from '@devexperts/dxcharts-lite/dist/chart/canvas/canvas-bounds-container';import { ChartBootstrap } from '../../../../src/utils/chart.model';import { CanvasModel } from '@devexperts/dxcharts-lite/dist/chart/model/canvas.model';class LineDrawer implements Drawer {private canvasModel: CanvasModel;constructor(private chart: ChartBootstrap) {this.canvasModel = this.chart.dynamicObjectsCanvasModel;}draw() {const ctx = this.canvasModel.ctx;const chartBounds = this.chart.bounds.getBounds(CanvasElement.CHART);ctx.save();ctx.beginPath();ctx.strokeStyle = '#FF00FF';const candleSeries = this.chart.chartModel.mainCandleSeries;candleSeries.getSeriesInViewport().flat().forEach(visualCandle => {const candleYs = visualCandle.yBodyKeyPoints(candleSeries.view);const x = visualCandle.xCenter(candleSeries.view);candleYs.forEach(y => {ctx.moveTo(x, y);ctx.lineTo(chartBounds.x + chartBounds.width, y);});});ctx.stroke();ctx.restore();}getCanvasIds(): Array<string> {return [this.canvasModel.canvasId];}}export const CustomDrawerLines = () => {const onChartCreated = useCallback((chart: ChartBootstrap) => {const lineDrawer = new LineDrawer(chart);chart.drawingManager.addDrawer(lineDrawer, 'drawer');}, []);return <DemoChart onChartCreated={onChartCreated} />;};
Result: Horizontal lines are drawn for each target candle.
Avoid partially erased lines
If drawn lines disappear or look clipped when the chart re-renders, verify that:
- You draw on the correct canvas (usually
dynamicObjectsCanvasModelfor custom overlays). - Line coordinates span the full drawable area — use
CanvasBoundsContainerbounds (from bottom to top of the chart area) rather than partial Y ranges that may fall outside the visible clip region. - Y coordinates are calculated with
ChartModel#toY(or candleyBodyKeyPoints) so they stay aligned with the price scale after zoom or pan.