JavaScript Heatmap Chart

If you want to learn about heatmaps. this demo shows you how to create a JavaScript Heatmap Chart using SciChart.js, our 5-star rated JavaScript Chart Component.

# Heatmap Size: 0 x 0
FPS: 00 

Fullscreen

Edit

 Edit

Docs

src/drawExample.ts
import {
    HeatmapColorMap,
    HeatmapLegend,
    MouseWheelZoomModifier,
    NumericAxis,
    SciChartSurface,
    UniformHeatmapDataSeries,
    UniformHeatmapRenderableSeries,
    zeroArray2D,
    ZoomExtentsModifier,
    ZoomPanModifier,
} from "scichart";
import { appTheme } from "./appTheme";

const MAX_SERIES = 100;
const WIDTH = 300;
const HEIGHT = 200;

// Draws a Heatmap chart in real-time
export const drawExample = async (rootElement: string | HTMLDivElement) => {
    // Create a SciChartSurface
    const { sciChartSurface, wasmContext } = await SciChartSurface.create(rootElement, {
        theme: appTheme.SciChartJsTheme,
    });

    // Add XAxis and YAxis
    sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { isVisible: false }));
    sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { isVisible: false }));

    // Create a Heatmap Data-series. Pass heatValues as a number[][] to the UniformHeatmapDataSeries
    const initialZValues: number[][] = generateExampleData(WIDTH, HEIGHT, 200, 20, MAX_SERIES);
    const heatmapDataSeries = new UniformHeatmapDataSeries(wasmContext, {
        xStart: 0,
        xStep: 1,
        yStart: 0,
        yStep: 1,
        zValues: 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,
        useLinearTextureFiltering: false,
        colorMap: new HeatmapColorMap({
            minimum: 0,
            maximum: 200,
            gradientStops: [
                { offset: 1, color: appTheme.VividPink },
                { offset: 0.9, color: appTheme.VividOrange },
                { offset: 0.7, color: appTheme.MutedRed },
                { offset: 0.5, color: appTheme.VividGreen },
                { offset: 0.3, color: appTheme.VividSkyBlue },
                { offset: 0.2, color: appTheme.Indigo },
                { offset: 0, color: appTheme.DarkIndigo },
            ],
        }),
    });

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

    // Add interaction
    sciChartSurface.chartModifiers.add(new ZoomPanModifier({ enableZoom: true }));
    sciChartSurface.chartModifiers.add(new ZoomExtentsModifier());
    sciChartSurface.chartModifiers.add(new MouseWheelZoomModifier());

    // Functions for running the example in real-time
    let timerId: NodeJS.Timeout;
    let updateIndex: number = 0;

    const updateChart = () => {
        // Cycle through pre-generated data on timer tick
        const newZValues = generateExampleData(WIDTH, HEIGHT, 200, updateIndex++, MAX_SERIES);
        // Update the heatmap z-values
        heatmapDataSeries.setZValues(newZValues);
        if (updateIndex >= MAX_SERIES) {
            updateIndex = 0;
        }
        timerId = setTimeout(updateChart, 16);
    };

    const startUpdate = () => {
        if (!timerId) {
            updateChart();
        }
    };

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

    const subscribeToRenderStats = (callback: (stats: { xSize: number; ySize: number; fps: number }) => void) => {
        // Handle drawing/updating FPS
        let lastRendered = Date.now();
        sciChartSurface.rendered.subscribe(() => {
            const currentTime = Date.now();
            const timeDiffSeconds = (currentTime - lastRendered) / 1000;
            lastRendered = currentTime;
            const fps = 1 / timeDiffSeconds;
            callback({
                xSize: heatmapDataSeries.arrayWidth,
                ySize: heatmapDataSeries.arrayHeight,
                fps,
            });
        });
    };

    return { sciChartSurface, subscribeToRenderStats, controls: { startUpdate, stopUpdate } };
};

