SVG Draw a circle with 4 sectors
The numbers don't make much sense. You start by moving to (200,200)
, then draw a straight line to (300,100)
(length: 141 units) followed by a circular arc ending at (172.73,227.27)
(radius 180 units). Shouldn't the length of the straight line segment at least be equal to the radius of the circle?
You're making life terribly difficult for yourself. If you want to draw four circular segments, a good first step would be to use a <g>
element to move the coordinate system to the centre of the circle. Then you can create all four segments using near-identical code.
Here's an example:
<svg width="200" height="200" viewBox="0 0 200 200">
<g transform="translate(100,100)" stroke="#000" stroke-width="2">
<path d="M0 0-70 70A99 99 0 0 1-70-70Z" fill="#f00"/>
<path d="M0 0-70-70A99 99 0 0 1 70-70Z" fill="#080"/>
<path d="M0 0 70-70A99 99 0 0 1 70 70Z" fill="#dd0"/>
<path d="M0 0 70 70A99 99 0 0 1-70 70Z" fill="#04e"/>
</g>
</svg>
If you want a circle with a different radius, replace 99
with the radius you want, and replace 70
with this value times sqrt(0.5).
Path data breakdown:
M0 0-70 70
Move to (0,0)
, then draw a straight line to (-70,70)
(the L
is implied).
A99 99 0 0 1-70-70
Draw an elliptical arc from this point to (-70,-70)
with rx=rx=99
, x-axis-rotation=0
, large-arc-flag=1
, and sweep-flag=0
. (The last two parameters are described here).
Z
Close the path.
i'm realy lazy, so what i do when i need to draw arcs, is i use the following script: i create a unit vector:
var p = svgElem.createSVGPoint()
p.x = 0
p.y = 1
then i cerate a matrix for my rotations:
var m = svgElem.createSVGMatrix()
and finally i rotate the unit vector and translate/scale it to where i want it.
var p2 = p.matrixTransform(m.rotate(45))
p2.x = cx + p2.x*rx
p2.y = cy + p2.y*ry
and now i can either console.log(p2.x,p2.y)
if i want to hardcode the segment, or you can create the segments from script.
here is a basic example (i know, for a simple case like the one above, this is not necessary, but its an easy general solution, which has help me a lot in the past years...)
var svgElem=document.getElementById("svg");
var cx=100;
var cy=100;
var rx=90;
var ry=90;
var p = svgElem.createSVGPoint();
p.x = 0;
p.y = 1;
var m = svgElem.createSVGMatrix();
var p2 = p.matrixTransform(m.rotate(45));
p2.x = cx + p2.x*rx;
p2.y = cy + p2.y*ry;
console.log(p2.x,p2.y);
var path = document.createElementNS("http://www.w3.org/2000/svg","path");
svgElem.appendChild(path);
var d="M"+cx+" "+(cy+ry)+"A"+rx+" "+ry+" 0 0 1"+p2.x+" "+p2.y+"L"+cx+" "+cy+"z";
path.setAttribute("d",d)
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="200" height="200">
</svg>
Here is the function which does programmatic generation of SVG
sector path I used in React
component:
getSectorPath(x, y, outerDiameter, a1, a2) {
const degtorad = Math.PI / 180;
const halfOuterDiameter = outerDiameter / 2;
const cr = halfOuterDiameter - 5;
const cx1 = (Math.cos(degtorad * a2) * cr) + x;
const cy1 = (-Math.sin(degtorad * a2) * cr) + y;
const cx2 = (Math.cos(degtorad * a1) * cr) + x;
const cy2 = (-Math.sin(degtorad * a1) * cr) + y;
return "M" + x + " " + y + " " + cx1 + " " + cy1 + " A" + cr + " " + cr + " 0 0 1 " + cx2 + " " + cy2 + "Z";
}
and here is the usage:
<svg width={outerDiameter} height={outerDiameter}>
<path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 45, 135)} fill="#f00"/>
<path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 135, 225)} fill="#f00"/>
<path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 225, 315)} fill="#f00"/>
<path d={this.getSectorPath(outerDiameter / 2, outerDiameter / 2, outerDiameter, 315, 45)} fill="#f00"/>
</svg>