0
votes

I'm using D3.js to draw some SVG shapes. When the shapes overlap, I would like to either dilate or erode the parent/child shapes accordingly to get rid of overlap.

However, these shapes only have a stroke outline, no fill.

There are several examples that use the native SVG filters to achieve this effect, but they all rely on shapes having a fill color.

When I set fill="none" for erode filter, the shape disappears. When I do so for the dilate filter, I am left with a shape with a big stroke-width. I just want a static shape stroke (with transparent fill or no fill).

Here's my JSFiddle. https://jsfiddle.net/programmingprincess/2q3zd0o5/4/

The red/blue/green shape on the left would be perfect IF the blue shape had an empty fill, and only the blue outline. In the JS Fiddle, they use the green to create a "mocked" blue stroke.

The two shapes to the right show what happens when I mess with the stroke and fill values for the green shape.

2

2 Answers

0
votes

You can apply your erode filter on the path within a mask, then apply that mask to the same path.

<svg viewBox="0 0 612 792">
  <defs>
    <filter id="erode">
      <feMorphology operator="erode" in="SourceGraphic" radius="12" />
    </filter>
    <path id="myPath" d="M193.193,85c23.44,0.647,45.161,0.774,62,12c1.596,1.064,12,11.505,12,13
    c0,2.941,8.191,5.669,3,12c-3.088,3.767-6.01-0.758-11-1c-19.56-0.948-33.241,12.296-33,34c0.163,14.698,8.114,24.492,4,41
    c-1.408,5.649-6.571,15.857-10,21c-2.484,3.726-7.898,10.784-12,13c-4.115-11.677,2.686-27.29-6-35c-6.693-5.942-20.021-4.051-26,1
    c-13.573,11.466-11.885,41.492-7,58c-5.8,1.772-18.938,7.685-23,12c-6.752-10.805-15.333-17.333-24-26c-3.307-3.307-9.371-12-15-12
    c-16.772,0-13.963-15.741-13-28c1.283-16.324,1.727-28.24,4-42c1.276-7.72,8-16.411,8-23c0-7.416,15.945-29,23-29
    c4.507,0,17.678-8.701,24-11C164.853,90.76,178.27,88.546,193.193,85"  />
    <mask id="myMask">
      <!-- Everything under a white pixel will be visible -->
      <rect x="0" y="0" width="612" height="792" fill="white" />
      <use href="#myPath" fill="black" filter="url(#erode)"></use>
    </mask>
  </defs>
  <path d="M50,50 L150,150 L250,10 Z" fill="green"></path>
  <use href="#myPath" fill="purple" mask="url(#myMask)"></use>
</svg>

Codepen

0
votes

Using ksav idea of a mask I modified it a bit by drawing the stroke inside the mask after eroding the shape. Because the stroke color is always black when using erode I add an additional filter to invert the mask using a feColorMatrix

<svg viewBox="0 0 612 792">
  <defs>
    <filter id="erode">
      <feMorphology operator="erode" in="SourceGraphic" radius="12" />
    </filter>
    <filter id="invert">
    <feColorMatrix in="SourceGraphic" type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"/>
    </filter>
    <path id="myPath" d="M193.193,85c23.44,0.647,45.161,0.774,62,12c1.596,1.064,12,11.505,12,13
    c0,2.941,8.191,5.669,3,12c-3.088,3.767-6.01-0.758-11-1c-19.56-0.948-33.241,12.296-33,34c0.163,14.698,8.114,24.492,4,41
    c-1.408,5.649-6.571,15.857-10,21c-2.484,3.726-7.898,10.784-12,13c-4.115-11.677,2.686-27.29-6-35c-6.693-5.942-20.021-4.051-26,1
    c-13.573,11.466-11.885,41.492-7,58c-5.8,1.772-18.938,7.685-23,12c-6.752-10.805-15.333-17.333-24-26c-3.307-3.307-9.371-12-15-12
    c-16.772,0-13.963-15.741-13-28c1.283-16.324,1.727-28.24,4-42c1.276-7.72,8-16.411,8-23c0-7.416,15.945-29,23-29
    c4.507,0,17.678-8.701,24-11C164.853,90.76,178.27,88.546,193.193,85"  />
    <mask id="myMask">
      <!-- Everything under a white pixel will be visible -->
      <g filter="url(#invert)">
      <rect x="0" y="0" width="612" height="792" fill="white" />
      <use href="#myPath" stroke-width=9 stroke="#000" fill="white" filter="url(#erode)"></use>
      </g>
    </mask>
  </defs>
  <path d="M50,50 L150,150 L250,10 Z" fill="green" stroke="#00f" stroke-width=4></path>
  <rect x="0" y="0" width="612" height="792" fill="purple" mask="url(#myMask)" />
</svg>