Home > Back-end >  SVG Shape Lighting
SVG Shape Lighting

Time:07-13

Summary: I'm trying to create a canvas of randomized rock climbing holds using vector graphics generated with properties such as color, rotation, size and path values. To add depth to these I'm trying to add a sort of randomized shadow to them to show that one or more sides of the shape are raised from the background.

Question: I've been able to apply this filter onto the svg however as you can see on the below image "Light Filter" I get this white effect bleeding out to the edge of the svg element. I'd like to find a way to keep that raised effect and have the color show or find a new way to show shadow randomized to each edge of the svg path?

You can find the filter code in the function: addFilter

You can disable the filter effect by commenting out the function addFilter(); and applyFilter();

No Filter:

enter image description here

Light Filter:

enter image description here

      //create a filter for the svg copying the rough paper filter and apply it to the svg
      var filter = document.createElementNS("http://www.w3.org/2000/svg", "filter");
      filter.setAttribute("id", "roughpaper");
      filter.setAttribute("x", "0%");
      filter.setAttribute("y", "0%");
      filter.setAttribute("width", "100%");
      filter.setAttribute("height", "100%");
      var feDiffuseLighting = document.createElementNS("http://www.w3.org/2000/svg", "feDiffuseLighting");
      feDiffuseLighting.setAttribute("in", "noise");
      feDiffuseLighting.setAttribute("lighting-color", "#ffffff");
      feDiffuseLighting.setAttribute("surfaceScale", "2");
      var feDistantLight = document.createElementNS("http://www.w3.org/2000/svg", "feDistantLight");
      feDistantLight.setAttribute("azimuth", "45");
      feDistantLight.setAttribute("elevation", "60");
      feDiffuseLighting.appendChild(feDistantLight);
      filter.appendChild(feDiffuseLighting);
      document.getElementById("svg-0").appendChild(filter);
body {
      background-color: #333;
      overflow: hidden;
    }
    #svg-container {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
    }
    .svg-element {
      position: absolute;
      width: 150px;
      height: 150px;
    }
<div id="svg-container">
      <svg
        viewBox="0 0 200 200"
        preserveAspectRatio="none"
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        version="1.1"
        
        id="svg-0"
        filter="url(#roughpaper)"
      >
        <path
          d="M27.8,-30.1C31.8,-29.8,27.8,-17,30.3,-5C32.9,7,42,18.2,38.3,19.7C34.5,21.1,18,12.7,4.6,21.4C-8.9,30.1,-19.3,55.9,-25.4,58.5C-31.5,61.2,-33.3,40.7,-44.1,24.4C-54.8,8,-74.4,-4.3,-75.5,-15.9C-76.6,-27.6,-59.1,-38.6,-43.4,-36.8C-27.7,-34.9,-13.9,-20.3,-1,-19.1C11.9,-17.9,23.9,-30.3,27.8,-30.1Z"
          transform="translate(100, 100)"
          
          id="path-0"
          style="fill: rgb(106, 76, 147)"
        ></path>
        
      </svg>
    </div>

CodePudding user response:

Diffuse light effects should be multiplied with the original, otherwise you'll see the the lighting color rather than the combination of original color lighting. So just add a feBlend with a multiply - like so. Update: and then add a feComposite/in to "clip to self" - so you don't see the background lit with the light as well.

//create an array with multiple svg paths
var svgPaths = [
  {
    path: "M27.8,-30.1C31.8,-29.8,27.8,-17,30.3,-5C32.9,7,42,18.2,38.3,19.7C34.5,21.1,18,12.7,4.6,21.4C-8.9,30.1,-19.3,55.9,-25.4,58.5C-31.5,61.2,-33.3,40.7,-44.1,24.4C-54.8,8,-74.4,-4.3,-75.5,-15.9C-76.6,-27.6,-59.1,-38.6,-43.4,-36.8C-27.7,-34.9,-13.9,-20.3,-1,-19.1C11.9,-17.9,23.9,-30.3,27.8,-30.1Z",
  },
  {
    path: "M36.5,-45.3C49.8,-32.4,64.8,-23.2,69,-10.5C73.3,2.2,66.7,18.5,58.3,34.1C49.8,49.8,39.4,64.8,23.8,74.4C8.1,84,-12.7,88.2,-22.9,77.9C-33,67.7,-32.3,43,-35.4,26.1C-38.5,9.1,-45.3,0,-46.2,-10.5C-47.2,-21,-42.3,-32.7,-33.6,-46.4C-24.9,-60.1,-12.5,-75.7,-0.4,-75.2C11.6,-74.7,23.2,-58.1,36.5,-45.3Z",
  }
];
var colors = ["#FF595E", "#FFCA3A", "#8AC926", "#1982C4", "#6A4C93"];





