I recently notice that if you create element like a circle in SVG (inline SVG embedded into HTML), using inspector/firebug or jQuery, your circle is not visible on SVG until you refresh the SVG, I found a hack to force refresh of the SVG, I just get text of the SVG and insert it again into the DOM, and all elements that were not visible like circle mention before will be rendered.
Here is referesh function, as jQuery plugin
$.fn.xml = function() { return (new XMLSerializer()).serializeToString(this[0]); }; $.fn.DOMRefresh = function() { return $($(this.xml()).replaceAll(this)); };
Those plugins should work with every XML embeded into HTML not only SVG. Don’t look very nice but it work, but I found a better way fix jQuery to work with SVG. I found that when I use function document.createElementNS
instead of document.createElement
elements added to inline SVG using for instance appendChild
function everything work fine. So only thing that need to be done for jQuery to work with inline SVG is to replace this function if element is SVG. First I wrote method in jQuery object that test if element is SVG element, there are only three elements that have the same name in HTML and SVG is a
, script
, style
and title
tags so I didn’t put them in.
isSVGElement: function( o ) { if (o instanceof SVGElement) { return true; } else { if (typeof o === 'string') { return $.inArray(o, ['altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'set', 'stop', 'svg', 'switch', 'symbol', 'text', 'textPath', 'tref', 'tspan', 'use', 'view', 'vkern']) !== -1; } } }
I get the list of elements from Mozilla MDN.
I added this method to main jQuery.extend({
that add methods to jQuery object. Next thing is to replace createElement
with createElementNS
, there are only 2 places with this in parseHTML (in the same jQuery.extend
) and createSafeFragment
function, only one is responsible for inserting elements – parseHTML. Below is the code for that function.
parseHTML: function( data, context, keepScripts ) { if ( !data || typeof data !== "string" ) { return null; } if ( typeof context === "boolean" ) { keepScripts = context; context = false; } context = context || document; var parsed = rsingleTag.exec( data ), scripts = !keepScripts && []; // Single tag if ( parsed ) { if ( jQuery.isSVGElement( parsed[1] ) ) { return [ context.createElementNS( "http://www.w3.org/2000/svg", parsed[1]) ]; } else { return [ context.createElement( parsed[1] ) ]; } } parsed = jQuery.buildFragment( [ data ], context, scripts ); if ( scripts ) { jQuery( scripts ).remove(); } return jQuery.merge( [], parsed.childNodes ); },
Unfortunetnly not all manupulation methods that create new elements will work but it’s better then refresh hack. The stuff that don’t work is when you create more then one element from a string or if you put some attributes. In this case jQuery use document fragments and innerHTML to create the DOM. If we will want to fix that too we will need to write a parser that will call createElementNS
.
You can also include those function after you load jQuery so original code will not be changed.
The other way is to use document.createElementNS
and element.setAttributeNS
that need to be used if you want to add xlink:href
attribute (it use http://www.w3.org/1999/xlink
namespace).