Search code examples
svgd3.jssvg-filters

d3.js - svg filter equivalent with d3.js


I got below svg filter from svg file:

   <defs>
      <filter height="300%" id="blurfilter" width="300%" x="-1" y="-1">
         <feGaussianBlur result="blurOut" stdDeviation="2.0" />
         <feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0" />
         <feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3" />
         <feBlend in="SourceGraphic" in2="blurOut3" mode="normal" />
      </filter>
   </defs>

What's the correct way to implement it with d3.js?

I try below code but it looks like not correct:

 svg.append('defs')
    .append('filter')
    .attr('width','300%')
    .attr('id','blurfilter')
    .attr('x',-1)
    .attr('y',-1)
    .append('feGaussianBlur')
    .attr('result','blurOut')
    .attr('stdDeviation',2.0)
    .append('feColorMatrix')
    .attr('id','blurOut')
    .attr('result','blurOut2')
    .attr('type','matrix')
    .attr('values','0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0')
    .append('feOffset')
    .attr('dx',4.0)
    .attr('dy',4.0)
    .attr('in','blurOut2')
    .attr('result','blurOut3')
    .append('feBlend')
    .attr('in','SourceGraphic')
    .attr('in2','blurOut3')
    .attr('mode','normal')

Solution

  • You need to break the chain, currently you are appending as follows:

     svg.append('defs')
        .append('filter')
        ...
        .append('feGaussianBlur')
        ...
        .append('feColorMatrix')
        ...
        .append('feOffset')
        ...
        .append('feBlend')
    

    Each time you use .append() you return a new selection of the append element(s). So you're appending a feBlend element to a parent feOffset element, not the filter itself. Eg:

       <defs>
          <filter height="300%" id="blurfilter" width="300%" x="-1" y="-1">
             <feGaussianBlur result="blurOut" stdDeviation="2.0">
                 <feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0" >
                     <feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3" >
                         <feBlend in="SourceGraphic" in2="blurOut3" mode="normal" />
                     </feOffset>
                  </feColorMatrix>
              </feGaussianBlur>
          </filter>
       </defs>
    

    Instead, break the chains and append to a selection of the filter:

    var filter = svg.append('defs')
      .append('filter')
      .attr(...
    
    filter.append('feGaussianBlur')
      .attr(...
    
    filter.append('feColorMatrix')
      .attr(...
    
    filter.append('feOffset')
       .attr(...
    
    filter.append('feBlend')
       .attr(...
    

    Which will give you a DOM structure the same as your example.