Search code examples
javascriptsveltenode-redvictoriametricsuplot

uplot freezing, when zooming, using svelte, nodered and uibuilder


uplot is used to dislay timeseries data from VictoriaMetrics database. For the backend Node-Red is used to forward and recieve the query with node-red-contrib-uibuilder.

It works basically and is very fast.

The problem is, when I try to zoom into the uplot graph, my browser (Chrome, Firefox, Edge) freezes. It seems to run out of memory.

Here are parts of my code, using svelte.

    <script>
    import { onMount } from "svelte";
    import { query } from "../lib/uibStore";
    import { transformToUplot } from "../lib/helper";

    // import uPlot from "uplot";
    import Browsebar from "../components/Browsebar.svelte";
    import TimerangeSelect from "../components/TimerangeSelect.svelte";

    let uplotdiv; // 

    let opts = {
        title: "Temperaturen1",
        id: "chart1",
        class: "my-chart",
        width: 1000,
        height: 600,
        series: [
            {},
            {                
                show: true, // initial toggled state (optional)
                spanGaps: true,                
                label: "RT",            
                stroke: "red", // series style
                scale: "Temperature",
                value: (self, rawValue) => rawValue.toFixed(1) + "°C",
            },
            {
                show: true,
                spanGaps: true,
                label: "KT",
                stroke: "green",
                scale: "Temperature",
                value: (self, rawValue) => rawValue.toFixed(1) + "°C",
            },
            {
                show: true,
                spanGaps: true,
                label: "VT",
                stroke: "blue",
                scale: "Temperature",
                value: (self, rawValue) => rawValue.toFixed(1) + "°C",
            },

        ],
        scales: {
            x: { time: true },
            Temperature: {
                auto: true,
                // range: [-10, 20],
                side: 3,
            },
        },
        axes: [
            {},
            {
                scale: "Temperature",
                values: (self, ticks) => ticks.map((rawValue) => rawValue.toFixed(1) + "°C"),
            },
        ],
        cursor: { drag: { x: true, y: true } },
    };
    let plot; // = new uPlot(opts);
    let uPlot;

    let d = [[0], [0], [0], [0]];
    let resolved = false;

    $: uisend($query); //use uibilder.send, if query changes which occurs when timerange or nav index changes

    //send a victoriametrics query to the backend, _q is part of query
    function uisend(_q) {
        // Example 'uvr_prozess_celsius{ort="1"}&start=-3d&step=60s'
        uibuilder.send({ topic: "getVMetrics", payload: _q });
    }

    onMount(async () => {
        uisend($query);

        const uplotModule = await import("https://unpkg.com/[email protected]/dist/uPlot.esm.js");
        uPlot = uplotModule.default;

        
        plot = new uPlot(opts, [[0], [0], [0], [0]], uplotdiv);
    });

    uibuilder.onChange("msg", function (msg) {
        // load Metrics via Node-Red's uibuilder, serverside
        if (msg.topic === "getVMetrics") {            
            resolved = true;
            
            if (msg.payload.data.result.length > 0) {
                d = transformToUplot(msg.payload.data);
                plot.setData(d);
            }
        }
    });
</script>

<svelte:head>
    <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/uPlot.min.css" />
</svelte:head>

<Browsebar>
    <TimerangeSelect />
</Browsebar>

<hr />

<div bind:this={uplotdiv} />

{#if resolved}
    <code>{$query}</code>
{:else}
    <h4>lade Metriken... {$query}</h4>
{/if}

<hr />

Has anyone experienced freezing with uplot? What did you do?


Solution

  • Lucky me, I found the problem. It had to do with the way I transformed the victoriametrics data. On every timestamp I did Number(timestamp).toFixed(0). Without toFixed(0) it is working now. :)

    //transform raw data from metrics query to the uplot format
    export function transformToUplot(dt) {
        let udata = []; //2d data array, conforming uPlot
        let tsd = []; //timestamp array
    
        //from first result take only the timestamps
        for (let t of dt.result[0].values) {
            // tsd.push(Number(t[0]).toFixed(0)); //this was bad!!!!, it lead to freezing
            tsd.push(Number(t[0]));
        }
        udata.push(tsd);
    
        //then the values
        for (let r of dt.result) {
            let sd = [];
            for (let d of r.values) {
                let val = Number(d[1]);
                sd.push(val);
            }
            udata.push(sd);
        }
        return udata;
    }
    

    Thanks for your interest!