Why is this simple SVG icon scaling? - html

I have a jsFiddle demonstrating this:
http://jsfiddle.net/L0a3xa7j/1/
I've made a simple SVG icon for a window restore. I wish it to be 13x11. Here's the page markup:
<svg display="none" width="0" height="0" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="i-restore" viewBox="0 0 13 11">
<line x1="2" y1="0" x2="13" y2="0" stroke-width="1" stroke="white"/>
<line x1="13" y1="0" x2="13" y2="9" stroke-width="1" stroke="white"/>
<rect x="0" y="2" width="11" height="9" stroke="white" fill="none" stroke-width="2"/>
</symbol>
</defs>
</svg>
<svg class="svg"><use xlink:href="#i-restore"/></svg>
And here's the CSS:
body{background:#000}
.svg
{
color:#FFF; width:13px; height:11px;
}
I'm expecting a 1 pixel space between the rectangle and the 2 lines. The rectangle should be 2 pixels thick in stroke and the lines 1 pixel thick. I don't understand why the aspect ratio is not correct when the css pixel dimensions match that of the SVG's viewbox.
What's the correct way to fix this? Thanks for any help.

1/2 of a stroke occurs inside the boundary of the shape and 1/2 outside
<rect x="0" y="2" width="11" height="9" stroke="white" fill="none" stroke-width="2"/>
starts at -1, 1 and is 13 pixels wide and 11 pixels high. Your svg size isn't big enough to accommodate the size of its contents and the overflow is clipped.
That's why the spaces between things are not as you expect either.

You're giving the lines a stroke of 2.
Set stroke-width="1". fiddle(I enlarged the view)
EDIT
Try a square viewBox fiddle
viewBox="0 0 15 15"

Related

How to set correct Inline SVG Circle coordinates

I can make an inline SVG circle like this:
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
However, I'm struggling to understand the cx and cy and height and width properties.
What I want to achieve is a 15x15px circle that has no free space around it, but I can't seem to get it right.
<svg height="15" width="15"><circle cx="0" cy="0" r="9" stroke="black" stroke-width="1" fill="#c0c0c0" /></svg>
This one only shows the bottom right corner
<svg height="15" width="15"><circle cx="7.5" cy="7.5" r="9" stroke="black" stroke-width="1" fill="#c0c0c0" /></svg> This one cuts the circle to a square
What is the correct way to achieve what I want? You can try for yourself here: https://www.w3schools.com/graphics/tryit.asp?filename=trysvg_circle
Let's make the SVG canvas borders visible for clarity.
To do this, write a CSS style in the header of the SVG fil
style="border:1px solid"
<svg height="100" width="100" style="border:1px solid">
<circle id="circ" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
The next step is to define the parameters width, height, x, y for the bounding rectangle of the circle using the JS getBBox() method
<svg height="100" width="100" viewBox="0 0 100 100" style="border:1px solid">
<circle id="circ" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<script>
let bb = circ.getBBox();
console.log(bb);
</script>
You can see that the width of the rectangle is 80px padding from the beginning of the SVG canvas 10px, total size is 10 + 80 + 10 = 100px
If you want there to be no white space around the svg element, you need to remove these margins and add space to fit a 3px circle stroke
<svg height="84" width="84" viewBox="0 0 84 84" style="border:1px solid">
<circle id="circ" cx="42" cy="42" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<script>
let bb = circ.getBBox();
console.log(bb);
</script>
The border around the SVG canvas can be removed as it was used to visually debug positioning
In the first case the root element has a height and width of 15 so you can see a portion of the x axis from 0 to 15 and the same for the y axis. A circle centred at the origin will therefore only have the bottom right corner visible as that's the only part of the circle within the root element canvas.
As to the second circle 7.5 - 9 (the radius) - 0.5 (1/2 the stroke width) < 0 and 7.5 + 9 + 0.5 > 15 so the circle is simply bigger than the outer SVG element canvas.

Inverse-fill svg shape

I want to make an horizontal s-curved shape where the bottom part of the shape is filled with a color.
When i use a quadratic bézier curve i get the shape that i want, but when i apply a fill color, the inside of the shapes get filled. See below
<svg width="400" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M0,30 Q100,0 200,30 T400,30" stroke="blue" stroke-width="1" fill="blue"/>
</svg>
I then tried do work with individual paths, which got me closer, but i want to reverse-fill the second path, but i have no idea how. This is my shape
<svg width="400" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M0,30 Q100,0 200,30" stroke="blue" stroke-width="1" fill="blue"/>
<path d="M200,30 Q300,60 400,30" stroke="blue" stroke-width="1" fill="none" />
<rect x="0" y="30" width="200" height="30" fill="blue" />
</svg>
How can i apply a filling color to the bottom side of the right curve?
If I understood the task correctly, you need to add three straight lines to your path (30px down from the end of the curve, then 400px left, and then 30px up, or just complete the path). You can use v, h, and Z commands in the same d attribute of the same path element for it:
<svg width="400" height="50" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M0,30 Q100,0 200,30 T400,30 v30 h-400 Z" stroke="blue" stroke-width="1" fill="blue"/>
</svg>

Equivalent of "background-size: fill" for SVG <image> element

I have a situation where I have a SVG graphic whose width is a percentage of the viewport, and whose height is fixed. Inside the graphic I have an SVG image element which I want to always fill its immediate container without distorting, much as would be achieved by using CSS background-size: fill.
How can I achieve this using my SVG?
Here's a minimal setup of the problem (and a codepen):
<svg width=100% height=300>
<rect width=100% height=300 stroke="blue" stroke-width=30 fill="transparent" />
<image xlink:href="//unsplash.it/500/300" width=100% height=100% />
</svg>
In the above snippet, I need the image to fill the entire container without distorting (in this instance, the container being the root SVG), regardless of viewport width.
I can't switch to regular HTML because the graphic I'm working on has an SVG clipping mask applied to the image element.
I found this question, which seems close to what I'm asking, but I don't think answers my question:
How can I make my embedded svg image stetch to fill a container?
In hopes of avoiding the XY problem, here's the actual SVG graphic I'm working on. And the (fixed-height, variable-width) result I'm trying to achieve:
Svg scaling with image
If you add a viewbox to the svg the svg knows how to scale.
Now adding the same viewBox ratio as the svg makes it so the svg will always have the same scale as the image.
You can always scale the image to its inside the viewBox.
Then it will always scale with the svg.
svg {
border: 2px solid black;
}
<svg width="100%" height="100%" viewBox="0 0 500 300">
<image width="500" height="300" xlink:href="//unsplash.it/500/300"/>
</svg>
To keep the height of the image unchanged, set the fixed value of the viewport height and preserveAspectRatio = "none"
<svg width="100%" height="300" viewBox="0 0 500 300" preserveAspectRatio = "none">
<image width="500" height="300" xlink:href="//unsplash.it/500/300"/>
</svg>
UPD
The proportions of the picture will not change, the height remains fixed when using preserveAspectRatio="xMinYMin slice"
<svg width="100%" height="300" viewBox="0 0 500 300" preserveAspectRatio="xMinYMin slice">
<image width="100%" height="300" xlink:href="//unsplash.it/500/300" />
</svg>
UPD2
I looked your codepen Like the idea. I've finished it with your permission. Modified some parameters
<svg width="100%" height="400" preserveAspectRatio="xMinYMin slice">
<defs>
<mask id="clipping">
<rect width="100%" height="400" fill="white"/>
<ellipse cx="50%" cy="120%" rx="75%" ry="37%"/>
</mask>
<linearGradient id="Gradient1" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="white"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
</defs>
<rect width="100%" height="400" fill="orange" mask="url(#clipping)" transform="translate(-20 12) rotate(-2.5)" />
<image xlink:href="https://unsplash.it/1000/500" width="100%" height="400" mask="url(#clipping)" transform="translate(0 -10)" />
<rect width="100%" height="400" fill="url(#Gradient1)" mask="url(#clipping)" transform="translate(0 -10)" opacity="0.25" />
</svg>
I ended up using two SVGs and an image which used a clipping mask defined in the first SVG to clip it down. I was able to make the SVGs scale by only defining a viewbox, not a width and height. I opted to use a fixed aspect ratio instead of a fixed height, percentage width, as I had originally planned.
body > * {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
img {
clip-path: url(#clipper);
}
<svg viewBox="0 0 1000 500">
<defs>
<symbol id="arch" viewBox="0 0 1000 400">
<path d="M0 0 H 1000 V 400 Q 500 300, 0 400" />
</symbol>
<clipPath id="clipper" clipPathUnits="objectBoundingBox">
<path d="M0 0 H 1 V 1 Q .5 .75, 0 1" />
</clipPath>
<linearGradient id="Gradient1" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="#87AFBF"/>
<stop offset="100%" stop-color="#002855"/>
</linearGradient>
</defs>
<use href="#arch" width="100%" y="-40" fill="#F9B000" transform="translate(-20 12) rotate(-2.5)" />
</svg>
<img src="//unsplash.it/1000/400" alt="">
<svg viewBox="0 0 1000 500">
<use href="#arch" y="-50" fill="url(#Gradient1)" opacity="0.75" />
</svg>
CodePen

viewbox and icon positioning in SVG

I just have this very simple svg below;
<div>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 194 186" class="circliful">
<g stroke="#ccc">
<line x1="133" y1="50" x2="140" y2="40" stroke-width="2"></line>
</g>
<g stroke="#ccc">
<line x1="140" y1="40" x2="200" y2="40" stroke-width="2"></line>
</g>
<circle cx="100" cy="100" r="57" class="border" fill="#eee" stroke="none" stroke-width="15" stroke-dasharray="360" transform="rotate(-90,100,100)"></circle>
<circle class="circle" cx="100" cy="100" r="57" fill="none" stroke="#3498DB" stroke-width="5" stroke-dasharray="180, 20000" transform="rotate(-90,100,100)"></circle>
<text text-anchor="middle" x="100" y="110" class="icon" style="font-size: 40px" fill="#3498DB"></text>
<text class="timer" text-anchor="middle" x="175" y="35" style="font-size: 22px; undefined;" fill="#aaa">50%</text>
</svg>
</div>
FIDDLE HERE
The viewbox of the svg element is viewBox="0 0 194 300" and the y attribute on the icon is y="110" , my question is , is the Y attibute intentionally 110 ??
I.E. if i wanted to center the icon i would do the following:
(186/2)+ (height of icon/2) // 186 is the height of the viewbox
Am i right in assuming that the value of 110 is added in respect to the height of the viewbox ?
The y value of 110 will have been chosen by the author in order to vertically centre the text in the circle. It is not directly related to the viewBox. It is related to the centre of the circle, the size of the text (22) and to some extent the shape of the glyphs in whatever font is being used. For instance, the height of capital letters may vary for different fonts given the same font size.
SVG does not provide any way to automatically centre text vertically. So you have to position text manually.
Nope
dominant-baseline="central"
x="100"
100 is the vertical center of the circle (ry in the circle element) and dominant-baseline sets the text Y coordinate to the vertical center of the text.

How to center a circle in an svg

I'm lost as to how I can put a circle element at the center of an svg without it moving around or getting bigger and smaller as I resize the page.
I've tried viewBox but it doesn't do what I expected.
An alternative to the viewBox variant:
<svg width="100" height="100">
<circle cx="50%" cy="50%" r="10"/>
</svg>
The circle would however get bigger if you zoom the whole page.
Another way is to use a zero-length path with rounded linecaps, like this:
<svg viewBox="0 0 100 100">
<path d="M50 50" stroke-linecap="round" stroke="black"
fill="none" vector-effects="non-scaling-stroke"
stroke-width="20"/>
</svg>
http://jsfiddle.net/dAEB9/
<svg viewBox="-1 -1 2 2"> <!-- viewBox defines the coordinate system.-->
<circle cx="0" cy="0" r="1" />
</svg>
https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
http://jsfiddle.net/QrNnN/
Put your circle in group <g> and use transform="translate(x, y)".
<svg viewBox="0 0 400 400">
<g transform="translate(200, 200)">
<circle cx="0" cy="0" r="200" style="" fill="darkOrange"></circle>
</g>
</svg>
Result:
Simple example on JSFiddle:
https://jsfiddle.net/mattez/0p2pstrf/