0

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?

psarka
  • 1,562
  • 1
  • 13
  • 25
  • Are you sure your `async` `onMount` implementation is correct? Can you try something like [this](https://svelte.dev/repl/7e175db016b74c4ba4688c76114866c9?version=3.23.0) and see if it works? – Eldar Jul 06 '22 at 09:08
  • I'm not sure of anything :( With my implementation I get no errors, and an empty plot element appears that reacts to mouse movements, but shows no plot. I tried to fit things to your example, but I got lost. I'm not sure what is supposed to go to onMount and to lazyLoading :( – psarka Jul 06 '22 at 09:36

1 Answers1

1

There are several things to fix or improve:

  • uPlot does not take typed arrays as data
  • The reactive statement is a bit pointless, as it only triggers in a meaningful once after uPlot has been loaded
  • One should not query the DOM in Svelte but use bind:this or events instead
  • onMount already executes only in the browser
<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

H.B.
  • 166,899
  • 29
  • 327
  • 400