s.kacer
s.kacer

Reputation: 101

How to add shadow to SVG <path>?

I would like to create a simple shadow effect for some paths in SVG generated from a library. I have effectively used <feDropShadow> to add a shadow to other SVG elements like <rect>, but applying the same to a <path> either seems to make it disappear or has no effect.

For reference, here is the simple filter I am using:

<filter id="${id}">
  <feDropShadow dx="0" dy="0"
  flood-color="${color}" />
</filter>

I then select the relevent SVG element and append this to its style attribute: filter: url(#filter-id).

As mentioned previously, this works fine when applied to a <rect>, but not to a <path>. Also just for reference, what I am trying to achieve is to make a specific part of the SVG graphic "glow" to signify it being selected. I'l also mention that my target browser is google chrome, since browsers seem to vary quite a bit in their implementation of the SVG spec.

If someone can help me figure out how to achieve the desired effect for I would greatly appreciate it!

Edit: I realize it would probably help if I included the SVG in question, since the most useful answer I've gotten doesn't seem to work for it. I wish I could provide a more minimal example, but this is about the most minimal I can manage. To provide context for it,all of the SVG is generated in the page dynamically using the mermaid-js library, except the two filters I append to the inner HTML, which should be used to "highlight" relevant parts of the svg as events are triggered on the web page. I apply these filters to the relevant elements by appending filter: url(#filter-id) to its style attribute. This does work for when I apply it to a that contains a , but doesn't when I apply it to a that contains a or if I apply it directly to the in question.

In the snippet, one of the nodes in the graph is highlighted successfully, represented by the with id "flowchart-a-14". The filter is also applied to the arrow going between the alpha and bravo node, which is represented by the with id "L-a-b", which instead of being highlighted, disappears.

Note 1: the behavior is using google chrome, which is the target browser. note 2: can't seem to include a runnable snippet. The button for bringing up the snippet editor doesn't appear for me.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mermaid-access-0" width="100%" height="50.720001220703125" style="max-width: 350.6000061035156px;" viewBox="0 0 350.6000061035156 50.720001220703125">
  <style>#mermaid-access-0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-access-0 .error-icon{fill:#552222;}#mermaid-access-0 .error-text{fill:#552222;stroke:#552222;}#mermaid-access-0 .edge-thickness-normal{stroke-width:2px;}#mermaid-access-0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-access-0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-access-0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-access-0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-access-0 .marker{fill:#333333;}#mermaid-access-0 .marker.cross{stroke:#333333;}#mermaid-access-0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-access-0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-access-0 .label text{fill:#333;}#mermaid-access-0 .node rect,#mermaid-access-0 .node circle,#mermaid-access-0 .node ellipse,#mermaid-access-0 .node polygon,#mermaid-access-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-access-0 .node .label{text-align:center;}#mermaid-access-0 .node.clickable{cursor:pointer;}#mermaid-access-0 .arrowheadPath{fill:#333333;}#mermaid-access-0 .edgePath .path{stroke:#333333;stroke-width:1.5px;}#mermaid-access-0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-access-0 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-access-0 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-access-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-access-0 .cluster text{fill:#333;}#mermaid-access-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80,100%,96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-access-0:root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-access-0 flowchart{fill:apa;}</style>
  <g>
    <g class="output">
      <g class="clusters"/>
      <g class="edgePaths">
        <g class="edgePath LS-a LE-b" id="L-a-b" style="opacity: 1;filter:url(#mermaid-access-highlight-secondary);">
          <path class="path" d="M59.349998474121094,25.360000610351562L102.30999946594238,25.360000610351562L145.27000045776367,25.360000610351562" marker-end="url(#arrowhead14)" style="fill:none"/>
          <defs>
            <marker id="arrowhead14" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
              <path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/>
            </marker>
          </defs>
        </g>
        <g class="edgePath LS-b LE-c" id="L-b-c" style="opacity: 1;">
          <path class="path" d="M197.2400016784668,25.360000610351562L240.2000026702881,25.360000610351562L283.1600036621094,25.360000610351562" marker-end="url(#arrowhead15)" style="fill:none"/>
          <defs>
            <marker id="arrowhead15" viewBox="0 0 10 10" refX="9" refY="5" markerUnits="strokeWidth" markerWidth="8" markerHeight="6" orient="auto">
              <path d="M 0 0 L 10 5 L 0 10 z" class="arrowheadPath" style="stroke-width: 1; stroke-dasharray: 1, 0;"/>
            </marker>
          </defs>
        </g>
      </g>
      <g class="edgeLabels">
        <g class="edgeLabel" transform="translate(102.30999946594238,25.360000610351562)" style="opacity: 1;">
          <g transform="translate(-17.96000099182129,-7.360000133514404)" class="label">
            <rect rx="0" ry="0" width="35.92000198364258" height="14.720000267028809"/>
            <foreignObject width="44.900001525878906" height="18.399999618530273">
              <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">
                <span id="L-L-a-b" class="edgeLabel L-LS-a' L-LE-b">Step 1</span>
              </div>
            </foreignObject>
          </g>
        </g>
        <g class="edgeLabel" transform="translate(240.2000026702881,25.360000610351562)" style="opacity: 1;">
          <g transform="translate(-17.96000099182129,-7.360000133514404)" class="label">
            <rect rx="0" ry="0" width="35.92000198364258" height="14.720000267028809"/>
            <foreignObject width="44.900001525878906" height="18.399999618530273">
              <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">
                <span id="L-L-b-c" class="edgeLabel L-LS-b' L-LE-c">Step 2</span>
              </div>
            </foreignObject>
          </g>
        </g>
      </g>
      <g class="nodes">
        <g class="node default" id="flowchart-a-14" transform="translate(33.67499923706055,25.360000610351562)" style="opacity: 1;filter:url(#mermaid-access-highlight-primary);">
          <rect rx="0" ry="0" x="-25.675000190734863" y="-17.360000133514404" width="51.35000038146973" height="34.72000026702881" class="label-container"/>
          <g class="label" transform="translate(0,0)">
            <g transform="translate(-15.675000190734863,-7.360000133514404)">
              <foreignObject width="39.1875" height="18.399999618530273">
                <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">alpha</div>
              </foreignObject>
            </g>
          </g>
        </g>
        <g class="node default" id="flowchart-b-15" transform="translate(171.25500106811523,25.360000610351562)" style="opacity: 1;">
          <rect rx="0" ry="0" x="-25.985000610351562" y="-17.360000133514404" width="51.970001220703125" height="34.72000026702881" class="label-container"/>
          <g class="label" transform="translate(0,0)">
            <g transform="translate(-15.985000610351562,-7.360000133514404)">
              <foreignObject width="39.962501525878906" height="18.399999618530273">
                <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">bravo</div>
              </foreignObject>
            </g>
          </g>
        </g>
        <g class="node default" id="flowchart-c-16" transform="translate(312.88000106811523,25.360000610351562)" style="opacity: 1;">
          <rect rx="0" ry="0" x="-29.719999313354492" y="-17.360000133514404" width="59.439998626708984" height="34.72000026702881" class="label-container"/>
          <g class="label" transform="translate(0,0)">
            <g transform="translate(-19.719999313354492,-7.360000133514404)">
              <foreignObject width="49.29999923706055" height="18.399999618530273">
                <div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; white-space: nowrap;">charlie</div>
              </foreignObject>
            </g>
          </g>
        </g>
      </g>
    </g>
  </g>
  <filter id="mermaid-access-highlight-primary">
    <feDropShadow dx="0" dy="0" flood-color="red"/>
  </filter>
  <filter id="mermaid-access-highlight-secondary">
    <feDropShadow dx="0" dy="0" flood-color="cyan"/>
  </filter>
</svg>

Upvotes: 1

Views: 3100

Answers (3)

This is the code from Alexander_TT his great answer.

I just wrapped it in a Custom Element (supported in all modern browsers) because it is a great example where SVG and Custom Elements are a good mix.

<svg-navigator colors="gold,goldenrod">
  <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 110 110'>
    <defs><filter id='drop-shadow' x='-20%' y='-20%' height='130%' width='130%'>
        <feGaussianBlur in='SourceAlpha' stdDeviation='2' />
        <feOffset dx='1' dy='0' result='offsetblur' />
        <feMerge><feMergeNode /><feMergeNode in='SourceGraphic' /></feMerge>
      </filter></defs>
    <g><!-- The <svg-navigator> Custom Element replaces all these A tags -->
      <a href="">All questions</a>
      <a href="/tagged/javascript">All JavaScript questions</a>
      <a href="/tagged/css">All CSS questions</a>
      <a href="/tagged/javascript">All SVG questions</a>
      <a href="/tagged/web+components">All Web Components questions</a>
      <a href="/tagged/custom+elements">All Custom Elements questions</a>
      <a href="/tagged/javascript+template">All Template questions</a>
      <a href="/tagged/shadowDOM">All shadowDOM questions</a>
    </g>
    <circle id='center' fill='#696969' stroke='white' stroke-width='3' cx='55' cy='55' r='17' />
  </svg>
</svg-navigator>
<script>
  customElements.define("svg-navigator", class extends HTMLElement {
    connectedCallback() {
      let colors = this.getAttribute("colors").split `,`;
      let pointers = ["<circle cx='90' cy='70' r='6' fill='white'/>",
                      "<polyline points='90,60 95,70 85,75' fill='white'/>"];
      setTimeout(() => // make sure DOM can be read
        this.querySelector('G')
          .innerHTML = [...this.querySelectorAll("A")].map((node, idx) =>
            `<g transform='rotate(${idx*45-22.5} 55 55)'>` +
            `<a href='https://stackoverflow.com/questions${node.href}''><title>${node.innerHTML}</title>` +
            `<path fill='${colors[idx%2]}' id='s${idx+1}' d='M 55 55 L 105 55 A 50 50 0 0 1 90.5 90.5z'/>` +
            `</a>${pointers[idx % 2]}</g>` // return segment
          ).join ``)}})

</script>

<style>
  svg {
    height: 200px;
    width: 200px;
    --d: dodgerblue;
    --r: red;
    --g: yellowgreen;
  }
  svg path,
  #center {
    cursor: pointer;
    transition: all 0.8s ease;
  }
  #center:hover {
    fill: var(--g);
    filter: url(#drop-shadow);
  }
  #s1:hover,
  #s3:hover,
  #s5:hover,
  #s7:hover {
    fill: var(--d);
    filter: url(#drop-shadow);
  }

  #s2:hover,
  #s4:hover,
  #s6:hover,
  #s8:hover {
    fill: var(--r);
    filter: url(#drop-shadow);
  }

</style>

Upvotes: 2

Alexandr_TT
Alexandr_TT

Reputation: 14545

As the OP comments:

for my use case it is necessary to dynamically highlight different parts of the SVG as the user interacts with the application

Maybe so?

When you hover over different parts of the application, they are highlighted and a shadow is added.

In addition, hints have been added that appear when hovering over different parts of the SVG.

<a xlink:href="https://stackoverflow.com/questions/tagged/javascript"> 
        <title> All javascript questions </title>
      <path id="s2"  d="M 55 55 L 90.35 90.35 A 50 50 0 0 1 55 105 Z"/>
     </a> 

Added working links on which there is a transition to various sections of stackoverflow.

Please read the comments to help you understand the main points of the solution.

svg {
  height: 330px;
  width: 330px;
  --d:dodgerblue;
  --r:red;
  --g:yellowgreen;
}

#spot {
  fill:white;
  pointer-events:none;
  }
 #arrow {
 fill:none;
 stroke:white;
 stroke-width:2;
 pointer-events:none;
 } 

