Chartjs-Svelte , pass data to chartjs from API

2👍

The chart component needs to be notified of the new data.

This can be achieved using reactive statements.

let myChart;

$: if (myChart) {
  myChart.data.datasets[0].data = [stats.temp0]; // update the data
  myChart.update(); // notify chart.js to render the new data
}

REPL

0👍

Chart.js expects an array for the data field and not a single value, wrapping it with square brackets so it becomes an array with a single item will make it show up

<script>
    import { onMount } from "svelte";
    import Chart from "chart.js/auto";

    export let stats;

    let ctx;

    onMount(async () => {
        const myChart = new Chart(ctx, {
            type: "bar",
            data: {
                labels: ["red"],
                datasets: [
                    {
                        label: "# of Votes",
                        data: [stats.temp0],
                        backgroundColor: [
                            "rgba(255, 99, 132, 0.2)",
                            "rgba(54, 162, 235, 0.2)",
                            "rgba(255, 206, 86, 0.2)",
                            "rgba(75, 192, 192, 0.2)",
                            "rgba(153, 102, 255, 0.2)",
                            "rgba(255, 159, 64, 0.2)",
                        ],
                        borderColor: [
                            "rgba(255, 99, 132, 1)",
                            "rgba(54, 162, 235, 1)",
                            "rgba(255, 206, 86, 1)",
                            "rgba(75, 192, 192, 1)",
                            "rgba(153, 102, 255, 1)",
                            "rgba(255, 159, 64, 1)",
                        ],
                        borderWidth: 1,
                    },
                ],
            },
            options: {
                scales: {
                    y: {
                        beginAtZero: true,
                    },
                },
            },
        });
    });
</script>

<div class="card bg-gradient-info">
    <canvas id="myChart" width="400" height="100" bind:this={ctx} />
</div>

0👍

Using onMount is not best pattern

With Svelte we can do better! There is the use directive.
Thanks to the great lihautan, where I learned about it. See playlist!

Applying this pattern, the Chart.svelte component would look like this:

Chart.svelte
-------------
<script>    
    import Chart from "chart.js/auto";
    import {setup} from "./options.js" //returns all chart option, incl. data

    export let chartdata;   
            
    function makeChart(ctx, d){     
        const myChart = new Chart(ctx, setup(d)); //init the chart
        return {
            update(u){
                myChart.data.datasets[0].data = u;  
                myChart.update()
            },
            destroy(){ myChart.destroy();   }               
        }
    }
</script>

<canvas use:makeChart={chartdata} width="400" height="300" />

To make it more readable, the options parameter is put into an extra file.

options.js
----------
export function setup(data){
    
    return  { 
            type: "bar",
            data: {
                labels: ['cpu', 'card'],
                datasets: [
                    {
                        label: "# of Votes",
                        data,
                        backgroundColor: [
                            "rgba(255, 99, 132, 0.2)",
                            "rgba(54, 162, 235, 0.2)",
                        ],
                        borderColor: [
                            "rgba(255, 99, 132, 1)",
                            "rgba(54, 162, 235, 1)",
                        ],
                        borderWidth: 1,
                    },
                ],
            },
            options: {
                scales: {
                    y: {
                        beginAtZero: true,
                    },
                },
            },
        };
}

In the main app via the input fields, it is possible to dynamically change the values of the displayed data.

App.svelte
----------
<script>
    import Chart from "./Chart.svelte";
    let cpu = 1;    let cards = 2;  
    $: chartdata = [cpu, cards];
</script>

<div>
    <label>cpu <input type="number" bind:value={cpu} /> </label>
    <label>cards <input type="number" bind:value={cards} /> </label>    
</div>

<Chart {chartdata} />

<style>
    div{
         display: flex;
    }
</style>

In the REPL you may find the working code. Just wait a litte bit, until the chart.js package is loaded.

Leave a comment