JavaScript Chart with BaseValue Axes

Demonstrates how to create a JavaScript Chart with BaseValue axes using SciChart.js to build non-linear and custom-scaled axes

Fullscreen

Edit

 Edit

Docs

drawExample.ts

index.html

vanilla.ts

ExampleDataProvider.ts

theme.ts

Copy to clipboard
Minimise
Fullscreen
1import {
2    AnnotationDragDeltaEventArgs,
3    BaseValueAxis,
4    CoordinateCalculatorBase,
5    CursorModifier,
6    ELabelPlacement,
7    EllipsePointMarker,
8    EXyDirection,
9    FastLineRenderableSeries,
10    MouseWheelZoomModifier,
11    NumberRange,
12    NumericAxis,
13    SciChartSurface,
14    VerticalLineAnnotation,
15    XDataSeries,
16    XyDataSeries,
17    ZoomExtentsModifier,
18    ZoomPanModifier,
19} from "scichart";
20import { ExampleDataProvider } from "../../../ExampleData/ExampleDataProvider";
21import { appTheme } from "../../../theme";
22
23/**
24 * Generate baseValues for a non-linear scale based on a power law
25 * @param visibleRange The visible range to generate values for
26 * @param base The base for the power law (e.g., 10 for powers of 10)
27 * @returns An array of values based on the power law, including zero if in range
28 */
29const generatePowerLawBaseValues = (
30    visibleRange: NumberRange,
31    base: number = 10,
32    minimumPower: number = 1
33): number[] => {
34    const baseValues: number[] = [];
35
36    // Generate negative powers
37    if (visibleRange.min < 0) {
38        const lowPower = Math.ceil(Math.log(Math.abs(visibleRange.min)) / Math.log(base));
39        const max =
40            visibleRange.max >= 0 ? minimumPower : Math.floor(Math.log(Math.abs(visibleRange.max)) / Math.log(base));
41        for (let power = lowPower; power >= minimumPower; power--) {
42            const value = -Math.pow(base, power);
43            baseValues.push(value);
44        }
45    }
46
47    // Add zero if it's within the range
48    if (visibleRange.min <= 0 && visibleRange.max >= 0) {
49        baseValues.push(0);
50    }
51
52    // Generate positive powers
53    if (visibleRange.max > 0) {
54        const highPower = Math.ceil(Math.log(Math.abs(visibleRange.max)) / Math.log(base));
55        const min =
56            visibleRange.min <= 0 ? minimumPower : Math.floor(Math.log(Math.abs(visibleRange.min)) / Math.log(base));
57        for (let power = minimumPower; power <= highPower; power++) {
58            const value = Math.pow(base, power);
59            baseValues.push(value);
60        }
61    }
62    return baseValues;
63};
64
65export const drawExample = async (rootElement: string | HTMLDivElement) => {
66    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
67        theme: appTheme.SciChartJsTheme,
68    });
69
70    const xAxis = new BaseValueAxis(wasmContext, {
71        id: "BaseValueAxis",
72        visibleRange: new NumberRange(-0.1, 10.1),
73        flippedCoordinates: false,
74        labelPrecision: 3,
75        cursorLabelPrecision: 2,
76        baseValues: [0, 1, 2, 3, 4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 6, 7, 8, 9, 10],
77        // autoTicks: true,
78        // majorDelta: 10,
79        // minorDelta: 2,
80        // labelProvider: new NumericLabelProvider()
81    });
82    sciChartSurface.xAxes.add(xAxis);
83    const baseXValues = xAxis.getBaseValues() as XDataSeries;
84
85    // Generate baseYValues using power law with base 10
86    const initialVisibleRange = new NumberRange(-500, 500);
87    const powerLawBase = 10;
88    const baseYValueSeries = new XDataSeries(wasmContext, {
89        xValues: generatePowerLawBaseValues(initialVisibleRange, powerLawBase),
90    });
91
92    const yAxis = new BaseValueAxis(wasmContext, {
93        visibleRange: initialVisibleRange,
94        minorsPerMajor: 9,
95        baseValues: baseYValueSeries,
96        autoTicks: false,
97    });
98    yAxis.visibleRangeChanged.subscribe((data) => {
99        baseYValueSeries.clear();
100        baseYValueSeries.appendRange(
101            generatePowerLawBaseValues(yAxis.visibleRange.union(initialVisibleRange), powerLawBase)
102        );
103    });
104
105    yAxis.tickProvider.getMajorTicks = (
106        minorDelta: number,
107        majorDelta: number,
108        visibleRange: NumberRange,
109        coordCalc?: CoordinateCalculatorBase
110    ) => {
111        const ticks = generatePowerLawBaseValues(visibleRange, powerLawBase);
112        return ticks;
113    };
114
115    yAxis.tickProvider.getMinorTicks = (
116        minorDelta: number,
117        majorDelta: number,
118        visibleRange: NumberRange,
119        coordCalc?: CoordinateCalculatorBase
120    ) => {
121        const majors = generatePowerLawBaseValues(visibleRange, powerLawBase);
122        const minors: number[] = [];
123        for (let i = 0; i < majors.length - 1; i++) {
124            const cur = majors[i];
125            const next = majors[i + 1];
126            const mpm = yAxis.minorsPerMajor + (next === 0 || cur === 0 ? 1 : 0);
127            const step = (next - cur) / mpm;
128            for (let j = 1; j < mpm; j++) {
129                minors.push(cur + step * j);
130            }
131        }
132        return minors;
133    };
134
135    sciChartSurface.yAxes.add(yAxis);
136
137    const lineSeries = new FastLineRenderableSeries(wasmContext, {
138        stroke: "white",
139        pointMarker: new EllipsePointMarker(wasmContext, {
140            width: 9,
141            height: 9,
142            strokeThickness: 0,
143            fill: "steelblue",
144            stroke: "LightSteelBlue",
145        }),
146    });
147
148    lineSeries.rolloverModifierProps.tooltipTextColor = "black";
149
150    sciChartSurface.renderableSeries.add(lineSeries);
151
152    const { xValues, yValues } = ExampleDataProvider.getNoisySinewave(1000, 10, 10, 150, 20);
153    lineSeries.dataSeries = new XyDataSeries(wasmContext, { xValues: xValues, yValues });
154
155    // We use a hidden numeric axis synced to the BaseValue x axis to position the vertical line
156    const linearXAxis = new NumericAxis(wasmContext, {
157        isVisible: false,
158        visibleRange: xAxis.visibleRange,
159    });
160    sciChartSurface.xAxes.add(linearXAxis);
161    xAxis.visibleRangeChanged.subscribe((data) => (linearXAxis.visibleRange = data.visibleRange));
162
163    const magnifierAnnotation = new VerticalLineAnnotation({
164        xAxisId: linearXAxis.id,
165        x1: 5,
166        stroke: appTheme.MutedOrange,
167        strokeThickness: 3,
168        labelValue: "Drag Me!",
169        showLabel: true,
170        labelPlacement: ELabelPlacement.Top,
171        isEditable: true,
172        onDrag: (args: AnnotationDragDeltaEventArgs) => {
173            // Update the BaseValues adding more points around the annotation x coordinate, effectively zooming in that area and compressing elsewhere
174            const newBaseValues: number[] = [];
175            for (let x = 0; x <= 10; x++) {
176                if (x < args.sender.x1 - 0.5 || x > args.sender.x1 + 0.5) {
177                    newBaseValues.push(x);
178                } else {
179                    for (let d = -0.5; d <= 0.5; d += 0.1) {
180                        newBaseValues.push(args.sender.x1 + d);
181                    }
182                }
183            }
184            baseXValues.clear();
185            baseXValues.appendRange(newBaseValues);
186        },
187    });
188
189    sciChartSurface.annotations.add(magnifierAnnotation);
190
191    sciChartSurface.chartModifiers.add(
192        new ZoomPanModifier({ xyDirection: EXyDirection.XyDirection, includedXAxisIds: [xAxis.id] })
193    );
194    sciChartSurface.chartModifiers.add(new ZoomExtentsModifier({ includedXAxisIds: [xAxis.id] }));
195    sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier({ includedXAxisIds: [xAxis.id] }));
196    sciChartSurface.chartModifiers.add(new CursorModifier({ showAxisLabels: true }));
197
198    return { sciChartSurface, wasmContext };
199};
200

