0

I'm trying to place an arbitrary image as a background of an SVG which has a fixed size. The desired behavior is for an image which is larger than the fixed size of the SVG to be scaled uniformly to fit inside the box (i.e. "meet" and not "clip"), and for an image which is smaller to be displayed at its native size. (It should also be centered, but I've figured that part out.)

It's been easy to get large images to scale down, but I haven't figured out how to get small images to not scale up. Any ideas? It's a similar problem to this question but for SVG instead of CSS. This other question is definitely related, but because I don't know the pixel sizes of the images in advance the solution doesn't help me.

Here's a simplified version of the current SVG structure, with a Placekitten as a background image:

<svg xmlns="http://www.w3.org/2000/svg" id="svgroot" xlinkns="http://www.w3.org/1999/xlink" width="640" height="480" x="640" y="480" overflow="visible">
  <svg id="canvasBackground" width="640" height="480" x="0" y="0" overflow="none" style="pointer-events:none">
    <rect width="100%" height="100%" x="0" y="0" stroke="#000" fill="#FFF" style="pointer-events:none"/>
    <image id="background_image" width="100%" height="100%" preserveAspectRatio="xMidYMid" style="pointer-events:none" href="http://placekitten.com/500/400/"/>
  </svg>
</svg>
2
  • You can't achieve that effect with plain SVG. You would need to embed a little script to do it. Is that acceptable? It would work in browsers, but not necessarily in other SVG renderers. Commented Nov 4, 2013 at 22:05
  • Scripting is fine, I think, although figuring out where to put the script in the current set of libraries might be a challenge. (We're using a custom branch of the Sketchily gem for Rails to embed the svg-edit script, so we might have to do some bashing to fit a custom script in the right place.)
    – pjmorse
    Commented Nov 5, 2013 at 15:57

1 Answer 1

1

There is no way (AFAIK) via the SVG DOM to get the natural size of an image. So you need to use the HTML DOM to load the image first in order to determine the size.

var  htmlImg = document.createElement("img");
// Add an onload listener so we know when it is loaded
htmlImg.addEventListener('load', function() {
    // Get the image width and height (modern browsers only unfortunately)
    var  w = htmlImg.naturalWidth;
    var  h = htmlImg.naturalHeight;
    // Now we can add an <image> element to the <svg>
    // ...
});
// Set the img src attribute to trigger the load
htmlImg.src = url;

Here is a working demo.

This code uses the naturalWidth and naturalHeight properties of the HTMLImageElement. These are not supported by older browsers (eg. IE7/8). If you need to support older browsers, you will have to do a bit more work. Search SO for help with this.

1
  • Thanks! This site is pretty aggressive about HTML5 features, so we're unlikely to go out of our way to support older IE versions. I'll drop this in and see how it goes.
    – pjmorse
    Commented Nov 7, 2013 at 14:18

Not the answer you're looking for? Browse other questions tagged or ask your own question.