Chartjs-How to pass DOM elements for libraries (eg. ChartJS, Hightcharts) in Virtual DOMs (such as Qwik)?

0👍

Solution

Sadly this was a silly issue of perhaps on my network side or god knows what why the search engine on the Qwik doc never suggested anything for me when I looked up "Ref" in their docs. But my problem has been solved after finding the following link:

https://qwik.builder.io/tutorial/hooks/use-signal/#example

For future reference for myself or any beginners facing the similar issue, I’m writing down my implementation below:

// Root component
import { component$, useSignal } from "@builder.io/qwik";
...
import ChartJSGraph from "../components/chartJSGraph/chartJSGraph";

export default component$(() => {
  const chartData1 = useSignal({
    labels: ["January", "February", "March", "April", "May", "June", "July"],
    datasets: [{
      label: 'Inventory Value per Outlet',
      data: [65, 59, 80, 81, 56, 55, 40],
      fill: false,
      borderColor: 'rgb(75, 192, 192)',
      tension: 0.1
    }]
  });

  return (
    <div class="w-100 h-100">
    ...
        <ChartJSGraph
          width={'100%'}
          height={'25px'}
          chartData={chartData1.value}
        />
    </div>
  );
});

And here’s the code for my ChartJSGraph component that uses the data supplied to generate the chart while using the reference of the canvas element to point to ChartJS where to create the chart.

// ChartJSGraph component
import { component$, useClientEffect$, useSignal } from "@builder.io/qwik";
import { Chart } from 'chart.js/auto';
...

interface GraphProps {
  height: string;
  width: string;
  chartData: object;
}

export default component$((props: GraphProps) => {
  const outputRef = useSignal<Element>();

  useClientEffect$(() => {
    new Chart(
      outputRef.value,
      {
        type: 'line',
        data: props.chartData
      }
    );
  });

  return (
    <>
      <canvas ref={outputRef} width={props.width} height={props.height}>
      </canvas>
    </>
  );
});

0👍

The DOM element that is passed to the charting library can only be accessed once it has been mounted to the page. Qwik/Vue/React all provide component mounted hooks.

Inside these mounted hooks you can reference your DOM element via id or querySelector or using the internal DOM reference feature of Qwuik/Vue/React and then use that when initialising the chart. The latter is the cleaner approach.

For example, in Vue:

<template>
<div id="acquisitions" ref="chartEl"></div>
</template>
<script setup>
import Chart from 'chart.js/auto';
import { ref, onMounted } from 'vue';
const chartEl = ref(null)


onMounted(() => {

 const chartOpts = {
      type: 'bar',
      data: {
        labels: data.map(row => row.year),
        datasets: [
          {
            label: 'Acquisitions by year',
            data: data.map(row => row.count)
          }
        ]
      }
    }

 new Chart(
    chartEl.value,
    chartOpts    
  );
})

</script>

Leave a comment