简体   繁体   中英

SVG Shape Lighting

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:

在此处输入图像描述

Light Filter:

在此处输入图像描述

 //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" class="svg-element" 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)" class="path" id="path-0" style="fill: rgb(106, 76, 147)" ></path> </svg> </div>

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 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); 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" class="svg-element" width="100%" height="100%" viewBox="0 0 200 200" preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg"> </svg> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM