javascript 动态添加 SVG 渐变
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10894377/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dynamically adding a SVG gradient
提问by Miki
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:
我有这个带路径的 SVG 容器。我想编辑它,所以路径的填充将是一个模式。这是我失败的尝试:
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 paths' fill:
然后更改路径的填充:
$(base + ' svg path').each(function() {
this.setAttribute('fill','url(#MyGradient)')
}
This doesn't work. What am I missing?
这不起作用。我错过了什么?
回答by Phrogz
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.
您的问题(您“遗漏”了什么)是 jQuery 在 XHTML 命名空间中创建新元素,而 SVG 元素必须在 SVG 命名空间中创建。您不能在 SVG 元素的字符串中使用原始代码。
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.
最简单(无插件)的方法是停止如此依赖 jQuery,而只使用简单的 DOM 方法来创建元素。是的,它比仅使用 jQuery 为您神奇地构建元素更冗长……但 jQuery 在这种情况下不起作用。
Demo: http://jsfiddle.net/nra29/2/
演示: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" pluginthat has a lot of convenience methods for common SVG operations, including the ability to create linear gradients.
或者,您可以包含Keith Woods 的“jQuery SVG”插件,该插件具有许多用于常见 SVG 操作的便捷方法,包括创建线性渐变的能力。
回答by Sirko
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.
我认为您必须使用 jQuery 的 SVG 插件(可在此处找到)。使用“普通”jQuery 库添加 SVG 元素时,命名空间可能会混淆。
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 fiddlein 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.
刚刚创建了这个小提琴以测试论文(如@Phrogz 所建议)。事实上,它http://www.w3.org/1999/xhtml
作为插入的命名空间返回<linearGradient>
,这是错误的命名空间,因此验证了我的上述推测。
回答by Miki
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).
显然,当首次创建 SVG 时,必须在标签中包含一个模式(它可能只在那时被读取)。
Thus, replacing the SVG tag's wrapper's contents with themselves works (base
being that wrapper):
因此,用它们自己替换 SVG 标签的包装器的内容(base
作为那个包装器):
$(base).html($(base).html())
回答by Hoffmann
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:
我只是想顺便说一下,我找到了一个更优雅的解决方案,它允许您继续将 jQuery 与 SVG 元素一起使用,但没有 jQuery SVG 库(不再更新,并且在 jQuery 1.8 或更高版本中存在一些问题)。只需使用这样的函数:
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:
它在 SVG 命名空间上创建一个 SVG 元素并用 jQuery 封装它,一旦在正确的命名空间中创建元素,您就可以在 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.
它不像您希望的那样紧凑,因为您必须手动创建每个元素,但它比使用 DOM 方法操作所有内容要好得多。
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:
一个小提示,jQuery .attr() 函数假定所有属性都是小写的,而 SVG 元素则不是这种情况(例如标签中的viewBox
属性<svg>
)。为了解决这个问题,当使用大写字母设置属性时,请使用以下内容:
$("svg")[0].setAttribute("viewBox", "0 0 1000 1000");