How to create a Market Depth (Order Book) JavaScript Chart using Mountain Series and a Custom Modifier
drawExample.ts
index.html
vanilla.ts
theme.ts
DepthCursorModifier.ts
1import { appTheme } from "../../../theme";
2
3import {
4 SciChartSurface,
5 MouseWheelZoomModifier,
6 ZoomExtentsModifier,
7 XyDataSeries,
8 NumericAxis,
9 FastMountainRenderableSeries,
10 NumberRange,
11 EAutoRange,
12 EXyDirection,
13 EAxisAlignment,
14} from "scichart";
15import { DepthCursorModifier } from "./DepthCursorModifier";
16
17// SCICHART EXAMPLE
18
19export const drawExample = async (rootElement: string | HTMLDivElement) => {
20 // Create a SciChartSurface
21 const { wasmContext, sciChartSurface } = await SciChartSurface.create(rootElement, {
22 theme: appTheme.SciChartJsTheme,
23 });
24
25 const xAxis = new NumericAxis(wasmContext, {
26 axisAlignment: EAxisAlignment.Top,
27 labelPrecision: 4,
28 rotation: 90,
29 });
30
31 sciChartSurface.xAxes.add(xAxis);
32
33 const yAxis = new NumericAxis(wasmContext, {
34 autoRange: EAutoRange.Always,
35 growBy: new NumberRange(0, 0.05),
36 });
37 sciChartSurface.yAxes.add(yAxis);
38
39 const AAPL_data = {
40 buy: [
41 { price: 132.79743, volume: 339 },
42 { price: 132.79742, volume: 713 },
43 { price: 132.79741, volume: 421 },
44 { price: 132.7974, volume: 853 },
45 { price: 132.79739, volume: 152 },
46 { price: 132.79738, volume: 243 },
47 { price: 132.79737, volume: 296 },
48 { price: 132.79736, volume: 123 },
49 { price: 132.79735, volume: 158 },
50 { price: 132.79734, volume: 238 },
51 { price: 132.79733, volume: 164 },
52 { price: 132.79732, volume: 273 },
53 { price: 132.79731, volume: 35 },
54 { price: 132.79729, volume: 30 },
55 { price: 132.79726, volume: 29 },
56 { price: 132.79722, volume: 484 },
57 { price: 132.79721, volume: 458 },
58 { price: 132.7972, volume: 244 },
59 { price: 132.79719, volume: 10 },
60 { price: 132.79698, volume: 124 },
61 ],
62 sell: [
63 { price: 132.79744, volume: 847 },
64 { price: 132.79745, volume: 2412 },
65 { price: 132.79746, volume: 635 },
66 { price: 132.79747, volume: 323 },
67 { price: 132.79748, volume: 828 },
68 { price: 132.79749, volume: 322 },
69 { price: 132.7975, volume: 268 },
70 { price: 132.79751, volume: 92 },
71 { price: 132.79752, volume: 249 },
72 { price: 132.79753, volume: 189 },
73 { price: 132.79754, volume: 179 },
74 { price: 132.79755, volume: 122 },
75 { price: 132.79756, volume: 28 },
76 { price: 132.7976, volume: 114 },
77 { price: 132.79764, volume: 27 },
78 { price: 132.79767, volume: 10 },
79 { price: 132.79772, volume: 31 },
80 { price: 132.79785, volume: 484 },
81 { price: 132.79786, volume: 364 },
82 { price: 132.79787, volume: 244 },
83 ],
84 };
85
86 const buyValues: number[] = [];
87 let totalVol = 0;
88 for (const v of AAPL_data.buy) {
89 totalVol += v.volume;
90 buyValues.push(totalVol);
91 }
92 const sellValues: number[] = [];
93 totalVol = 0;
94 for (const v of AAPL_data.sell) {
95 totalVol += v.volume;
96 sellValues.push(totalVol);
97 }
98
99 const buySeries = new FastMountainRenderableSeries(wasmContext, {
100 dataSeries: new XyDataSeries(wasmContext, { xValues: AAPL_data.buy.map((v) => v.price), yValues: buyValues }),
101 stroke: "green",
102 fill: "00890033",
103 strokeThickness: 2,
104 isDigitalLine: true,
105 });
106 const sellSeries = new FastMountainRenderableSeries(wasmContext, {
107 dataSeries: new XyDataSeries(wasmContext, { xValues: AAPL_data.sell.map((v) => v.price), yValues: sellValues }),
108 stroke: "red",
109 fill: "89000033",
110 strokeThickness: 2,
111 isDigitalLine: true,
112 });
113 sciChartSurface.renderableSeries.add(buySeries, sellSeries);
114
115 xAxis.tickProvider.getMajorTicks = (minor, major, visibleRange) => {
116 const ticks: number[] = [];
117 const threshold = 400;
118 const buyYs = buySeries.dataSeries.getNativeYValues();
119 const buyXs = buySeries.dataSeries.getNativeXValues();
120 let lastY = 0;
121 for (let i = 0; i < buySeries.dataSeries.count(); i++) {
122 const y = buyYs.get(i);
123 if (y - lastY > threshold) {
124 ticks.push(buyXs.get(i));
125 }
126 lastY = y;
127 }
128 const sellYs = sellSeries.dataSeries.getNativeYValues();
129 const sellXs = sellSeries.dataSeries.getNativeXValues();
130 lastY = 0;
131 for (let i = 0; i < sellSeries.dataSeries.count(); i++) {
132 const y = sellYs.get(i);
133 if (y - lastY > threshold) {
134 ticks.push(sellXs.get(i));
135 }
136 lastY = y;
137 }
138 return ticks.sort((a, b) => a - b);
139 };
140
141 const depthModifier = new DepthCursorModifier({
142 buySeries,
143 sellSeries,
144 crosshairStrokeDashArray: [3, 2],
145 crosshairStrokeThickness: 3,
146 axisLabelFill: "transparent",
147 });
148 depthModifier.highlightColor = appTheme.DarkIndigo;
149 // Optional: Add some interactivity to the chart
150 sciChartSurface.chartModifiers.add(
151 new ZoomExtentsModifier(),
152 new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }),
153 depthModifier
154 );
155
156 sciChartSurface.zoomExtents();
157 xAxis.visibleRangeLimit = xAxis.visibleRange;
158 yAxis.visibleRangeLimit = yAxis.visibleRange;
159 return { sciChartSurface };
160};
161This example demonstrates how to build a high-performance Market Depth Chart using JavaScript and SciChart.js. It visualizes cumulative buy and sell order book data with two mountain series and a bespoke custom modifier that enhances mouse interactions, annotations, and hit testing.
The chart is initialized via the drawExample function which creates a SciChartSurface, configures NumericAxis, and instantiates two FastMountainRenderableSeries for buy and sell data. The custom modifier, DepthCursorModifier, is implemented directly using the core SciChart.js API to manage mouse events, dynamic annotations, and coordinate transformations. Developers can explore advanced customization through the Custom Chart Modifier API, which is leveraged to handle tasks such as updating crosshair lines and markers based on real-time mouse movement. The implementation also employs accurate hit testing using the RenderableSeries Hit-Test API and transforms canvas coordinates to data coordinates using the Axis APIs - Convert Pixel to Data Coordinates.
Key features include real-time updating of annotations, dynamic highlighting of data points, and robust mouse event handling that provides a seamless interactive experience. The chart efficiently computes the mid-price between buy and sell data points and highlights the interactive region with crosshair annotations.
This example follows best practices for resource management in JavaScript by providing a cleanup (destructor) function that disposes of the SciChartSurface when no longer needed. Additionally, performance optimizations are achieved through careful DPI scaling and efficient update routines as described in the Performance Tips & Tricks documentation. The implementation reinforces principles for developing high-performance, interactive charts while maintaining clear separation of concerns and robust handling of chart events.

