0

I am constructing an svg using D3.js. Inside it I am using <image> to place two types of images img1 and img2 where both have same width W but img1 is shorter than img2 i.e. H1<H2.

the two candidate images

They should be placed within the outer svg in a rectangle with dimensions WxH2 at position (x,y) and the shorter one (img1) should be aligned vertically at the bottom of this rectangle like this:

both images overlayed

This sounds like a job for viewBox & preserveAspectRatio so I tried creating a nested <svg> element with dimensions WxH2 (the larger of the 2 heights) at position (x,y) and depending on the image dynamically added each time, the layout (here shown with both images) would be:

overall SVG layout with both images

Sample code with W=35, H1=19, H2=88, x=100, y=200:

```

<svg...> <!--outer SVG-->
    <svg width="35" height="88" x="100" y="200" viewBox="0 0 35 88" preserveAspectRatio="xMidYMax meet"> <!-- nested SVG-->
        <image xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="img1_OR_img2" width="35" height="CORRESPONDING_img_HEIGHT"></image>
    </svg> <!-- end of nested SVG-->
</svg> <!-- end of outer SVG-->

```

The problem is that the height of the nested svg is ignored and it's the height of the <image> that defines the height of the rectangle. So no matter what vertical alignment I ask for through preserveAspectRatio in the nested svg, in the case of the shorter image img1 it will not make a difference since the rectangle is already the height of the img1. If I have <image> always have the larger height H2, then the smaller image img1 appears vertically aligned in the middle.

Should I be using a whole different substructure instead of a nested svg or am I misusing the viewBox/preserveAspectRatio combo?

Note: regarding the topic viewBox & preserveAspectRatio, I used this article which is the best I've found online so far (kudos to Sara for an amazing article).

Thalis K.
  • 7,363
  • 6
  • 39
  • 54

1 Answers1

0

Your problem is that you are changing the heights. In both cases you should be using 88 for "CORRESPONDING_img_HEIGHT". You need to use the same viewport for both images and let SVG position the image within the viewport according to the preserveAspectRatio setting.

In fact, you don't need to be using nested SVGs. The <image> element also has a preserveAspectRatio attribute.

<svg xmlns:xlink="http://www.w3.org/1999/xlink">
    <image x="100" y="200" width="35" height="88" xlink:href="img1" preserveAspectRatio="xMidYMax meet"/>
    <image x="100" y="200" width="35" height="88" xlink:href="img2" preserveAspectRatio="xMidYMax meet"/>
</svg>
GuCier
  • 6,919
  • 1
  • 29
  • 36
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181