I am using ReactJS. My aim is to trigger some events when an image loads inside an SVG element.

Without SVG element, this code below works as expected -

function onImageLoad(event) {
   console.log("Event triggered from <img> element", event);
    // AS EXPECTED : Event object has natural width and natural height
  }

return (
      <div>
        <img src={imageName} onLoad={ (event) => onImageLoad(event) }/> 
      </div>
)

However, this code does not work as expected -

function onImageLoad(event) {
    console.log("Event triggered from <image> element", event);
    // UNEXPECTED : Event object does not have natural width or natural height
  }

return (
      <div>
        <svg>
          <image href={imageName} onLoad={ (event) => onImageLoad(event) }/> 
        </svg>
      </div>
)

I have tried reading in several places. Its not clear why <image> is different from <img> for onLoad() synthetic event in react.

2

There are 2 best solutions below

0
Gautam Ghai On

You need to pass the event.currentTarget, not the event itself

<image href={imageName} onLoad={ (event) => onImageLoad(event.currentTarget) }/> 
0
Kaiido On

Unlike HTMLImageElement, the SVGImageElement interface doesn't expose a naturalWidth or naturalHeight properties, nor any ways to retrieve the intrinsic size of the inner image by the way.

If you want to get it, the easiest would be to load the image again in an HTML <img>, an alternative would be to create an ImageBitmap from the <image> but not all browsers do support it.

const svgImg = document.querySelector("image");
const getSVGImageSize = async (src) => {
  const img = new Image();
  img.src = src.href.baseVal;
  await img.decode();
  const { width, height } = img;
  return { width, height };
};

getSVGImageSize(svgImg)
  .then(({ width, height }) => console.log("from HTMLImageElement", { width, height }))

// alternative using createImageBitmap,
// not supported in Safari
svgImg.addEventListener("load", e => createImageBitmap(svgImg)
  .then(({ width, height }) => console.log("fom ImageBitmap", { width, height }))
  .catch(console.error)
);
<svg>
  <image href="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png"/>
</svg>