// Draws a Heatmap legend over the <div id={divHeatmapLegend}></div>
export const drawHeatmapLegend = async (rootElement: string | HTMLDivElement) => {
    const { heatmapLegend, wasmContext } = await HeatmapLegend.create(rootElement, {
        theme: {
            ...appTheme.SciChartJsTheme,
            sciChartBackground: appTheme.DarkIndigo + "BB",
            loadingAnimationBackground: appTheme.DarkIndigo + "BB",
        },
        yAxisOptions: {
            isInnerAxis: true,
            labelStyle: {
                fontSize: 12,
                color: appTheme.ForegroundColor,
            },
            axisBorder: {
                borderRight: 1,
                color: appTheme.ForegroundColor + "77",
            },
            majorTickLineStyle: {
                color: appTheme.ForegroundColor,
                tickSize: 6,
                strokeThickness: 1,
            },
            minorTickLineStyle: {
                color: appTheme.ForegroundColor,
                tickSize: 3,
                strokeThickness: 1,
            },
        },
        colorMap: {
            minimum: 0,
            maximum: 200,
            gradientStops: [
                { offset: 1, color: appTheme.VividPink },
                { offset: 0.9, color: appTheme.VividOrange },
                { offset: 0.7, color: appTheme.MutedRed },
                { offset: 0.5, color: appTheme.VividGreen },
                { offset: 0.3, color: appTheme.VividSkyBlue },
                { offset: 0.2, color: appTheme.Indigo },
                { offset: 0, color: appTheme.DarkIndigo },
            ],
        },
    });

    return { sciChartSurface: heatmapLegend.innerSciChartSurface.sciChartSurface };
};

// 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 generateExampleData(
    width: number,
    height: number,
    cpMax: number,
    index: number,
    maxIndex: number
): number[][] {
    // Returns a 2-dimensional javascript array [height (y)] [width (x)] size
    const zValues = zeroArray2D([height, width]);

    // math.round but to X digits
    function roundTo(number: number, digits: number) {
        return number;
        // return parseFloat(number.toFixed(digits));
    }

    const angle = roundTo(Math.PI * 2 * index, 3) / maxIndex;

    // When appending data to a 2D Array for the heatmap, the order of appending (X,Y) does not matter
    // but when accessing the zValues[][] array, we set data [y] then [x]
    for (let y = 0; y < height; y++) {
        for (let x = 0; x < width; x++) {
            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() * 10;
            zValues[y][x] = zValue > cpMax ? cpMax : zValue;
        }
    }
    return zValues;
}

Heatmap Chart Example - JavaScript

Overview

This example demonstrates a high-performance Heatmap Chart implemented using JavaScript with SciChart.js. The implementation focuses on real-time data streaming and dynamic visual updates, leveraging WebGL-powered rendering for optimal performance.

Technical Implementation

The chart is built by creating a SciChartSurface instance via the SciChart.js API, and hidden numeric axes are added to simplify the presentation. The example generates a two-dimensional array of data which is fed to a UniformHeatmapDataSeries. A UniformHeatmapRenderableSeries is then configured with a detailed gradient via HeatmapColorMap to accurately represent the data. Real-time updates are managed using JavaScript’s setTimeout to continuously update the series, as explained in the Adding Realtime Updates documentation.

Features and Capabilities

Key features include real-time chart updates with dynamic data streaming, advanced color mapping techniques, and integrated performance monitoring. The color mapping is finely tuned using gradient stops which you can learn more about in the Uniform Heatmap Chart documentation and Uniform-Heatmap-Colormaps resources. In addition, interactive modifiers such as ZoomPanModifier and MouseWheelZoomModifier enhance the user experience.

Integration and Best Practices

Built on JavaScript, this example adheres to best practices by directly interacting with the SciChart.js API without relying on additional frameworks. Developers can monitor performance by subscribing to render events, a technique detailed in the Performance Tips & Tricks guide. Furthermore, interactive features are implemented using modifiers like the MouseWheelZoomModifier to ensure a smooth user experience. This approach provides a clear and maintainable structure for integrating SciChart.js within any JavaScript project.