BaseValue Axes – JavaScript

Overview

This example demonstrates how to use the BaseValueAxis in SciChart.js to create non-linear, index-based axes that allow full control over how data is distributed along an axis. Unlike a standard NumericAxis, a BaseValueAxis spaces data points evenly by index while still preserving their original numeric values for labels, cursors, and annotations.

This approach makes it possible to compress, expand, or distort sections of the axis dynamically—enabling advanced visualization techniques such as log-linear scales, adaptive magnification, and gap compression.

How the BaseValueAxis Works

The BaseValueAxis operates by mapping data values to an internal index space defined by a set of base values. These base values:

  • Are spaced evenly along the axis (by index)
  • Define how real numeric values are interpolated between ticks
  • Can be dynamically changed at runtime

Instead of plotting points by their numeric distance, SciChart converts data values into indices using an IndexCalculator. This allows multiple data series with different sampling densities or clustered values to coexist on the same axis without distortion or gaps.

Technical Implementation

In this example, a BaseValueAxis is used for both the X and Y axes. The X-axis is initialized with an explicit array of base values, while the Y-axis dynamically generates base values using a power-law function to create a logarithmic-style scale.

The Y-axis base values are updated whenever the visible range changes, ensuring that tick marks and labels remain meaningful at all zoom levels. Custom tick providers are used to precisely control major and minor tick placement, demonstrating how the axis can be tailored for advanced numeric scales.

