Rafael Emshoff
Rafael Emshoff

Reputation: 2729

SVG viewBox breaks 100% fill of viewPort while preserving aspect ratio

Q: How can I use the viewBox coordinate system whilst still filling the viewPort completely and preserving aspect ratio?

I'm new to svg programming, so hopefully I'm just mis-understanding a basic concept.

I want to create an interactive & responsive map with , based on a background image that the user uploads.

Here's the basic example I'm trying to get to work (JSFiddle):

<svg version="1.1" 
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink" 
     width="200px" 
     height="400px"  
     preserveAspectRatio="xMidYMid meet" 
     style="border: 1px solid black;">

    <image x="0" y="0" width="100%" height="100%"
           preserveAspectRatio="xMidYMid meet"
           xlink:href="http://www.bized.co.uk/sites/bized/modules/bized_cb_navigation/images/floorplan_info.gif">
    </image>
</svg>

This works nicely. since however the viewPort changes, the image always fills it whilst maintaining its aspect ratio. (See wide-Screen example)

Next I add a coordinate system viewBox="0 0 100 100":

If you take a different image that is wider than tall, then the wide-screen view breaks, and the vertical-screen view still works.

When I inspect the SVG in Chrome DOM Element inspector, for the first two examples without using viewBox="0 0 100 100" The svg element has the same size as the viewPort. Once the viewBox attribute is added, the element becomes a square with sides equal to the lesser of the viewPort's sides.

This behavior is explained in this Tutorial as:

"... the view box is scaled according to the smaller of the two aspect ratios..."

I need the viewBox attribute so that I can zoom and pan on the image within the viewPort.

Upvotes: 2

Views: 2787

Answers (2)

Paul LeBeau
Paul LeBeau

Reputation: 101830

This is because you effectively have two competing viewBox transformations.

Because of your square viewBox, you are fitting the image into a square, and then fitting the square into your SVG rectangle.

If you make your SVG viewBox the same dimensions as your image (or the same aspect ratio will do), then the problem will be resolved.

viewBox="0 0 155 210"

http://jsfiddle.net/2qexypLs/15/

http://jsfiddle.net/2qexypLs/16/

Upvotes: 1

Rafael Emshoff
Rafael Emshoff

Reputation: 2729

My current solution is to use JavaScript to dynamically set the viewBox width and height values to the same value as svg width and height values. That way the aspect ratio for x and y are the same and the fill returns to 100% of viewPort. (JsFiddle)

For the interactive elements layer of the map I have a separate coordinate system that is mapped to the background image scaling ratio when the svg viewPort is defined. That means all coordinates need to be recalculated on svg define/change width/height event.

After this first re-calculation, the map can be zoomed and panned by changing the viewBox parameters without any further calculations.

Upvotes: 0

Related Questions