Scale image element in SVG to fit the SVG dimensions - javascript

I have an image element inside an SVG element. The href attribute of the image element and the width and height of the SVG element is set dynamically in JavaScript. I want the image element to fill up the parent SVG element.
<svg id="mySVG">
<svg:g>
<image id="bgImg" width="100%" height="100%"></img>
...
</svg:g>
</svg>
Basically, I want the image element to be set as a background image of the SVG element.

Here are some examples. Most likely you need to make the size of the image match the viewBox of the svg.
Depending on your use case you can use preserveAspectRatio to control how the image behaves inside the SVG:
svg {
background-color: orange;
}
<p>Without setting the size:</p>
<svg xmlns="http://www.w3.org/2000/svg">
<image href="https://via.placeholder.com/150"/>
</svg>
<p>The size of the image matches the viewBow of the SVG:</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
<image href="https://via.placeholder.com/150"/>
</svg>
<p>And then control the size of the SVG with a width (or height) attribute:</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" width="100">
<image href="https://via.placeholder.com/150"/>
</svg>
<p>Same as above but with a viewBox that does not fit the size of the image and therefore the size of the image needs to be set explicitly:</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100">
<image href="https://via.placeholder.com/150" width="100" height="100"/>
</svg>
<p>Force the image to match the viewBox with preserveAspectRatio = none:</p>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 150">
<image href="https://via.placeholder.com/150" width="300" height="150" preserveAspectRatio="none"/>
</svg>

Related

Am I handling SVG's correctly?

