Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Round-cap lines used in a SVG pattern

Tags:

svg

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.

like image 390
matt Avatar asked Nov 30 '25 05:11

matt


2 Answers

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 :)

like image 83
Andru Avatar answered Dec 03 '25 23:12

Andru


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>

=)

like image 38
matt Avatar answered Dec 04 '25 00:12

matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!