Reputation: 3301
I'm trying to create an arc that points to a specific angle, width (in degrees), and distance from center (so that the arcs don't overlap).
The included snippet calls JavaScript function DrawLine
that draws the line, but at the incorrect angle. Also, the arc changes its angle when the DISTANCE_FROM_CENTER
variables change, and that shouldn't happen.
I'm including a screenshot of what the angles should look like.
I'm also including how we interpret angles in a circle, and 310 degrees should point to the upper left. The javascript draws them pointing to the right.
let svg = document.getElementById("icon");
function drawLine(azimuth, radius, length)
{
let circumference = radius * 2 * Math.PI;
// Create an SVG <circle> element
let line = document.createElementNS(svg.namespaceURI, "circle");
line.setAttribute("r", radius);
line.setAttribute("stroke-dasharray", length + ' ' + circumference);
line.setAttribute("transform", "rotate(" + azimuth + ")");
// Add it to the <svg> element
svg.appendChild(line);
}
let DISTANCE_FROM_CENTER1 = 93,
DISTANCE_FROM_CENTER2 = 65,
DISTANCE_FROM_CENTER3 = 30,
DISTANCE_FROM_CENTER4 = 9;
drawLine(312, DISTANCE_FROM_CENTER1, 110);
drawLine(312, DISTANCE_FROM_CENTER2, 95);
drawLine(312, DISTANCE_FROM_CENTER3, 55);
drawLine(312, DISTANCE_FROM_CENTER4, 15);
svg {
width: 400px;
}
circle {
fill: none;
stroke: black;
stroke-width: 14;
}
<svg id="icon" viewBox="-100 -100 200 200">
</svg>
Upvotes: 1
Views: 257
Reputation: 3490
If you're trying to line up the middles of the segments, you'll have to calculate the angle. The segment starts at 0 and the length is based on that starting point, and then when you rotate the segment the entire thing turns that amount. Since you're passing the same transform value (200) to all the segments, they all turn the same amount, and so all of their starting points are still aligned.
So try this (I'm just using the values you were using in your snippet, not sure how these relate to the picture, which has a different number of segments and lengths and angles). Calculate the percentage of arc that your segment comprises, and offset the rotation by half of that.
let svg = document.getElementById("icon");
function drawLine(azimuth, radius, length) {
let circumference = radius * 2 * Math.PI;
let arc = length / circumference * 360;
let line = document.createElementNS(svg.namespaceURI, "circle");
line.setAttribute("r", radius);
line.setAttribute("stroke-dasharray", `${length} ${circumference}`);
line.setAttribute("transform", `rotate(${azimuth-(arc/2)})`);
svg.appendChild(line);
}
const arcs = [
{azimuth: 200, dist: 93, length: 110},
{azimuth: 200, dist: 65, length: 95},
{azimuth: 200, dist: 30, length: 55},
{azimuth: 200, dist: 9, length: 15},
//{azimuth: 200, dist: 1, length: 1.5}
];
arcs.forEach(el=>{drawLine(el.azimuth, el.dist, el.length)});
svg {
width: 400px;
}
circle {
fill: none;
stroke: black;
stroke-width: 14;
}
<svg id="icon" viewBox="-100 -100 200 200">
</svg>
SVG thinks 0 is dead right, and that's where the path is going to start, so if you expect 312 to point toward the upper left, like your picture, and you also want to keep passing it 312, etc, I think you can just subtract 90 from the azimuth inside your function. Like this:
let svg = document.getElementById("icon");
function drawLine(azimuth, radius, length) {
let circumference = radius * 2 * Math.PI;
let arc = length / circumference * 360;
let line = document.createElementNS(svg.namespaceURI, "circle");
line.setAttribute("r", radius);
line.setAttribute("stroke-dasharray", `${length} ${circumference}`);
line.setAttribute("transform", `rotate(${azimuth-(arc/2)-90})`);
svg.appendChild(line);
}
const arcs = [
{azimuth: 312, dist: 93, length: 110},
{azimuth: 312, dist: 65, length: 95},
{azimuth: 312, dist: 30, length: 55},
{azimuth: 312, dist: 9, length: 15},
//{azimuth: 312, dist: 1, length: 1.5}
];
arcs.forEach(el=>{drawLine(el.azimuth, el.dist, el.length)});
svg {
width: 400px;
}
circle {
fill: none;
stroke: black;
stroke-width: 14;
}
<svg id="icon" viewBox="-100 -100 200 200">
</svg>
Upvotes: 2