Round-cap lines used in a SVG pattern

2020-03-06 02:50发布

Currently using an SVG <pattern> element with a bunch of <line> elements will cause it to have a sort of tapered-off edge. I've tried a bunch of different CSS stylings to get around this, but nothing's really worked. Here's the code to a circle with a stitch masked on it:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="500" width="500">
  <defs>
    <pattern id="stripe" patternUnits="userSpaceOnUse" width="20" height="20">
      <line x1="0" y1="0" x2="20" y2="20" />
    </pattern>
    <mask id="mask">
      <rect height="500" width="500" style="fill: url(#stripe)" />
    </mask>
    <style>
      #stripe line {
        fill: white;
        stroke: white;
        stroke-linecap: square;
        stroke-linejoin: miter;
        stroke-width: 10px;
      }
      g {
        mask: url(#mask);
        stroke-linecap: square;
        stroke-linejoin: miter;
      }
      circle {
        fill: green;
      }
    </style>
  </defs>
  <g>
    <circle cx="250" cy="250" r="200" style="fill: rgba(0, 255, 0, 0.2);" />
  </g>
</svg>

And here's a fiddle of what this looks like. No combination of stoke-linecap and stroke-linejoin has worked for me. Do I instead need to draw a full <path> across the entire mask?

Thanks for any help.

标签: svg
4条回答
手持菜刀,她持情操
2楼-- · 2020-03-06 03:29

That's an interesting problem. It looks like a line-cap issue but the actual problem is that the line corners of your pattern lie outside of the coordinates. Here is a diagram to understand what is happening:

enter image description here

You can either make the pattern larger with <pattern id="stripe" patternUnits="userSpaceOnUse" width="30" height="30"> or move the coordinates of your lines. In a cursory search I couldn't find any directive that would allow your pattern to overlap or display the overflow, but someone else might know of a workaround.

查看更多
Rolldiameter
3楼-- · 2020-03-06 03:43

Woo! What a ride.

After seeing Duopixel's answer, I got started on a trail. I didn't know it was possible to achieve this effect until I understood the bounding box that applies to patterns.

Googling brought me to this mailing list answer which didn't make much sense at first until the original author returned with gained insight (sorry, too many links). I looked back at the answer and saw potential in solving this problem.

Solution:
You have to overlay two patterns on-top of eachother in the right coordinates!

Code: (demo - http://jsfiddle.net/66UDU/)

<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="500" width="500">
  <defs>
    <pattern id="stripe1" class="stripe" patternUnits="userSpaceOnUse" width="20" height="20">
      <line x1="0" y1="0" x2="20" y2="20" />
    </pattern>
    <pattern id="stripe2" class="stripe" patternUnits="userSpaceOnUse" x="6" y="6" width="20" height="20">
      <line x1="0" y1="0" x2="20" y2="20" />
    </pattern>
    <mask id="mask">
      <rect height="500" width="500" style="fill: url(#stripe1)" />
      <rect height="500" width="500" style="fill: url(#stripe2)" />
    </mask>
    <style>
      .stripe line {
        fill: white;
        stroke: white;
        stroke-width: 4px;
      }
      g {
        mask: url(#mask);
      }
      circle {
        fill: rgba(0, 255, 0, 0.25);
      }
    </style>
  </defs>
  <g>
    <circle cx="250" cy="250" r="200" />
  </g>
</svg>

=)

查看更多
该账号已被封号
4楼-- · 2020-03-06 03:44

The post is old, but as I searched for a solution maybe someone also needs another solution like me. As described above, a diagonal pattern has problems, thats why I created a straight horizontal line pattern and tranformed it with patternTransform="rotate(45)". Then only 1 <line /> is needed instead of 2 overlapping ones.

Example:

<pattern id="stripe45" className="stripe-pattern" patternUnits="userSpaceOnUse" patternTransform="rotate(45)" width=".2" height=".2">
      <line x1="0" y1=".1" x2=".2" y2=".1" />
    </pattern>
查看更多
We Are One
5楼-- · 2020-03-06 03:45

Well I know that this answer isn't far off 2 years late, but I stumbled across this question while researching another problem and thought I'd throw in my 2 cents for anyone who might come across it.

The problem here is as highlighted by Duopixel: the pattern just doesn't tile right.

Your solution certainly masks the problem by overlaying two non-tiling patterns to hide the non-tiling corners, but if you make the pattern wider and add additional lines offset from one another, and offset so as to ensure they never overlap a corner of the tile you can create a functioning pattern. You can up the stroke width on this all the way up without any problems with the corners.

<pattern id="stripe" patternUnits="userSpaceOnUse" width="40" height="20">
  <line x1="-10" y1="0" x2="10" y2="20" />
  <line x1="10" y1="0" x2="30" y2="20" />
  <line x1="30" y1="0" x2="50" y2="20" />
</pattern>

See this fiddle

I actually like the pattern made by the original problem though! I might have to find a use for it somewhere :)

查看更多
登录 后发表回答