简体   繁体   中英

Image as a pointStyle with ChartJS in React

I'm using chartjs / react-chartjs-s to draw some plots in React/NextJS. I want to use an image for the pointStyle for one plot in specific. In plain JavaScript, an image can be created using const i = new Image() and used as a pointStyle in ChartJS.

In React I get an error ReferenceError: Image is not defined . If I try to import Image from next/image and use that, then the image does not appear on initial render (like here which interestingly can use new Image() ), and if I click on a datum on the chart I get an error Error: Rendered more hooks than during the previous render.

TLDR: Does anyone know how to use an image/icon as a pointStyle using Next.js, ChartJS, and react-chartjs-2? Thanks!

I'm using:

  1. react v. 18.2.0
  2. react-dom v. 18.2.0
  3. next v 13.0.05
  4. chart.js v. 4.1.1
  5. react-chartjs-2 v. 5.1.0

Solution:

new Image() reference the DOM, but since Next uses SSR, you have to utilize the useRef , useState , and useEffect hooks to circumvent the issue of trying to access the DOM.

import React, { useEffect, useRef, useState } from "react";
import {
  Chart as ChartJS,
  RadialLinearScale,
  PointElement,
  LineElement,
  Filler,
  Tooltip,
  Legend
} from "chart.js";
import { Radar } from "../node_modules/react-chartjs-2/dist";

ChartJS.register(
  RadialLinearScale,
  PointElement,
  LineElement,
  Filler,
  Tooltip,
  Legend
);

function App() {
  // useRef lets you reference a DOM object, persistent between renders
  const ref = useRef();
  const [onClient, setOnClient] = useState();
  
  // On first render, set onClient flag to true
  useEffect(() => {
    setOnClient(true);
  }, []);

  // On first render, set the current value of the ref to the image
  useEffect(() => {
    ref.current = new Image(25, 25);
    ref.current.src = "https://i.stack.imgur.com/gXQrT.png";
  }, []);

  const data = {
    labels: ["Business 1", "Business 2", "Business 3"],
    datasets: [
      {
        label: "Number of Businesses",
        data: [1300, 400, 160],
        backgroundColor: "rgba(255, 99, 132, 0.2)",
        borderColor: "rgba(255, 99, 132, 1)",
        borderWidth: 1,
        // Set the value of pointStyle to the ref value
        pointStyle: ref.current
      }
    ]
  };

  return (
    <div className="App">
      // Return the graph if rendering is happening on the client
      {onClient && <Radar data={data} />}

      <form>
        <input type="text" placeholder="Label" />
        <input type="text" placeholder="Dataset" />
        <button>Add Data</button>
      </form>
    </div>
  );
}

export default App;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM