In order for dash patterns to render the same in all SVG renderers, the SVG specification defines where the dash pattern should begin for all shapes. Including rectangles.
For a rectangle, the start point is at the left end of the horizontal section of the top side of the rectangle. So if there is a rounded corner, it is at the point where the curve meets the straight. The dash pattern then proceeds around the rectangle in a clockwise direction.
That start point is effectively a tunnel or portal through which the dash pattern emerges and disappears into. You can't change its location, you just have to construct your dash pattern carefully with that start point in mind.
You don't say where exactly how much of the rounded corner you want included in the top stroke, but I am going to assume you want to include the whole of the curve.
In your example the rectangle is 150x150 with a corner radius of 20. Let's call those w, h, and r.
To calculate the dash pattern correctly we need to work out the lengths of all the sides and rounded corners accurately.
The top and bottom will each be length (w - 2 * r) = 110
. Lets call this xlen
.
The left and right sides will be length (w - 2 * r) = 110
. Let's call this ylen
.
Each of the rounded corners will be length (PI * 2 * r) / 4 = 31.416
. Let's call this rlen
Dash pattern version 1
We could just make our dash pattern up from the different lengths of pattern that we need to complete the circumference of the rectangle. Ie.
- Top of the rect (not including left corner):
xlen + rlen = 141.416
.
- Right side gap in pattern:
ylen = 110
.
- Bottom side (including both corners:
rlen + xlen + rlen = 172.832
.
- Left side gap in pattern:
ylen = 110
.
- Top left corner:
rlen = 31.416
.
So the dash pattern would be "141.416 110 172.832 110 31.416"
.
rect {
stroke-width: 4px;
stroke: black;
fill:red;
stroke-dasharray: 141.416 110 172.832 110 31.416;
}
<svg width="400" height="400">
<rect x="10" y="10" width="150" height="150" rx="20"/>
</svg>
Dash pattern version 2
The other, simpler, but less obvious solution perhaps is to take advantage of the fact that dash patterns repeat. Combine this with a dash offset and we can make the dash pattern a lot simpler.
- Top of the rect (including both corners):
rlen + xlen + rlen = 172.832
.
- Right side gap in pattern:
ylen = 110
.
- Then let it repeat to form the bottom and left sides.
So the dash pattern would be "172.832 110"
.
"But wait" you might say, That won't wwork because the pattern will be shifted clockwise by the length of a rounded corner. You are right.
rect {
stroke-width: 4px;
stroke: black;
fill:red;
stroke-dasharray: 172.832 110;
}
<svg width="400" height="400">
<rect x="10" y="10" width="150" height="150" rx="20"/>
</svg>
However if we use stroke-dashoffset
to shift the pattern left/anti-clockwise, we will lose some of the first dash, but we will also be "pulling" some of the next repeat of the dash pattern back through that start/end "portal". This relies on the dash pattern being the exact right length. That's why we were so careful at the start to calculate all the lengths accurately.
Spo what is the value we need to use for stroke-dashoffset
? The way the dash offset works is that it specifies how far into the pattern we should start drawing from. So it needs to be after the length of the rounded corner, or 31.416
.
So if we add that we get:
rect {
stroke-width: 4px;
stroke: black;
fill:red;
stroke-dasharray: 172.832 110;
stroke-dashoffset: 31.416;
}
<svg width="400" height="400">
<rect x="10" y="10" width="150" height="150" rx="20"/>
</svg>
You can see that if you want your dash pattern to start and stop at the correct places, it is possible. You just need to calculate the lengths in your dash pattern accurately.
If you need to have the same sort of pattern on rectangle of other sizes you need to recaclculate the lengths using the formulas I list at the start of this answer.