SciChart.js - High Performance Realtime Javascript Charts Examples Suite

JavaScript Heatmap Chart

Demonstrates how to create a JavaScript Heatmap Chart using SciChart.js, High Performance JavaScript Charts

When click Start first time data is being generated, it could take a while

Source Code

View on GitHub
import * as React from "react";
import { NumericAxis } from "scichart/Charting/Visuals/Axis/NumericAxis";
import { SciChartSurface } from "scichart";
import { UniformHeatmapDataSeries } from "scichart/Charting/Model/UniformHeatmapDataSeries";
import { UniformHeatmapRenderableSeries } from "scichart/Charting/Visuals/RenderableSeries/UniformHeatmapRenderableSeries";
import { HeatmapColorMap } from "scichart/Charting/Visuals/RenderableSeries/HeatmapColorMap";
import { ZoomPanModifier } from "scichart/Charting/ChartModifiers/ZoomPanModifier";
import { ZoomExtentsModifier } from "scichart/Charting/ChartModifiers/ZoomExtentsModifier";
import { MouseWheelZoomModifier } from "scichart/Charting/ChartModifiers/MouseWheelZoomModifier";
import { zeroArray2D } from "scichart/utils/zeroArray2D";

const divElementId = "chart";
const cachedHeatmapDataForExample: number[][][] = [];
const MAX_SERIES = 20;
const WIDTH = 300;
const HEIGHT = 200;

const drawExample = async () => {
    const { sciChartSurface, wasmContext } = await SciChartSurface.create(divElementId);
    sciChartSurface.xAxes.add(new NumericAxis(wasmContext));
    sciChartSurface.yAxes.add(new NumericAxis(wasmContext));

    // Create a Heatmap Data-series. Pass heatValues as a number[][] to the UniformHeatmapDataSeries
    const initialZValues: number[][] = iterate(WIDTH, HEIGHT, 200, 0, MAX_SERIES);
    const heatmapDataSeries = new UniformHeatmapDataSeries(wasmContext, 100, 1, 100, 1, initialZValues);

    // Create a Heatmap RenderableSeries with the color map. ColorMap.minimum/maximum defines the values in
    // HeatmapDataSeries which correspond to gradient stops at 0..1
    const heatmapSeries = new UniformHeatmapRenderableSeries(wasmContext, {
        dataSeries: heatmapDataSeries,
        colorMap: new HeatmapColorMap({
            minimum: 0,
            maximum: 200,
            gradientStops: [
                { offset: 0, color: "#00008B" },
                { offset: 0.2, color: "#6495ED" },
                { offset: 0.4, color: "#006400" },
                { offset: 0.6, color: "#7FFF00" },
                { offset: 0.8, color: "#FFFF00" },
                { offset: 1.0, color: "#FF0000" },
            ],
        }),
    });

    // Add heatmap to the chart
    sciChartSurface.renderableSeries.add(heatmapSeries);

    // Add interaction
    sciChartSurface.chartModifiers.add(new ZoomPanModifier());
    sciChartSurface.chartModifiers.add(new ZoomExtentsModifier());
    sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());

    return { sciChartSurface, wasmContext, heatmapDataSeries };
};

// This function generates data for the heatmap series example
// because data-generation is not trivial, we generate once before the example starts
// so you can see the speed & power of SciChart.js
function iterate(width: number, height: number, cpMax: number, index: number, maxIndex: number): number[][] {
    const zValues = zeroArray2D([height, width]);
    // math.round but to X digits
    function roundTo(number: number, digits: number) {
        return parseFloat(number.toFixed(digits));
    }
    const angle = roundTo(Math.PI * 2 * index, 3) / maxIndex;

    for (let x = 0; x < width; x++) {
        for (let y = 0; y < height; y++) {
            const v =
                (1 + roundTo(Math.sin(x * 0.04 + angle), 3)) * 50 +
                (1 + roundTo(Math.sin(y * 0.1 + angle), 3)) * 50 * (1 + roundTo(Math.sin(angle * 2), 3));
            const cx = width / 2;
            const cy = height / 2;
            const r = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
            const exp = Math.max(0, 1 - r * 0.008);
            const zValue = v * exp + Math.random() * 50;
            zValues[y][x] = zValue > cpMax ? cpMax : zValue;
        }
    }
    return zValues;
}

let timerId: NodeJS.Timeout;
let updateIndex: number = 0;

export default function HeatmapChart() {
    const [heatmapDataSeries, setHeatmapDataSeries] = React.useState<UniformHeatmapDataSeries>();
    const [sciChartSurface, setSciChartSurface] = React.useState<SciChartSurface>();

    React.useEffect(() => {
        (async () => {
            const res = await drawExample();
            setSciChartSurface(res.sciChartSurface);
            setHeatmapDataSeries(res.heatmapDataSeries);
        })();
        // Delete sciChartSurface on unmount component to prevent memory leak
        return () => sciChartSurface?.delete();
    }, []);

    const updateChart = () => {
        timerId = setTimeout(updateChart, 20);
        // Cycle through pre-generated data every 20ms
        const newZValues = cachedHeatmapDataForExample[updateIndex++];
        // Update the heatmap z-values
        heatmapDataSeries.setZValues(newZValues);
        if (updateIndex >= MAX_SERIES) {
            updateIndex = 0;
        }
    };

    const handleStart = () => {
        // Pre-generate data for the example.
        // We do this once since data-generation of complex waveforms is quite heavy.
        if (cachedHeatmapDataForExample.length === 0) {
            for (let i = 1; i < MAX_SERIES; i++) {
                cachedHeatmapDataForExample.push(iterate(WIDTH, HEIGHT, 200, i, MAX_SERIES));
            }
        }

        if (!timerId) {
            updateChart();
        }
    };

    const handleStop = () => {
        clearTimeout(timerId);
        timerId = undefined;
    };

    return (
        <div>
            <div id={divElementId} style={{ maxWidth: 900 }} />
            <div style={{ marginTop: 20 }}>
                When click Start first time data is being generated, it could take a while
            </div>
            {heatmapDataSeries && (
                <div>
                    <div style={{ marginTop: 20 }}>
                        <button onClick={handleStart}>Start</button>
                        <button onClick={handleStop} style={{ marginLeft: 10 }}>
                            Stop
                        </button>
                    </div>
                </div>
            )}
        </div>
    );
}

// JavaScript Chart Examples

SciChart.js ships with ~40 JavaScript Chart Examples which you can browse, play with, view the source code and see related documentation. All of this is possible with the SciChart.js Examples Suite, which ships as part of the SciChart.js SDK

Description

Demonstrates how to create a JavaScript Heatmap Chart. The FastUniformHeatmapRenderableSeries accepts a 2D array of data and has user-defined color map which can be used to color points by value.

Tips!

Click Start to see the incredible performance of the Heatmap Chart in a real-time context!

Documentation Links

SciChart.js: Fast, Realtime, High Performance JavaScript Charts | JavaScript Chart Examples | Sitemap