#center {
fill:#797979;
stroke:#FFFFFF;
stroke-width:3;
cursor: pointer; 
-webkit-transition: all 0.8s ease;
  transition: all 0.8s ease;

} 
#center:hover {
fill: var(--g);
filter:url(#drop-shadow);
}

#s1,#s3, #s5, #s7 {
fill:#3A3A3A;
cursor: pointer; 
 -webkit-transition: all 0.8s ease;
  transition: all 0.8s ease;
}

#s2,#s4,#s6,#s8 {
fill:#797979;
cursor: pointer; 
-webkit-transition: all 0.8s ease;
  transition: all 0.8s ease;
}


#s1:hover, #s3:hover, #s5:hover, #s7:hover  {
 fill: var(--d);
 filter:url(#drop-shadow);
}
#s2:hover, #s4:hover, #s6:hover, #s8:hover  {
 fill: var(--r);
 filter:url(#drop-shadow);
}
<svg xmlns="http://www.w3.org/2000/svg" 
    xmlns:xlink="http://www.w3.org/1999/xlink" viewBox='0 0 110 110'> 
    <defs>  
     <!-- Hover Drop Shadow Filter -->
<filter id="drop-shadow" x="-20%" y="-20%" height="130%" width="130%">
      <feGaussianBlur in="SourceAlpha" stdDeviation="2"/> 
      <feOffset dx="1" dy="0" result="offsetblur"/> 
      <feMerge> 
        <feMergeNode/>
        <feMergeNode in="SourceGraphic"/> 
      </feMerge>
    </filter>
