0

Here's my SVG:

<svg width="663" height="576" viewBox="0 0 663 576" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect id="misa" width="663" height="576" fill="#D9D9D9"/>
</svg>

And here is my React component:

import React, { useEffect, useRef } from "react";
import "./App.css";
import hillstateSvg from "./images/B.svg"; // SVG file path

const escapeCssSelector = (id) => {
  return `#${CSS.escape(id)}`;
};

const App = () => {
  const canvasRef = useRef(null);

  useEffect(() => {
    fetch(hillstateSvg)
      .then((response) => response.text())
      .then((data) => {
        const parser = new DOMParser();
        const svgDoc = parser.parseFromString(data, "image/svg+xml");
        const svgElement = svgDoc.documentElement;
        const canvas = canvasRef.current;
        const ctx = canvas.getContext("2d");

        // Set canvas size to match SVG size
        const svgWidth = parseInt(svgElement.getAttribute("width"));
        const svgHeight = parseInt(svgElement.getAttribute("height"));
        canvas.width = svgWidth;
        canvas.height = svgHeight;

        console.log(`Canvas size set to width: ${svgWidth}, height: ${svgHeight}`);

        const svgString = new XMLSerializer().serializeToString(svgElement);
        const img = new Image();
        const svgBlob = new Blob([svgString], { type: "image/svg+xml;charset=utf-8" });
        const url = URL.createObjectURL(svgBlob);

        img.onload = () => {
          ctx.drawImage(img, 0, 0);
          URL.revokeObjectURL(url);

          console.log("Image loaded and drawn on canvas");

          // Add blue dots
          const ids = ["misa", "misa2"];
          ids.forEach((id) => {
            const targetElement = svgElement.querySelector(escapeCssSelector(id));
            if (targetElement) {
              const bbox = targetElement.getBBox();
              if (bbox.width === 0 || bbox.height === 0) {
                // Try getBoundingClientRect if getBBox returns invalid dimensions
                const rect = targetElement.getBoundingClientRect();
                if (rect.width === 0 || rect.height === 0) {
                  console.log(`Element with ID: ${id} has invalid dimensions.`);
                  return;
                } else {
                  console.log(`Element ID: ${id}, rect:`, rect);
                  const cx = rect.left + rect.width / 2;
                  const cy = rect.top + rect.height / 2;
                  ctx.beginPath();
                  ctx.arc(cx, cy, 10, 0, 2 * Math.PI);
                  ctx.fillStyle = "blue";
                  ctx.fill();
                  console.log("Blue dot drawn using getBoundingClientRect");
                }
              } else {
                const cx = bbox.x + bbox.width / 2;
                const cy = bbox.y + bbox.height / 2;
                console.log(`Element ID: ${id}, bbox:`, bbox);
                ctx.beginPath();
                ctx.arc(cx, cy, 10, 0, 2 * Math.PI);
                ctx.fillStyle = "blue";
                ctx.fill();
                console.log("Blue dot drawn using getBBox");
              }
            } else {
              // Log if the element with the ID is not found
              console.log(`Element with ID: ${id} not found.`);
            }
          });
        };

        img.onerror = () => {
          console.error("Failed to load the image.");
        };

        img.src = url;
      })
      .catch((error) => {
        console.error("Error fetching or parsing the SVG file:", error);
      });
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <h1>SVG Element Click Coordinates</h1>
        <canvas ref={canvasRef} className="canvas-container"></canvas>
      </header>
    </div>
  );
};

export default App;

The console outputs the following messages indicating that the elements misa and are found, but their dimensions are invalid:

I'm using getBBox() to calculate the position of the elements. I've also tried using getBoundingClientRect(), but it also returns dimensions of 0.

How can I correctly get the dimensions and positions of these SVG elements to draw the blue dots on the canvas?

Any help would be greatly appreciated!

debugging

3
  • You'd have to attach the svg to a document that's rendered. Commented Jun 13 at 9:53
  • Your svg is parsed but not rendered. You can retrieve dimensions from the rect's x, y, width and height attributes. See example codepen Commented Jun 13 at 17:01
  • This related post may help "Any other ways to obtain the values of svg's bounding-rect". In short: you can only to some extent emulate getBBox in a headless/non-rendered environment by calculating x/y extremes from the geometry of elements. Dimensions set via CSS, <text> elements and transformations are hard to emulate - I'm not aware of any library that solves these issues. But maybe someone is working on it. Commented Jun 13 at 19:52

0

Browse other questions tagged or ask your own question.