javascriptsvelteuplot

Using uPlot with svelte, does not render


I'm struggling to make uPlot work with svelte. I can't find any minimal working example, so I'm crafting one myself and it does not render. Repro goes as follows:

npm create svelte repro

# y
# skeleton
# yes TypeScript
# yes ESLing
# yes Prettier
# yes Playwright

npm install
npm i uplot
npm run dev -- --open

And then I modify index.svelte to contain the following (best I could come up with, thanks to this answer In SvelteKit, how do you conditionally include a `<script>` block in `app.html`?)

<script lang="ts">

    import { browser } from '$app/env';
    import { onMount } from 'svelte';
    import "uplot/dist/uPlot.min.css"

    let uPlot;

    function redraw(uPlot) {

        if(!uPlot) return;

        let data = [new Float32Array([1, 2, 3, 4, 5]), new Float32Array([1, 3, 2, 5, 4])];

        const opts = {
            width: 600,
            height: 300,
            scales: {x: {time: false}},
            series: [{label: "x"}, {label: "y", stroke: "red"}],
        };

        new uPlot(opts, data, document.getElementById("uPlot"));
    }

    onMount(async () => {

        if (browser) {
            const uplotModule = await import('uplot');
            uPlot = uplotModule.default;
            console.log("uplot loaded", uplotModule, uPlot);
        }
    })

    $: redraw(uPlot)

</script>

<h1>Welcome to SvelteKit</h1>
<div id="uPlot"></div>

It does not render the plot :( What am I missing?


Solution

  • There are several things to fix or improve:

    <script lang="ts">
        import { onMount } from 'svelte';
        import 'uplot/dist/uPlot.min.css';
    
        let plotContainer;
    
        function redraw(uPlot) {
            let data = [[1, 2, 3, 4, 5], [1, 3, 2, 5, 4]];
    
            const opts = {
                width: 600,
                height: 300,
                scales: {x: {time: false}},
                series: [{label: "x"}, {label: "y", stroke: "red"}],
            };
    
            new uPlot(opts, data, plotContainer);
        }
    
        onMount(async () => {
            const uplotModule = await import('uplot');
            const uPlot = uplotModule.default;
            redraw(uPlot);
        })
    </script>
    
    <div bind:this={plotContainer}></div>
    

    REPL equivalent