</defs> 
  <!-- Circle segments with work links Click -->
<g transform="rotate(-22.5 55 55)" >
<a xlink:href="https://stackoverflow.com/questions"> 
    <title> All questions </title>
  <path id="s1"  d="M 55 55 L 105 55 A 50 50 0 0 1 90.35 90.35 Z"/>
</a>
    <a xlink:href="https://stackoverflow.com/questions/tagged/javascript"> 
        <title> All javascript questions </title>
      <path id="s2"  d="M 55 55 L 90.35 90.35 A 50 50 0 0 1 55 105 Z"/>
     </a> 
    
<a xlink:href="https://stackoverflow.com/questions/tagged/svg">
    <title> All SVG Questions </title>
<path id="s3"  d="M 55 55 L 55 105 A 50 50 0 0 1 19.6447 90.35 Z" />
</a>
    <a xlink:href="https://stackoverflow.com/questions/tagged/css"> 
       <title> All CSS Questions </title>
    <path id="s4"  d="M 55 55 L 19.64 90.353 A 50 50 0 0 1 5 55 Z" />
    </a>
<a xlink:href="https://stackoverflow.com/questions/tagged/java"> 
     <title> All java questions</title>
<path id="s5"  d="M 55 55 L 5 55 A 50 50 0 0 1 19.64 19.64 Z" />
</a> 
    <a xlink:href="https://stackoverflow.com/questions/tagged/python">
       <title> All python questions </title>
    <path id="s6"  d="M 55 55 L 19.64 19.64 A 50 50 0 0 1 55 5 Z" />
    </a> 
