Dynamically add SVG gradient

I have this SVG container with paths. I want to edit it, so filling the paths will be a template. This is my unsuccessful attempt:

I add a gradient:

$('svg defs').prepend('<linearGradient id="MyGradient"><stop offset="5%" stop-color="#F60" /><stop offset="95%" stop-color="#FF6" /></linearGradient>'); 

And then change the padding of the paths:

 $(base + ' svg path').each(function() { this.setAttribute('fill','url(#MyGradient)') } 

This does not work. What am I missing?

+8
javascript jquery svg
source share
4 answers

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 the source code in a string for SVG elements.

The simplest (without plugins) method is to stop relying on jQuery so much and just use simple DOM methods to create elements. Yes, this is more verbose than just using jQuery to magically create your elements for you ... but jQuery doesn't 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); } 

Library usage

Alternatively, you can include Keith Woods jQuery SVG plugin , which has many convenient methods for common SVG operations, including the ability to create linear gradients .

+19
source share

I think you will need to use the SVG plugin for jQuery (found here ). When adding SVG elements using the "normal" jQuery library, namespaces are likely to mix.

Try the following:

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

(Not quite sure, however. You might have to play around with this code a bit.)

EDIT

Just created a fiddle to check the thesis (as @Phrogz suggested). In fact, it returns http://www.w3.org/1999/xhtml as the namespace for the inserted <linearGradient> , which is the wrong namespace and thus confirms my previous assumptions.

+3
source share

Found a solution. This is a little ugly, but does not require the use of additional plugins.

Apparently, the template should be included in the tag when the SVG is first created (perhaps it is only readable).

Thus, replacing the contents of the SVG tag wrapper with the jobs themselves ( base is that shell):

 $(base).html($(base).html()) 
+3
source share

I just want to go in and say that I have found a more elegant solution that allows you to use jQuery with SVG elements, but without the jQuery SVG library (which is no longer updated and has some problems with jQuery 1.8 or higher). Just use this function:

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

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

Then you can use the function as follows:

 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 is not as compact as you can be, because you need to create each element manually, but it is much better than manipulating everything with DOM methods.

A small note. The jQuery.attr () function assumes that all attributes have a lower value, which does not apply to SVG elements (for example, the viewBox attribute in <svg> tags). To get around this, when setting up the uppercase attributes, use something like this:

 $("svg")[0].setAttribute("viewBox", "0 0 1000 1000"); 
+3
source share

All Articles