Dynamically adding a SVG gradient

前端 未结 4 630
庸人自扰
庸人自扰 2020-12-10 05:38

I have this SVG container with paths. I want to edit it, so the paths\' fill will be a pattern. This is my failed attempt:

I add a gradient:

$(\'svg          


        
相关标签:
4条回答
  • 2020-12-10 05:55

    Your problem (what you are "missing") is that jQuery creates new elements in the XHTML namespace, while SVG elements must be created in the SVG namespace. You cannot use raw code in a string for SVG elements.

    The simplest (no-plugins) method is to stop leaning on jQuery so much and just use simple DOM methods to create the elements. Yes, it's more verbose than just using jQuery to magically construct your elements for you...but jQuery does not work in this case.

    Demo: http://jsfiddle.net/nra29/2/

    createGradient($('svg')[0],'MyGradient',[
      {offset:'5%', 'stop-color':'#f60'},
      {offset:'95%','stop-color':'#ff6'}
    ]);
    $('svg path').attr('fill','url(#MyGradient)');
    
    // svg:   the owning <svg> element
    // id:    an id="..." attribute for the gradient
    // stops: an array of objects with <stop> attributes
    function createGradient(svg,id,stops){
      var svgNS = svg.namespaceURI;
      var grad  = document.createElementNS(svgNS,'linearGradient');
      grad.setAttribute('id',id);
      for (var i=0;i<stops.length;i++){
        var attrs = stops[i];
        var stop = document.createElementNS(svgNS,'stop');
        for (var attr in attrs){
          if (attrs.hasOwnProperty(attr)) stop.setAttribute(attr,attrs[attr]);
        }
        grad.appendChild(stop);
      }
    
      var defs = svg.querySelector('defs') ||
          svg.insertBefore( document.createElementNS(svgNS,'defs'), svg.firstChild);
      return defs.appendChild(grad);
    }
    

    Using a Library

    Alternatively, you can include Keith Woods' "jQuery SVG" plugin that has a lot of convenience methods for common SVG operations, including the ability to create linear gradients.

    0 讨论(0)
  • 2020-12-10 05:59

    Found a solution. It's a bit ugly, but doesn't require the use of additional plugins.

    Apparently, a pattern has to be included in the tag when the SVG is first created (it's probably only read then).

    Thus, replacing the SVG tag's wrapper's contents with themselves works (base being that wrapper):

    $(base).html($(base).html())
    
    0 讨论(0)
  • 2020-12-10 06:13

    I just want to drop by and say I have found a more elegant solution that allows you to keep using jQuery with SVG elements but without the jQuery SVG library (which is no longer being updated and has some problems with jQuery 1.8 or higher). Simply use a function like this:

    createSVGElement= function(element) {
        return $(document.createElementNS('http://www.w3.org/2000/svg', element));
    }
    

    it creates a SVG element on the SVG namespace and encapsulates it with jQuery, once the element is created in the right namespace you can use it freely with jQuery:

    You can then use the function in this manner:

    var $myGradient= createSVGElement('linearGradient')
        .attr( {
            id:"MyGradient"
        });
    
    //if you dont need `defs`, skip this next line
    var $myDefs = createSVGElement('defs');
    
    createSVGElement('stop')
        .attr({
            offset: "5%",
            "stop-color": "#F60"
        })
        .appendTo($myGradient);
    
    
    createSVGElement('stop')
        .attr({
            offset:"95%",
            "stop-color":"#FF6"
        })
        .appendTo($myGradient);
    
    //Use this if you already have `defs`
    $('svg defs').prepend($myGradient);
    
    //Use this if you dont have `defs`
    $('svg').prepend($myDefs);
    $('svg defs').prepend($myGradient);
    

    It's not as compact as you might want it to be since you have to create each element by hand, but its a lot better than manipulating everything with DOM methods.

    A small note, jQuery .attr() function assumes all attributes are lowercased, which is not the case for SVG elements (for example the viewBox attribute in <svg> tags). To get around that, when setting attributes with uppercased letters use something like this:

    $("svg")[0].setAttribute("viewBox", "0 0 1000 1000");
    
    0 讨论(0)
  • 2020-12-10 06:19

    I think you'll have to use the SVG plugin for jQuery (found here). When adding SVG elements using the "normal" jQuery library, probably the namespaces get mixed up.

    Try the following:

    svg.linearGradient( $('svg defs'), 
                        'MyGradient', 
                        [ ['5%', '#F60'], ['95%', '#FF6']] );
    

    (Not exactly sure, however. You might need to fiddle around a bit with that code.)

    EDIT

    Just created this fiddle in order to test the thesis (as suggested by @Phrogz). Indeed it returns http://www.w3.org/1999/xhtml as the namespace for the inserted <linearGradient>, which is the wrong namespace and thus validates my above speculation.

    0 讨论(0)
提交回复
热议问题