I have two identical paths, but stroked differently: https://jsfiddle.net/vzbdcupf/
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" width="300" height="300">
<style>
.s0 { fill: none; stroke: red ; stroke-width: 80 }
.s1 { fill: none; stroke: black; stroke-width: 4 }
</style>
<path d="m100 100c20 7 33-1 36-25 2-13-71 13-36 25z"/>
<path d="m100 100c20 7 33-1 36-25 2-13-71 13-36 25z"/>
</svg>
When I stroke the path with red, the stroke-width is huge, and there should not be any "hole" inside it. Why is there a hole?
I think it is related to the rendering algorithm (stroking is converted into filling paths, and the inner path gets "reflected"). But how do you explain it in terms of the SVG specification, to be able to say the rendering is correct?
CodePudding user response:
Not an explanation why this happens but a possible workaround:
Some observations on the occurrence of this rendering:
- appears on paths containing curve commands (
c
,s
,q
etc.) - won't appear on primitives like
<circle>
,<polygon>
or paths using only line commands likel
,h
,v
Applying a dashed stroke seems to fix this rendering issue:
pathLength="100"
stroke-dasharray="100 0"
stroke-linecap="round"
Example:
function applyDash() {
const svg = document.querySelector('svg');
const paths = svg.querySelectorAll('path');
paths.forEach(function(path) {
path.setAttribute('pathLength', 100);
path.setAttribute('stroke-dasharray', '100 0');
path.setAttribute('stroke-linecap', 'round');
})
}
<p><button type="button" onclick="applyDash()"> Apply dash fix</button></p>
<svg xmlns="http://www.w3.org/2000/svg" width="300px" height="300px" viewBox="0 0 300 300">
<path fill="none" stroke="#FF1746" stroke-width="80" d="M58,100c10,3.5,18.3,3.3,24.4-0.9S92.5,87,94,75 c1-6.5-16.8-3.3-30.4,3.1S40.5,94,58,100z" />
<path fill="none" stroke="#FF1746" stroke-width="80" d="M211.6,78.1l-14.5,11.1L206,100l13.6,2.4l10.7-3.3
l7.5-9.1l4.1-15l-9.7-3.3L211.6,78.1L211.6,78.1z" />
<circle fill="none" stroke="#FF1746" stroke-width="80" cx="230" cy="232.5" r="9.8" />
<path fill="none" stroke="#FF1746" stroke-width="80" d="M77.1,232.5c0,5.4-4.4,9.8-9.8,9.8
s-9.8-4.4-9.8-9.8s4.4-9.8,9.8-9.8S77.1,227.1,77.1,232.5z" />
</svg>
CodePudding user response:
Your guess as to what is happening is basically correct. When 2D graphics engines "stroke" a path, what they actually do is effectively convert the stroke into a filled path of its own. When the path that is being stroked has tight corners, larger stroke widths can cause the inside borders of the stroke path to overlap each other. The result is the same as if any path intersects with itself - it can cause holes. With actual fills, you can control how those holes are rendered with the fill-rule
property. Unfortunately, there is no such property for strokes.
The SVG 2 specification briefly mentions this phenomenon here, but ultimately leaves it up to implementers how they want to deal this situation.