I have a square div with two triangles drawn via SVGs within that looks like this :
I then have a button that once the onClick event is triggered it will add a class called hidden just basically has : display: none; visibility: hidden; to hide the bottom triangle, then displays two more triangles like so :
My current code looks like :
SVG to draw my triangle.
<svg id="triangle" width="100%" height="100%">
<path d="M0,0 L680,0 L0,680 Z " id="top_triangle" class="o-top_main"></path>
</svg>
Then the image for me to be able to use a background image :
<svg style="position: absolute;">
<defs>
<pattern id="image_top" width="1" height="1" viewBox="0 0 100 100">
<image id="svg_img_top" xlink:href='http://41.media.tumblr.com/tumblr_m8r9k312PE1qc6mk8o1_500.jpg' width="100" height="100" preserveAspectRatio="none"></image>
</pattern>
</defs>
</svg>
I've been drawing the SVG path like such <path d="M0,0 L680,0 L0,680 Z ". I've tried drawing an SVG triangle in photoshop, exporting out as an SVG then getting the path in the code and pasting in but the dimensions are never correct so I end up editing the path to the point where i've redrawn it anyway.
Is there anyway way I can draw an SVG triangle in Photoshop where I can then paste the path into my site without needing to change the path to the point where i've redrawn it?
My end site kind of looks similar to this :
Lets take a look at your first image here:
Now usually you allways want to create an viewBox on any svg element.
Width and height are usually set in css, but there are lots of cases where setting it in inline is better.
Now lets see your drawing 2 triangles with paths so and then adding another:
My suggestion is drawing 3 triangles then changing the color:
Update:
now with image url instead of colors. (the svg is getting quite complicated now)
var bottom = document.getElementById("tri_tri");
bottom.addEventListener("click", function() {
this.style.fill = "yellow";
this.style.stroke = "yellow";
});
/**/
.triangleArt {
width: 250px;
}
#tri_one {
fill: firebrick;
}
#tri_two {
fill: url(#image_top);
stroke: url(#image_top);
}
#tri_tri {
fill: url(#image_top);
stroke: url(#image_top);
cursor: pointer;
}
<svg viewBox="0 0 100 100" class="triangleArt" xmlns="http://www.w3.org/2000/svg" xmlns:x="http://www.w3.org/1999/xlink">
<defs>
<pattern id="image_top" patternUnits="userSpaceOnUse" width="250" height="156">
<image id="svg_img_top" xlink:href='http://41.media.tumblr.com/tumblr_m8r9k312PE1qc6mk8o1_500.jpg' x="0" y="0" width="250" height="156"></image>
</pattern>
</defs>
<path id="tri_one" d="m0,100 100,-100, -100,0z" />
<path id="tri_two" d="m100,0 0,100 -50,-50z" />
<path id="tri_tri" d="m100,100 -50,-50 -50,50z" />
</svg>

SVG view box crop using jquery

I am doing sticker website for my client. They need image crop within given SVG image. That SVG image is unshaped like Halloween face (see below).
When i upload an image, it will display within the given image. The rest of the image will hide.
How can i achieve this?
This is really quite easy with SVG clipPaths. It has good browser support as well, except of course IE.
.defs {
position: absolute;
width: 0;
height: 0;
}
.demo {
text-align:center;
}
.star image {
clip-path: url(#star-clip);
}
.hex image {
clip-path: url(#hex-clip);
}
.heart image {
clip-path: url(#heart-clip);
}
.shape image {
clip-path: url(#shape-clip);
}
<svg class="defs">
<defs>
<clipPath id="star-clip">
<polygon id="star" points="150,7.3 196.4,101.3 300,116.3 225,189.4 242.7,292.7 150,243.9 57.3,292.7 75,189.4 0,116.3 103.6,101.3" />
</clipPath>
<clipPath id="hex-clip">
<polygon id="hex" points="222.5,295 77.5,295 5,150 77.5,5 222.5,5 295,150" />
</clipPath>
<clipPath id="heart-clip">
<path id="heart" d="M248.078,5.883c-36.691-14.739-77.771-0.839-98.517,31.125C128.817,5.044,87.735-8.856,51.043,5.883 C9.354,22.632-10.863,70.009,5.887,111.696c16.06,39.98,143.314,139.607,143.314,139.607l0.359,0.28l0.36-0.28 c0,0,127.251-99.627,143.314-139.607C309.986,70.009,289.768,22.632,248.078,5.883z"/>
</clipPath>
<clipPath id="shape-clip">
<path id="shape" d="M132.9,0.9c-12.5,1-34.7,4.4-44.9,6.7c-33.5,7.6-55.7,28.2-63.8,58.8c-1.8,6.9-2.2,9.7-2.3,20.1c0,10.5,0.2,13.3,2.3,21.6 c9.5,40.7,33.2,90.2,71.5,149.8c10.5,16.4,14.8,21.8,22.8,29.3c4.3,3.9,8.3,6.8,13,9.2l6.9,3.4h10.9c10.9,0,10.9,0,17-2.9 c7.6-3.7,14.3-8.7,21.4-16.2c6.9-7.2,10.5-12.3,21.9-30.3C248,188.7,272,134.3,277.4,96.6c1.2-8.6,0.5-22.4-1.7-31.3 c-5.6-23.4-20.8-41.2-43.6-50.9c-15.3-6.5-27.5-10-44.5-12.5C177.7,0.5,144.9-0.1,132.9,0.9z"/>
</clipPath>
</defs>
</svg>
<div class="demo heart">
<svg width="300" height="300">
<image xlink:href="http://lorempixel.com/output/city-q-c-300-300-4.jpg" width="300" height="300" />
</svg>
</div>
<div class="demo star">
<svg width="300" height="300">
<image xlink:href="http://lorempixel.com/output/cats-q-c-300-300-10.jpg" width="300" height="300" />
</svg>
</div>
<div class="demo hex">
<svg width="300" height="300">
<image xlink:href="http://lorempixel.com/output/people-q-c-300-300-8.jpg" width="300" height="300" />
</svg>
</div>
<div class="demo shape">
<svg width="300" height="300">
<image xlink:href="http://lorempixel.com/output/nightlife-q-c-300-300-6.jpg" width="300" height="300" />
</svg>
</div>
You'll need to define your clipPath and then apply it to your image. In the demo, I created a separate SVG element that contains all of the shapes as path or polygon definitions and simply applied them using external styles. You can of course do this in a single SVG, such as:
<svg width="120" height="120">
<defs>
<clipPath id="shape-clip">
<path id="shape" d="M60,117.4c-20.4,0-44.8-53.6-49-76.4C7.3,21,26.6,4.2,46.9,2.6c7-0.5,19.8-0.2,26.2,0 C93.5,3.4,112.7,21,109,41C104.8,63.8,79.3,117.4,60,117.4z"/>
</clipPath>
</defs>
<image xlink:href="http://lorempixel.com/output/nightlife-q-c-120-120-6.jpg" width="120" height="120" style="clip-path: url(#shape-clip);" />
</svg>
Some things to keep in mind:
Your defs need to be defined in the source order before they are used (so you can't put them at the end of your page for example).
The SVG element defs will not display, but they will take up space in the rendered page. I just force them out of the document flow with position: absolute and give them a height and width of 0 to make sure they don't mess with my layout.
For more information, you might want to look at these:
Clipping and Masking in CSS, CSS Tricks
SVG Clip Path Tutorial, Jenkov.com
Clipping, Masking and Compositing Specification, W3C

How to resize an SVG animation?

I am stuck at resizing an svg animation to a different percentages of the page.
I have created a circle that increases its size and then goes back to normal with this:
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1">
<circle id="myCircle" cx="600" cy="250" r="70" fill="yellow" stroke="green" stroke-width="5">
<animate attributeName="r" values="70; 140; 210; 140; 70" dur="10s" repeatCount="indefinite"/>
</circle>
</svg>
Then, when I change the área size of the svg, the circle does not change its size nor the position within this area.
I have tried to scale the animation with CSS giving size to the body in pixels and then assign an area to the SVG in percentages:
body{
width: 1440px;
heigth: 990px
}
#mySVG{
width: 100%;
}
Also, I tried to change size with javascript:
function resize(){
var svg = document.getElementById("mySVG");
svg.style.width = window.innerWidht;
svg.style.height = window.innerHeight;
}
None of them worked… wondering what is the best method to scale SVG animations not only with this circle but with SVG animations in general.
Thank’s in advanced.
You have to use a viewbox to define the co-ordinate space. E.G.
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1"
viewbox="0 0 1200 1200">
The viewBox attribute allows to specify that a given set of graphics
stretch to fit a particular container element.
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.
<svg id="mySVG" xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 1200 1200">
<circle id="myCircle" cx="600" cy="250" r="70" fill="yellow" stroke="green" stroke-width="5">
<animate attributeName="r" values="70; 140; 210; 140; 70" dur="10s" repeatCount="indefinite" />
</circle>
</svg>
Useful SVG Resource Article # CSS-Tricks.com
MDN Link

Displaying SVG objects on either left or right side of page

I am dynamically generating some SVG. What I want to do is divide the page in half (no matter what size it is) and be able to insert some objects on the left side of the screen and some objects on the right of the screen. I just can't seem to get it right. I have actually tried to do it many different ways, the code listed here was my most recent attempt:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%">
<script type="text/ecmascript">
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var i = 0;
function makeBox() {
i++;
var newRect = document.createElementNS(svgNS,"rect");
newRect.setAttributeNS(null,"width", 100);
newRect.setAttributeNS(null,"height", 100);
newRect.setAttributeNS(null, "x", 10);
newRect.setAttributeNS(null, "y", i * 100);
newRect.setAttributeNS(null,"fill","blue");
if(i % 2 === 1) {
document.getElementById("screenLeft").appendChild(newRect);
} else {
document.getElementById("screenRight").appendChild(newRect);
}
}
</script>
<g id="firstGroup">
<text x="20" y="30" onclick="makeBox()" font-size="+13px">Click this text to Draw a Box.</text>
</g>
<svg id="screenLeft" viewBox="50% 100%">
</svg>
<svg id="screenRight" viewBox="50% 100%" x="50%">
</svg>
</svg>
Of course I changed a bunch of code to make this post more concise. What it does is, when user clicks the text, it draws a rectangle in element "screenLeft" or "screenRight" depending on if the increment (i) is even or odd.
The way I have the viewBox setup right now sort of works. If I reduce the chrome window to a smaller size, the gap between the "leftSide" and the "rightSide" does get smaller. However, if I have the window Maximized, the screen area is WAY too big. I have to scroll far to the right to see the "rightSide". It is about twice my screen size.
I have also tried several other methods, involving grouping.
So, I guess my question is, what is the best way to divide the screen in half so I can generate some objects on the left side of the screen and some on the right side of the screen, while allowing the total screen size to differ?
Give your <svg> element a viewBox with fixed width and an exceptional height. Then specify a preserveAspectRatio attribute with the value of xMidYMid slice.
This will ensure that the full width of your SVG viewport will always cover the viewBox, and half of your viewBox will thus cover half the screen.
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="-100 -1000 200 2000" preserveAspectRatio="xMidYMid slice">
<style type="text/css"><![CDATA[
rect { stroke:red }
text { text-anchor:middle; font-size:8px }
]]></style>
<rect x="-100" y="-1000" width="100" height="2000" fill="lightblue" />
<rect x="0" y="-1000" width="100" height="2000" fill="yellow" />
<text x="-50" y="0">Left Side</text>
<text x="+50" y="0">Right Side</text>
</svg>
See this live: http://phrogz.net/svg/half-width.svg
The only downside with this (which I can't tell if it matters to you) is that resizing the browser window will resize the elements. Maybe you want elements to always remain the same size on screen no mater how large the browser?
This seemed to do what I think you wanted, the only thing you need to decide is how you want aspect ratio to effect your display... I deliberately left the right side's aspect ratio unadjusted so you could see the difference.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" >
<svg width="50%" viewBox="0 0 100 100" preserveAspectRatio="none">
<rect x="0" y="0" width="100%" height="100%" fill="red" opacity="0.5"/>
</svg>
<svg x="50%" width="50%" viewBox="0 0 100 100" >
<rect x="0" y="0" width="100%" height="100%" fill="blue" opacity="0.5"/>
<rect x="80%" y="10%" width="10%" height="50%" fill="green"/>
<rect x="10" y="10" width="70" height="40" fill="gray"/>
</svg>

How can I resize an SVG?

I have code like this:
<span>
<svg height="32" version="1.1" width="32" xmlns="http://www.w3.org/2000/svg" style="overflow: hidden; position: relative; left: -0.0166626px; top: -0.983337px;">
<desc></desc>
<defs/>
<path style="" fill="#333333" stroke="none" d="M15.985,5.972C8.422,5.972,2.289999999999999,10.049,2.289999999999999,15.078C2.289999999999999,17.955,4.302999999999999...............1,27.68,22.274Z"/>
</svg>
</span>
I cut out most of the content and replaced it with ...
This presently creates a 32 by 32 icon. What I would like to know is can I use this code to create a 100 by 100 icon? I tried changing the width and height but it made no difference.
The width and height attributes on the SVG element only define the size of the drawing area. They don't scale the contents to fit that area. For that, you need to also use the viewBox attribute, like so:
<svg viewBox="0 0 32 32" height="100" width="100" ...>
The viewBox attribute establishes the coordinate system that is used for all the child elements of the SVG. You can then use the width and height to stretch this coordinate system to the desired size.
You can use the preserveAspectRatio attribute to decide how to scale if the aspect ratios don't match.
It worked for me by modifying the svg style
let svgDom = document.getElementsByTagName("svg")[0];
let newWidth=100,newHeight=90;
svgDom.style.width = newWidth+'px';
svgDom.style.height = newHeight+'px';
just throw a transform="scale(2)" and it will do the trick, ( React )
<svg
width={56}
height={56}
transform="scale(2)"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<circle cx={28} cy={28} r={24} fill="#F88423" />
<path
fillRule="evenodd"
clipRule="evenodd"
d="..."fill="#131903"
/>
</svg>

Categories