A hidden NumericAxis is synchronized with the BaseValue X-axis to allow precise placement of annotations. A draggable vertical line annotation dynamically modifies the base values, effectively creating a local magnification lens that expands detail around the cursor position while compressing the surrounding regions.

Features and Capabilities

Custom Non-Linear Scales: Create log-like, exponential, or irregular axes without sacrificing numeric accuracy or interaction support.

Dynamic Axis Warping: Modify base values in real time to zoom into specific regions while keeping the full dataset visible.

Precise Interaction Support: Cursor tooltips, annotations, and zooming remain accurate because numeric values are preserved internally.

High-Performance Rendering: All transformations are handled by SciChart’s WebAssembly engine, ensuring smooth interaction even with thousands of points.

Integration and Best Practices

The BaseValueAxis is ideal for advanced scientific, financial, or engineering charts where traditional linear or logarithmic axes are insufficient. It is especially useful for datasets with clustered values, uneven sampling, or where contextual magnification is required. For more details, see the BaseValue Axis documentation and related axis customization guides.

javascript Chart Examples & Demos

See Also: Charts added in v5 (9 Demos)

NEW!
JavaScript Trading Drawing Tools | Javascript Charts | SciChart.js

JavaScript Trading Drawing Tools

Create an interactive JavaScript trading charts for technical analysis. Trading Drawing Tools Demo, which shows how to use Polylines, Extended Lines, Rays, Channels, Pitchforks, Pitchfans, Fibonnaci Retracements, Measure, Stop Loss and Take Profit chart drawing tools for Technical Analysis.

NEW!
JavaScript Freehand Drawing Tools | SciChart.js Demo

JavaScript Freehand Drawing Tools

An example of using JavaScript FreehandDrawingModifier for arbitrary drawing on trading and financial charts. Can be used for drawing trends, arrow, markers, text, etc.

NEW!
JavaScript Chart with Smith Chart | SciChart.js Demo

JavaScript Chart with Smith Chart

Interactive JavaScript Smith chart for RF impedance matching — place markers, build matching networks step by step with the component chain, and switch between impedance and admittance grids.

NEW!
High Performance SVG Cursor & Rollover | SciChart.js Demo

High Performance SVG Cursor & Rollover

Demonstrates how to use the SVG render layer in SciChart.js to maintain smooth cursor interaction on heavy charts with millions of points.

NEW!
JavaScript Force Directed Graph | Javascript Charts | SciChart.js

JavaScript Force Directed Graph

JavaScript Force Directed Graph demo by SciChart.js. Visualize network graphs with physics simulation, interactive node dragging, and hover tooltips.

NEW!
JavaScript Overview for SubCharts with Range Selection

JavaScript Overview for SubCharts with Range Selection

Demonstrates how to create multiple synchronized subcharts with an overview range selector using SciChart.js and SubSurfaces

NEW!
JavaScript Orderbook Heatmap | Javascript Charts | SciChart.js

JavaScript Orderbook Heatmap

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

NEW!
High Precision Date Axis | Javascript Charts | SciChart.js Demo

High Precision Date Axis

Demonstrates 64-bit precision Date Axis in SciChart.js handling Nanoseconds to Billions of Years

NEW!
JavaScript Chart with DiscontinuousDateAxis Comparison

DiscontinuousDateAxis Comparison with Javascript

SciChart Ltd, 16 Beaufort Court, Admirals Way, Docklands, London, E14 9XL.