//create a function to apply properties to each svg element
function holdProps() {
  //based on the id of the svg element, re-position the svg element on the screen
  var svgElements = document.getElementsByClassName("svg-element");
  //set the position of the svg element to the top left
  for (var i = 0; i < svgElements.length; i  ) {
    svgElements[i].style.position = "absolute";
    svgElements[i].style.top = "0";
    svgElements[i].style.left = "0";
  }
  //console log the bounding box of each svg element
  for (var i = 0; i < svgElements.length; i  ) {
    var svg = svgElements[i];
    console.log(svg.getBoundingClientRect());
  }
}

//create a function to apply properties to each svg elements path value
function holdPaths() {
  //create a path and append it to each svg element
  $(".svg-element").each(function () {
    var path = document.createElementNS("http://www.w3.org/2000/svg", "path");

    //set attributes to the above created path
    path.setAttribute(
      "d",
      svgPaths[Math.floor(Math.random() * svgPaths.length)].path
    );
    path.setAttribute("transform", "translate(100, 100)");
    path.setAttribute("class", "path");
    path.setAttribute("id", "path-"   $(this).attr("id").split("svg-")[1]);
    this.appendChild(path);
  });

  //If a path id is clicked change the path to a random path with a random color
  $(".svg-element").click(function () {
    var path = svgPaths[Math.floor(Math.random() * svgPaths.length)].path;
    var color = colors[Math.floor(Math.random() * colors.length)];
    $(this).find("path").attr("d", path);
    $(this).find("path").css("fill", color);
  });
}

//create a function to apply random colors to each svg element
function colorHold() {
  $(".svg-element path").each(function () {
    var color = colors[Math.floor(Math.random() * colors.length)];
    $(this).css("fill", color);
    //stroke white width 5 if the svg is hoverd over
    $(this).hover(function () {
      $(this).css("stroke", "white");
      $(this).css("stroke-width", "5");
    }
    //reset stroke to black and stroke width to 1 if the svg is not hovered over
    , function () {
      $(this).css("stroke", "black");
      $(this).css("stroke-width", "0");
    }
    );
  });
}

//create feDistantLight and a fePointLight to each svg element
function addFilter() {
  var filter = document.createElementNS("http://www.w3.org/2000/svg", "filter");
    filter.setAttribute("id", "roughpaper");
    filter.setAttribute("x", "0%");
    filter.setAttribute("y", "0%");
    filter.setAttribute("width", "100%");
    filter.setAttribute("height", "100%");


var feGauss= document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur");
    feGauss.setAttribute("stdDeviation", "4");
    feGauss.setAttribute("result", "blur");
    filter.appendChild(feGauss);

  var feDiffuseLighting = document.createElementNS("http://www.w3.org/2000/svg", "feDiffuseLighting");
    feDiffuseLighting.setAttribute("in", "blur");
    feDiffuseLighting.setAttribute("lighting-color", "#ffffff");
    feDiffuseLighting.setAttribute("surfaceScale", "6");

  var feDistantLight = document.createElementNS("http://www.w3.org/2000/svg", "feDistantLight");
    feDistantLight.setAttribute("azimuth", "45");
    feDistantLight.setAttribute("elevation", "50");
  feDiffuseLighting.appendChild(feDistantLight);
  filter.appendChild(feDiffuseLighting);


var feBlend= document.createElementNS("http://www.w3.org/2000/svg", "feBlend");
    feBlend.setAttribute("mode", "multiply");
    feBlend.setAttribute("in2", "SourceGraphic");
    filter.appendChild(feBlend);

var feComp= document.createElementNS("http://www.w3.org/2000/svg", "feComposite");
    feComp.setAttribute("operator", "in");
    feComp.setAttribute("in2", "SourceGraphic");
    filter.appendChild(feComp);

  document.getElementsByTagName("svg")[0].appendChild(filter);
} 
//apply the filter to each svg element
function applyFilter() {
  var svgElements = document.getElementsByClassName("svg-element");
  for (var i = 0; i < svgElements.length; i  ) {
    svgElements[i].setAttribute("filter", "url(#roughpaper)");
  }
}

//on load run the functions
$(document).ready(function () {
  //create a path for each svg element
  holdPaths();
  //apply properties to each svg element
  holdProps();
  //apply random colors to each svg element
  colorHold();

  //Disable these two to remove the filter
  //create a filter to each svg element
  addFilter();
  //apply the filter to each svg element
  applyFilter();
});
body {
  background-color: #333;
  overflow: hidden;
}
#svg-container {
  /* full size of page*/
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  
}
.svg-element {
  position: absolute;
  
}
svg path {
  transition: 0.2s;
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj 3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<div id="svg-container">
  <!-- Create SVG -->
  <svg id="svg-01"  width="100%" height="100%" viewBox="0 0 200 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">

  </svg>
</div>

  • Related