Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SVG: border outline for group of elements

Tags:

html

svg

I'd like to add a border to a number of elements which are grouped by <g>. As an example:

<g id="group">
  <circle cx="125" cy="125" r="65" fill="orange" />
  <line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
</g>

Best case, the border should look like in the following picture. The distance between the elements and the border is not required (but nice to have). The main goal should be a single border (stroke) around the group elements.

group of elements

I found the picture in a tutorial, but there it was just to demonstrate what a group of elements may look like. So this doesn't help.

I already tried different solutions, but none of them worked as expected, e.g.

  • A SVG filter using feColorMatrix and feMorphology (see this post). But in this case, the color of the elements changes when applying the filter.
  • Styling the <g> with stroke and stroke-width results in a rectangular border around the group, which is also not the thing I want.

Any ideas, how to get a border around the group as shown in the picture?

like image 230
mixable Avatar asked Apr 06 '18 13:04

mixable


People also ask

Can you add a border to a svg element?

Make sure to add the <circle> element inside of the <svg> element. When rendered , it looks like this: We can also add a border line to the circle by adding stroke="black" and stroke-width="5" inside of the <circle> element.

How do you add a border to svg?

Try adding CSS filter() dropshadow (this can be applied on any svg: <img> , background-image , in the dom, etc.) Or, create some javascript function that clones each of the elements within the svg, removing fill/stroke attributes, and wrapping them in a g tag that has fill="none" and stroke attributes set.

Why does my svg have a border?

This is caused by the svg renderer in browsers trying to smooth out your svg images.


1 Answers

It would be difficult to get the dashed stroke shown in the image you provided. But a solid outline should be possible. Here's an example:

<svg width="250" height="250" viewBox="0 0 250 250">
  <defs>
    <filter id="groupborder" filterUnits="userSpaceOnUse"
            x="0" y="0" width="250" height="250">
      <feMorphology operator="dilate" in="SourceAlpha"
                    radius="8" result="e1" />
      <feMorphology operator="dilate" in="SourceAlpha"
                    radius="10" result="e2" />
      <feComposite in="e1" in2="e2" operator="xor"
                   result="outline"/>
      <feColorMatrix type="matrix" in="outline"
                     values="1 0 0 0 0
                             0 1 0 0 0
                             0 0 1 0 0
                             0 0 0 .3 0" result="outline2"/>
      <feComposite in="outline2" in2="SourceGraphic"
                   operator="over" result="output"/>
    </filter>
  </defs>
  <g id="group" filter="url(#groupborder)">
    <circle cx="125" cy="125" r="65" fill="orange" />
    <line x1="50" y1="50" x2="200" y2="200" stroke="blue" stroke-width="4" />
  </g>
</svg>

Here's how it works:

<feMorphology operator="dilate" in="SourceAlpha" radius="8" result="e1" />

Uses a dilate operation to fatten up the graphic elements. By using the source alpha as the input image, this results in black regions corresponding to the graphic elements in the image, and white everywhere else.

<feMorphology operator="dilate" in="SourceAlpha" radius="10" result="e2" />

The same filter again, but with a larger amount of dilation, resulting in a slightly fatter image

<feComposite in="e1" in2="e2" operator="xor" result="outline"/>

These dilated results are combined using an XOR operation that leaves behind a black outline.

<feColorMatrix type="matrix" in="outline"
values="1 0 0 0 0
        0 1 0 0 0
        0 0 1 0 0
        0 0 0 .3 0" result="outline2"/>

This filter multiplies the alpha component of the outline by 0.3 so it appears grey instead of solid black.

<feComposite in="outline2" in2="SourceGraphic" operator="over" result="output"/>

Finally, add this outline to the original image.

like image 71
r3mainer Avatar answered Oct 03 '22 13:10

r3mainer