How to set correct Inline SVG Circle coordinates - html

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.

Related

How to make background of SVG image opaque

I'm trying to make the entire SVG image background opaque.
All I could find on my search was how to make specific elements inside the image opaque, but I couldn't find anything regarding the background.
I know how to make the circle itself opaque/transparent, but not the background.
What do I need to add to make everything behind the circle opaque?
This is how the picture looks, note the white/grey squares indicating transparency
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="100px" viewBox="0 0 300 100">
<circle cx="50" cy="50" r="40" fill="blue"/>
</svg>
Try this out
You can also refer this link for the same: https://www.geeksforgeeks.org/how-to-set-the-svg-background-color/
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="100px" viewBox="0 0 300 100">
<rect width="100%" height="100%" fill="green" />
<circle cx="50" cy="50" r="40" fill="blue"/>
</svg>

How can I draw a pie chart only using stroke-dasharray, not stroke-dashoffset

I am trying to draw a pie chart only using stroke-dasharray and other things like rotate and translate, I am not allowed to use stroke-dashoffset since it is not supported by wkhtmltopdf 0.12.5. I have tried to do something similar to the code below
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="10" cx="10" cy="10" fill="white" />
<circle r="5" cx="10" cy="10" fill="bisque"
stroke="tomato"
stroke-width="10"
stroke-dasharray="10.99 31.4"
transform="rotate(-90) translate(-20)"/>
</svg>
Where 31.4 is the circumference of the circle and 10.99 is 35% of the circumference. This is drawing a slice representing 35% of the pie. How can I draw more slices (for example one respresenting 40% and another for 13%) after this one without using stroke-dashoffset, I could not figure this out. Thanks a lot for the help guys.
Creating pie charts that way is not really recommended. By "that way", I am referring to making circles where the stroke width matches the radius of the circle. To be precise, the stroke width is double the circle radius.
Some browsers (or browser versions) and rendering libraries have had bugs rendering circles of that form. The recommended way would be to create a path for each pie chart segment.
However, assuming you want to continue with this method, then here is what you need to know.
Stroke patterns on <circle> elements are rendered starting at 3 o'clock, and proceed clockwise around the circle.
That's why you have the rotate(-90) in your example above. The -90 rotation is rotating the circle -90deg so that the stroke starts at the top (12 o'clock).
The two numbers in the dash pattern are <length of dash> <length of gap>. The pattern then repeats.
Okay. Let's update your SVG to add the extra segments you requested.
Firstly, I would suggest a couple of changes:
Move the rotate(-90) to a parent group so that you don't have to worry about it when calculating the rotations for your new slices.
You'll find it a lot easier if you use the version of rotate() that takes a centre of rotaion: rotate(angle, centreX, centreY).
We need to add the fill colour (fill="bisque") to a separate circle. Otherwise the fill of each new segment you add will overlap the previous segments.
So our new starting point is this:
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
</g>
</svg>
Add a 40% segment
The stroke length you need will be 40% of 31.4 = 12.56.
To rotate it so that it starts at the end of the first segment, you'll need to rotate it by an angle equal to (10.99 / 31.4) * 360deg = 126deg.
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
<circle r="5" cx="10" cy="10"
stroke="goldenrod"
stroke-dasharray="12.56 31.4"
transform="rotate(126, 10,10)"/>
</g>
</svg>
Add a 13% segment
The stroke length you need will be 13% of 31.4 = 4.082.
To rotate it so that it starts at the end of the previous segment, you'll need to sum the lengths of the first two segments, and convert that to an angle.
((10.99 + 12.56) / 31.4) * 360deg = 0.75 * 360 = 270deg`.
<svg height="20%" width="20%" viewBox="0 0 20 20" style="border:1px solid gray; ">
<circle r="5" cx="10" cy="10" fill="bisque" />
<g transform="rotate(-90, 10,10)" fill="none" stroke-width="10">
<circle r="5" cx="10" cy="10"
stroke="tomato"
stroke-dasharray="10.99 31.4"/>
<circle r="5" cx="10" cy="10"
stroke="goldenrod"
stroke-dasharray="12.56 31.4"
transform="rotate(126, 10,10)"/>
<circle r="5" cx="10" cy="10"
stroke="cornflowerblue"
stroke-dasharray="4.082 31.4"
transform="rotate(270, 10,10)"/>
</g>
</svg>
I wrapped Paul his answer in a Custom Element <svg-pie-chart> (supported in all modern Browsers)
By using unknown element behaviour, it simplifies usage in an HTML document:
<svg-pie-chart>
<circle r="25%" cx="50%" cy="50%" fill="bisque" />
<segment percent="35" stroke="tomato" />
<segment percent="40" stroke="goldenrod" />
<segment percent="13" stroke="cornflowerblue" />
<circle r="2" cx="10" cy="10" fill="green" />
</svg-pie-chart>
<style>
svg-pie-chart svg {
width: 180px;
background: grey;
}
</style>
<script>
customElements.define("svg-pie-chart", class extends HTMLElement {
connectedCallback() {
setTimeout(() => { // wait till all children are (unknown) Elements
let rotate = 0;
let svg = [...this.querySelectorAll("*")].map(el => {
let elsvg = el.outerHTML;
if (el.nodeName == "SEGMENT") {
let [percent, stroke, deg = percent.value * .3142] = el.attributes;
elsvg = `<circle r='5' cx='10' cy='10' stroke='${stroke.value}'` +
` stroke-dasharray='${deg} 31.42' transform="rotate(${rotate} 10 10)"/>`;
rotate += (deg / 31.42) * 360;
}
return elsvg;
});
this.innerHTML=`<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'>` +
`<g transform='rotate(-90 10 10)' fill='none' stroke-width='10'></g></svg>`;
this.querySelector("g").innerHTML = svg.join``;
})}});
</script>

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>

Why is this simple SVG icon scaling?

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"

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/