I'll suggest a solution which works, but whose precisely mechanism I can't explain (Edit: explained in @LeBeau answer)
This is the culprit in your code:
end -= this.isCompleteAngle(start, end) ? 0.0001 : 0;
We can clearly see that if we increase the value when the ternary is true
, that is, increasing the amount of subtraction of the end
variable, the bizarre effect disappears. Let's show it.
With a very small subtraction, just 0.00001
, to make bizarre effect more noticeable:
function getPathArc(center, start, end, radius) {
end -= this.isCompleteAngle(start, end) ? 0.00001 : 0;
var degree = end - start;
degree = degree < 0 ? (degree + 360) : degree;
return this.getCirclePath(
center, getLocationFromAngle(start, radius, center),
getLocationFromAngle(end, radius, center), radius, (degree < 180) ? 0 : 1
);
}
function getCirclePath(center, start, end, radius, clockWise) {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' +
radius + ' 0 ' + clockWise + ' 1 ' + end.x + ' ' + end.y;
}
function getLocationFromAngle(degree, radius, center) {
var radian = (degree * Math.PI) / 180;
return {
x: Math.cos(radian) * radius + center.x,
y: Math.sin(radian) * radius + center.y
}
}
function isCompleteAngle(startAngle, endAngle) {
var totalAngle = endAngle - startAngle;
totalAngle = totalAngle <= 0 ? (totalAngle + 360) : totalAngle;
return Math.floor(totalAngle / 360) !== 0;
}
window.onload = function() {
document.getElementById("arc1").setAttribute("d", getPathArc({
x: 250,
y: 250
}, 90, 90, 200));
document.getElementById("arc2").setAttribute("d", getPathArc({
x: 250,
y: 250
}, 70, 70, 200));
};
<svg width="500" height="500">
<path id="arc1" fill="none" stroke="green" stroke-width="2" />
<path id="arc2" fill="none" stroke="red" stroke-width="2" />
</svg>
Now with a bigger subtraction, 0.01
:
function getPathArc(center, start, end, radius) {
end -= this.isCompleteAngle(start, end) ? 0.01 : 0;
var degree = end - start;
degree = degree < 0 ? (degree + 360) : degree;
return this.getCirclePath(
center, getLocationFromAngle(start, radius, center),
getLocationFromAngle(end, radius, center), radius, (degree < 180) ? 0 : 1
);
}
function getCirclePath(center, start, end, radius, clockWise) {
return 'M ' + start.x + ' ' + start.y + ' A ' + radius + ' ' +
radius + ' 0 ' + clockWise + ' 1 ' + end.x + ' ' + end.y;
}
function getLocationFromAngle(degree, radius, center) {
var radian = (degree * Math.PI) / 180;
return {
x: Math.cos(radian) * radius + center.x,
y: Math.sin(radian) * radius + center.y
}
}
function isCompleteAngle(startAngle, endAngle) {
var totalAngle = endAngle - startAngle;
totalAngle = totalAngle <= 0 ? (totalAngle + 360) : totalAngle;
return Math.floor(totalAngle / 360) !== 0;
}
window.onload = function() {
document.getElementById("arc1").setAttribute("d", getPathArc({
x: 250,
y: 250
}, 90, 90, 200));
document.getElementById("arc2").setAttribute("d", getPathArc({
x: 250,
y: 250
}, 70, 70, 200));
};
<svg width="500" height="500">
<path id="arc1" fill="none" stroke="green" stroke-width="2" />
<path id="arc2" fill="none" stroke="red" stroke-width="2" />
</svg>
Do you see? The two arcs overlap if the subtraction is bigger.
Therefore, the solution is increasing the difference in end -= someValue
.
Further investigation:
While investigating this, I console.log
ed every variable. They are almost the same.
Then, I copied both elements in both snippets. To my surprise, they are almost the same. Have a look, these are the two paths in the first snippet:
<path id="arc1" fill="none" stroke="green" stroke-width="2"
d="M 250 450 A 200 200 0 1 1 250.0349065848627 449.9999969538258"></path>
<path id="arc2" fill="none" stroke="red" stroke-width="2"
d="M 318.40402866513375 437.93852415718163 A 200 200 0 1 1 318.40406146659313 437.9385122184236"></path>
Now the two paths produced by the second snippet:
<path id="arc1" fill="none" stroke="green" stroke-width="2"
d="M 250 450 A 200 200 0 1 1 250.0000349065851 449.99999999999693"></path>
<path id="arc2" fill="none" stroke="red" stroke-width="2"
d="M 318.40402866513375 437.93852415718163 A 200 200 0 1 1 318.4368290834931 437.92658253955653"></path>
As you can see, the red paths are are almost identical, except for the x axis starting/ending values. It seems that, the more similar they are, the bigger the efect.
To test this, lets see what happens if the values are exactly the same (the black circle marks the origin):
<svg width="500" height="700">
<path id="arc1" fill="none" stroke="green" stroke-width="2" d="M 250 450 A 200 200 0 1 1 250.0349065848627 449.9999969538258"></path>
<path id="arc2" fill="none" stroke="red" stroke-width="2" d="M 318.4368290834931 437.93852415718163 A 200 200 0 1 1 318.4368290834931 437.92658253955653"></path>
<circle cx="318.4368290834931" cy="437.93852415718163" r="4"></circle>
</svg>
As I said before, I cannot explain this. But I'm sure one of the SVG specialists here shortly will.