JavaScript Chart - Examples
SciChart.js ships with over 80 JavaScript Chart demos which you can browse, view the source code and see related documentation. Build incredible complex dashboards with SciChart.js, our High Performance JavaScript Chart Library.
Demonstrates how to use SciChart.js to create a Market Depth Chart – a type of visualisation of the order book on a financial or trading exchange.
Rendering a Depth Chart in JavaScript
It’s simple to create a Depth Chart using SciChart.js. If you have order book data, you can calculate a cumulative sum and draw the result as two mountain charts. See the code below:
const AAPL_data = {
buy: [
{ price: 132.79743, volume: 339 },
{ price: 132.79742, volume: 713 },
{ price: 132.79741, volume: 421 },
{ price: 132.7974, volume: 853 },
{ price: 132.79739, volume: 152 },
{ price: 132.79738, volume: 243 },
{ price: 132.79737, volume: 296 },
{ price: 132.79736, volume: 123 },
{ price: 132.79735, volume: 158 },
{ price: 132.79734, volume: 238 },
{ price: 132.79733, volume: 164 },
{ price: 132.79732, volume: 273 },
{ price: 132.79731, volume: 35 },
{ price: 132.79729, volume: 30 },
{ price: 132.79726, volume: 29 },
{ price: 132.79722, volume: 484 },
{ price: 132.79721, volume: 458 },
{ price: 132.7972, volume: 244 },
{ price: 132.79719, volume: 10 },
{ price: 132.79698, volume: 124 }
],
sell: [
{ price: 132.79744, volume: 847 },
{ price: 132.79745, volume: 2412 },
{ price: 132.79746, volume: 635 },
{ price: 132.79747, volume: 323 },
{ price: 132.79748, volume: 828 },
{ price: 132.79749, volume: 322 },
{ price: 132.7975, volume: 268 },
{ price: 132.79751, volume: 92 },
{ price: 132.79752, volume: 249 },
{ price: 132.79753, volume: 189 },
{ price: 132.79754, volume: 179 },
{ price: 132.79755, volume: 122 },
{ price: 132.79756, volume: 28 },
{ price: 132.7976, volume: 114 },
{ price: 132.79764, volume: 27 },
{ price: 132.79767, volume: 10 },
{ price: 132.79772, volume: 31 },
{ price: 132.79785, volume: 484 },
{ price: 132.79786, volume: 364 },
{ price: 132.79787, volume: 244 }
]
};
const buyValues: number[] = [];
let totalVol = 0;
for (const v of AAPL_data.buy) {
totalVol += v.volume;
buyValues.push(totalVol); // Calculate cumulative sum
}
const sellValues: number[] = [];
totalVol = 0;
for (const v of AAPL_data.sell) {
totalVol += v.volume;
sellValues.push(totalVol);
}
// Render as mountain series
const buySeries = new FastMountainRenderableSeries(wasmContext, {
dataSeries: new XyDataSeries(wasmContext, { xValues: AAPL_data.buy.map(v => v.price), yValues: buyValues}),
stroke: "green",
fill: "00890033",
strokeThickness: 2,
isDigitalLine: true,
});
const sellSeries = new FastMountainRenderableSeries(wasmContext, {
dataSeries: new XyDataSeries(wasmContext, { xValues: AAPL_data.sell.map(v => v.price), yValues: sellValues}),
stroke: "red",
fill: "89000033",
strokeThickness: 2,
isDigitalLine: true,
});
sciChartSurface.renderableSeries.add(buySeries, sellSeries);
Adding Interactivity on Mouse-Over
The interactivity on mouse-over is provided by a custom Chart Modifier, which manages 8 annotations (LineAnnotation, BoxAnnotation and TextAnnotation) updating the cursor as the user moves the mouse.
SciChart.js has a rich ChartModifier API which allows you to add zooming, panning, tooltip behaviours to charts. You can also create your own custom modifiers. Below we add a custom modifier called the DepthCursorModifier to the chart.
const depthModifier = new DepthCursorModifier({
buySeries, sellSeries,
crosshairStrokeDashArray: [3,2], crosshairStrokeThickness: 3,
axisLabelFill: "transparent"
});
depthModifier.highlightColor = appTheme.DarkIndigo;
// Optional: Add some interactivity to the chart
sciChartSurface.chartModifiers.add(new ZoomExtentsModifier(),
new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection}),
depthModifier);
How the DepthCursorModifier works
Source code for the DepthCursorModifier is included in the Github links below, as well as a link to the source for the overall example/demo.
The DepthCursorModifier overrides onAttach and creates a number of annotations for the lines, text and highlight area on the chart.
public onAttach(): void {
super.onAttach();
this.xBuyLineAnnotation = this.createLineAnnotation(this.buyColor, this.axisLabelFill, this.axisLabelStroke);
this.yBuyLineAnnotation = this.createLineAnnotation(this.buyColor, this.axisLabelFill, this.axisLabelStroke);
this.yBuyLineAnnotation.showLabel = true;
this.xSellLineAnnotation = this.createLineAnnotation(this.sellColor, this.axisLabelFill, this.axisLabelStroke);
this.ySellLineAnnotation = this.createLineAnnotation(this.sellColor, this.axisLabelFill, this.axisLabelStroke);
this.ySellLineAnnotation.showLabel = true;
this.parentSurface.modifierAnnotations.add(this.xBuyLineAnnotation, this.yBuyLineAnnotation, this.xSellLineAnnotation, this.ySellLineAnnotation);
this.createMarkers();
this.parentSurface.modifierAnnotations.add(this.buySeries.rolloverModifierProps.marker, this.sellSeries.rolloverModifierProps.marker);
this.buyLabel = this.createTextAnnotation(EHorizontalAnchorPoint.Right);
this.sellLabel = this.createTextAnnotation(EHorizontalAnchorPoint.Left);
this.parentSurface.modifierAnnotations.add(this.buyLabel, this.sellLabel);
this.midLine = new VerticalLineAnnotation({
stroke: "white",
strokeDashArray: [3,2],
showLabel: true,
axisLabelFill: "white",
labelPlacement: ELabelPlacement.Top
});
this.parentSurface.modifierAnnotations.add(this.midLine);
this.highlightBox = new BoxAnnotation({
xCoordinateMode: ECoordinateMode.Pixel,
yCoordinateMode: ECoordinateMode.Relative,
strokeThickness: 0,
fill: this.highlightColor,
opacity: 0.3,
isHidden: true,
y1: 0,
y2: 1
});
this.parentSurface.modifierAnnotations.add(this.highlightBox);
}
Next, on mouse-over, onModifierMouseMove is called. This calls update() to update the positions of the annotations.
public modifierMouseMove(args: ModifierMouseArgs): void {
super.modifierMouseMove(args);
let translatedMousePoint: Point;
if (!this.mousePoint) {
this.mousePosition = EMousePosition.OutOfCanvas;
} else {
translatedMousePoint = translateFromCanvasToSeriesViewRect(
this.mousePoint,
this.parentSurface.seriesViewRect
);
if (!translatedMousePoint) {
this.mousePosition = EMousePosition.AxisArea;
} else {
this.mousePosition = EMousePosition.SeriesArea;
}
}
this.update();
}
The update() function uses our APIs to perform hit-test (convert mouse-coordinate to data-coordinate on series), as well as coordinate conversion to place the annotations on the chart.
Try mouse-over or touch the chart to see the annotations update!
You can also try making the Depth Chart dynamic by updating the data in the XyDataSeries.