I want to customize a stroke for an SVG ellipse, placing the stroke inside the ellipse. If I set the stroke property, I get the stroke divided, with half inside and half outside the ellipse. To achieve my goal, I tried placing a smaller ellipse inside the real ellipse, setting a stroke for the smaller ellipse, and setting its fill to none.
However, I noticed that the total size of the smaller ellipse is slightly larger than the real ellipse. I suspect that the formula used to calculate the rx and ry of the smaller ellipse may not be correct. I've been making the rx and ry of the real ellipse subtract half the stroke width.
I would like to know if there is a more precise formula for calculating the rx and ry of the smaller ellipse, or if there is another method to draw my stroke inside the real ellipse.
Edit: Use clip-path can hide the extra erea, but it may cause performance issue in my project, so I want to know if there is a 'better' way. And I also want to understand why there exists some extra area.
Thanks for any help! Here is my codepen: https://codepen.io/cactusxx/pen/GReKMRJ
var ellipseElement = document.getElementById("myEllipse");
var strokeElement = document.getElementById("myStroke");
var initialRx = parseFloat(ellipseElement.getAttribute("rx"));
var initialRy = parseFloat(ellipseElement.getAttribute("ry"));
var strokeWidth = 40;
var halfStrokeWidth = strokeWidth / 2.0;
var strokeRx = initialRx - halfStrokeWidth;
var strokeRy = initialRy - halfStrokeWidth;
console.log(strokeRx, strokeRy);
strokeElement.setAttribute("rx", strokeRx);
strokeElement.setAttribute("ry", strokeRy);
strokeElement.setAttribute("stroke-width", strokeWidth);
svg {
border: 1px solid blue;
}
<svg width="500" height="300" xmlns="http://www.w3.org/2000/svg">
<ellipse id="myEllipse" cx="150" cy="100" rx="100" ry="50" fill="green" />
<ellipse id="myStroke" fill="none" cx="150" cy="100" stroke="red" stroke-opacity=0.5 />
</svg>
You fall victim to a rule of geometry: If you draw a path at a fixed distance from the outline of an ellipse, it is not an ellipse. That is relatively easy to see if you draw the path inside, resulting in a smaller size, but it also holds true for paths outside. The geometrical proof is not something to be explained here. If you are interested, you should ask at math.stackexchange.
<svg viewBox="0 0 300 200">
<ellipse cx="150" cy="100" rx="80" ry="30" fill="none" stroke="darkgreen" stroke-width="40" />
<ellipse cx="150" cy="100" rx="80" ry="30" fill="none" stroke="red" />
<ellipse cx="150" cy="100" rx="60" ry="10" fill="none" stroke="red" />
<ellipse cx="150" cy="100" rx="100" ry="50" fill="none" stroke="red" />
</svg>
You won't be able to draw what you want to achieve if you combine two ellipses with different axis sizes. Instead, the best way is clipping away the part of the stroke lying outside the geometric path by using the same definition twice:
<clipPath>
<use>
element and set fill and stroke to your liking<use>
element with a clip-path
presentation attribute or CSS property.<svg width="500" height="300" xmlns="http://www.w3.org/2000/svg">
<clipPath id="clip">
<ellipse id="myEllipse" cx="150" cy="100" rx="100" ry="50" />
</clipPath>
<use href="#myEllipse" fill="green" stroke="red" stroke-width="80" clip-path="url(#clip)" />
</svg>