Outline a group of touching shapes with SVG
Asked Answered
C

3

2

For a certain style I'm going for, I want to outline a group of shapes in SVG. Applied to a group, the stroke property appears to outline each shape individually--effectively going on top of other shapes nearby. To explain my situation more clearly: I have a group of touching rectangles that are 8x8 pixels each. They do not form a larger rectangle, however.

For simplicity's sake, let's say they form a cross. So I have 5 rectangles--1 in the center and one more on each side of that one. I want to outline them all as if they were 1 shape. Given that this "cross" shape changes, I would prefer not to use paths since that would require a lot more coding. Isn't there any way that I could get the effects filter to recognize this group as a single shape?

If not, is it at least possible to make a black copy of this group that's exactly 2px larger in width and height that I can position behind the group to create a solid black outline? And if so, is it possible without duplicating the group?

Thank you for any help.

Chyack answered 22/2, 2012 at 9:14 Comment(0)
M
3

Like this:

<svg xmlns="http://www.w3.org/2000/svg">
    <defs>
        <filter id="biggerbwcopy">
          <feColorMatrix values="0 0 0 0 0
                                 0 0 0 0 0
                                 0 0 0 0 0
                                 0 0 0 1 0"/>
          <feMorphology operator="dilate" radius="2"/>
        </filter>
    </defs>
    <rect id="r" x="10" y="10" width="20" height="20" fill="blue" onclick="biggerbw()"/>
    <script>

      function biggerbw() {
        document.getElementById("r").style.filter="url(#biggerbwcopy)";
      }
    </script>
</svg>

http://jsfiddle.net/longsonr/LrDHT/1/ click on the rectangle and it becomes black and bigger.

You could extend the filter to put the original shape on top using feMerge

Michael answered 22/2, 2012 at 11:45 Comment(1)
feMorphology is exactly what I needed! ThanksChyack
I
17

You could use an svg filter like this one for example:

<filter id="outline">
  <feMorphology operator="dilate" in="SourceAlpha" radius="1"/>
  <feComposite in="SourceGraphic"/>
</filter>

Use the filter like this:

<g filter="url(#outline)">
  <circle fill="lime" cx="20" cy="10" r="5"/>
  <rect x="40" y="10" width="100" height="10" fill="lime"/>
  <line x1="20" y1="10" x2="80" y2="15" stroke="lime"/>
</g>

Another alternative that might work, depending on how your content looks is something like this:

<use xlink:href="#g" stroke-width="10" stroke="black"/>
<g id="g">
  <circle fill="lime" cx="20" cy="10" r="5"/>
  <rect x="40" y="10" width="100" height="10" fill="lime"/>
  <circle fill="lime" cx="140" cy="10" r="5"/>
  <circle fill="lime" cx="120" cy="10" r="5"/>
</g>
Ilke answered 22/2, 2012 at 12:43 Comment(2)
Thanks for the answer; had to give it to the first though :) Also useful though ^^ +1Chyack
Is there anyway to do this for multiple transparent shapes? I assume you would need a mode other than "SourceAlpha"Slagle
M
3

Like this:

<svg xmlns="http://www.w3.org/2000/svg">
    <defs>
        <filter id="biggerbwcopy">
          <feColorMatrix values="0 0 0 0 0
                                 0 0 0 0 0
                                 0 0 0 0 0
                                 0 0 0 1 0"/>
          <feMorphology operator="dilate" radius="2"/>
        </filter>
    </defs>
    <rect id="r" x="10" y="10" width="20" height="20" fill="blue" onclick="biggerbw()"/>
    <script>

      function biggerbw() {
        document.getElementById("r").style.filter="url(#biggerbwcopy)";
      }
    </script>
</svg>

http://jsfiddle.net/longsonr/LrDHT/1/ click on the rectangle and it becomes black and bigger.

You could extend the filter to put the original shape on top using feMerge

Michael answered 22/2, 2012 at 11:45 Comment(1)
feMorphology is exactly what I needed! ThanksChyack
M
0

Here's an answer without SVG filters:

svg { fill: pink; }
rect { fill: lightblue; }
#outline-me {
    filter: 
      drop-shadow( 2px  2px 0px black) 
      drop-shadow(-2px  2px 0px black) 
      drop-shadow(-2px -2px 0px black)
      drop-shadow( 2px -2px 0px black);
}
<svg xmlns="http://www.w3.org/2000/svg" height="344" width="440">    
 <g id="outline-me">
  <rect x="130" y="10" width="20" height="20" />
  <rect x="130" y="30" width="20" height="20" />
  <rect x="110" y="30" width="20" height="20" />
  <rect x="150" y="30" width="20" height="20" />
  <rect x="130" y="50" width="20" height="20" />
 </g>
</svg>

The nice thing about this is that in HTML you can have the rectangles transparent, and just show the outline using:

rect { fill: white; /* background: white */ }
#outline-me { mix-blend-mode: darken; }

(Unfortunately that bit wouldn't work for me for the SVG case)

http://jsfiddle.net/EoghanM/9ua5fyjx

Mercia answered 29/5, 2023 at 16:25 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.