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.

Ruffy
  • 835
  • 1
  • 10
  • 17

3 Answers3

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>
Erik Dahlström
  • 59,452
  • 12
  • 120
  • 139
  • Thanks for the answer; had to give it to the first though :) Also useful though ^^ +1 – Ruffy Feb 22 '12 at 12:55
  • Is there anyway to do this for multiple transparent shapes? I assume you would need a mode other than "SourceAlpha" – Broper Feb 22 '23 at 15:57
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

Robert Longson
  • 118,664
  • 26
  • 252
  • 242
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

EoghanM
  • 25,161
  • 23
  • 90
  • 123