<a xlink:href="https://stackoverflow.com/help"> 
     <title> Reference section </title> 
<path id="s7"  d="M 55 55 L 55 5 A 50 50 0 0 1 90.35 19.64 Z" />
</a>
    <a xlink:href="https://stackoverflow.com/questions/tagged/php"> 
        <title> All php questions  </title>
    <path id="s8"  d="M 55 55 L 90.35 19.64 A 50 50 0 0 1 105 55 Z" />
    </a>
</g>  
      <a xlink:href="https://stackoverflow.com/questions/tagged/html"> 
        <title> All HTML questions </title> 
     
  <circle id="center" cx='55' cy='55' r='17'  /> 
  </a>
      <!-- White circles -->
    <circle id="spot" cx='31' cy='31' r='6'   />  
     <use xlink:href="#spot" transform="rotate(90 55 55)" /> 
         <use xlink:href="#spot" transform="rotate(-90 55 55)" />
          <use xlink:href="#spot" transform="rotate(180 55 55)" />
  <!--White arrows --> 
    <polyline id="arrow" points = "46,21 55,12 64,21" fill="none" stroke="white" />   
       <use xlink:href="#arrow" transform="rotate(90 55 55)" /> 
         <use xlink:href="#arrow" transform="rotate(-90 55 55)" />
          <use xlink:href="#arrow" transform="rotate(180 55 55)" />
      
</svg>

Upvotes: 4

Use regular CSS

https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/drop-shadow()

But it is applied to all elements inside the SVG, you can't target just one SVG element.

<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'>
  <path d='M7 15h2v-2h-2v2zm1-14a4 4 90 00-4 4h2c0-1 1-2 2-2s2 1 2 2c0 2-3 2-3 6h2c0-3 3-3 3-6a4 4 90 00-4-4z'/>
</svg>

<style>
  svg {
    width: 200px;
    filter: drop-shadow(0 0 20px red);
  }
</style>

Upvotes: 1

Related Questions