Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define a source rectangle for an SVG <image> like you can in HTML Canvas or CSS

Tags:

html

css

canvas

svg

In HTML5 Canvas you can draw an image as a whole, or draw only a piece of it, or draw only a piece of it to an arbitrary rectangle (which may scale it).

Here's an example of all three:

enter image description here

Here's the code used to draw those three examples:

ctx.drawImage(img, 0, 0);

ctx.drawImage(img,
              // source rect
              50, 50, 70, 70,
              // destination rect
              0, 200, 70, 70
             );

ctx.drawImage(img,
              // source rect
              50, 50, 70, 70,
              // destination rect
              0, 270, 30, 30
             );

This is also relatively easy to do in CSS.

My question is, for a given image, how can you achieve the same effects using SVG <image> elements?

How do I, for instance, make an Image that occupies 50x50 pixels, that shows a portion of the referenced href, as in the first crop?

One could use a clipping path to crop part of the image, but then you (seemingly) cannot use a clipping path of a larger image while defining the width and height of the <image> element to be small.

Here's a fiddle with the above code plus a sample SVG element:

http://jsfiddle.net/wcjVd/

like image 610
Simon Sarris Avatar asked Oct 22 '13 18:10

Simon Sarris


1 Answers

You don't need a clipPath at all, you can use the viewBox to do what you want

<svg width="70px" height="70px" viewBox="50 50 70 70">    
    <image x="0" y="0" width="200" height="200" 
        xlink:href="http://placekitten.com/200/200" clip-path="url(#myClip)">
    </image>
</svg>

The value of the viewBox attribute is a list of four numbers <min-x>, <min-y>, <width> and <height>, separated by whitespace and/or a comma, which specify a rectangle in user space which should be mapped to the bounds of the viewport established by the given element, taking into account attribute preserveAspectRatio.

Demo Here

Glad I can help you here because you helped me with a Canvas project a few months ago!

Edit

You said that you needed to transform them also, so after an hour I came up with these couple options:

If you can, transform the original image and do the same effect. Demo here If you are wanting the cropped image at the origin (0,0) then the code would look like

<defs>
    <clipPath id="myClip">
        <rect x="0" y="0" width="70" height="70"/>
    </clipPath>
</defs>
     <image x="-50" y="-50" width="200" height="200" clip-path="url(#myClip)" 
            xlink:href="http://placekitten.com/200/200"></image>

OR, more satisfactorily, you could do it using a use

<defs> <!-- Your original clip -->
    <clipPath id="myClip">
        <rect x="50" y="50" width="70" height="70"/>
    </clipPath>         
</defs>
<image id="myImage" x="0" y="0" width="200" height="200" 
       xlink:href="http://placekitten.com/200/200" clip-path="url(#myClip)" />

<!-- Hide the original (I made a layer of white) -->
<!-- This is the part that you could probably find a better way of doing -->
<rect x="0" y="0" width="200" height="200" style="fill:white" />

<!-- Create what you want how you want where you want it -->
<use  x="-50" y="-50" width="200" height="200" xlink:href="#myImage" transform="scale(1.3)"/>
</svg>

Demo for that approach here

like image 84
Zach Saucier Avatar answered Sep 28 '22 06:09

Zach Saucier