Discover how to create a JavaScript Candlestick Chart or Stock Chart using SciChart.js. For high Performance JavaScript Charts, get your free demo now.

Easily create JavaScript OHLC Chart or Stock Chart using feature-rich SciChart.js chart library. Supports custom colors. Get your free trial now.

Create a JavaScript Realtime Ticking Candlestick / Stock Chart with live ticking and updating, using the high performance SciChart.js chart library. Get free demo now.

Create a Javascript heatmap chart showing historical orderbook levels using the high performance SciChart.js chart library. Get free demo now.

Create a JavaScript Multi-Pane Candlestick / Stock Chart with indicator panels, synchronized zooming, panning and cursors. Get your free trial of SciChart.js now.

Demonstrating the capability of SciChart.js to create a composite 2D & 3D Chart application. An example like this could be used to visualize Tenor curves in a financial setting, or other 2D/3D data combined on a single screen.

Create a JavaScript Multi-Pane Candlestick / Stock Chart with indicator panels, synchronized zooming, panning and cursors. Get your free trial of SciChart.js now.

Demonstrates how to place Buy/Sell arrow markers on a JavaScript Stock Chart using SciChart.js - Annotations API

This demo shows you how to create a <strong>{frameworkName} User Annotated Stock Chart</strong> using SciChart.js. Custom modifiers allow you to add lines and markers, then use the built in serialisation functions to save and reload the chart, including the data and all your custom annotations.