9

我有这个带路径的 SVG 容器。我想编辑它,所以路径的填充将是一个模式。这是我失败的尝试:

我添加了一个渐变:

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

然后更改路径的填充:

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

这行不通。我错过了什么?

4

4 回答 4

24

您的问题(您“缺少”)是 jQuery 在 XHTML 命名空间中创建新元素,而 SVG 元素必须在 SVG 命名空间中创建。您不能在 SVG 元素的字符串中使用原始代码。

最简单(无插件)的方法是停止过度依赖 jQuery,而只使用简单的 DOM 方法来创建元素。是的,它比仅仅使用 jQuery 为你神奇地构造你的元素更冗长......但是 jQuery 在这种情况下不起作用。

演示: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);
}

使用库

或者,您可以包含Keith Woods 的“jQuery SVG”插件,该插件具有许多用于常见 SVG 操作的便捷方法,包括创建线性渐变的能力。

于 2012-06-05T13:32:40.640 回答
3

我认为您必须使用 jQuery 的 SVG 插件(在此处找到)。使用“普通”jQuery 库添加 SVG 元素时,命名空间可能会混淆。

尝试以下操作:

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

(不过,不完全确定。您可能需要稍微修改一下该代码。)

编辑

刚刚创建了这个小提琴来测试论文(正如@Phrogz 所建议的那样)。实际上,它http://www.w3.org/1999/xhtml作为插入的命名空间返回<linearGradient>,这是错误的命名空间,因此验证了我的上述推测。

于 2012-06-05T09:11:47.477 回答
3

找到了解决方案。它有点难看,但不需要使用额外的插件。

显然,在第一次创建 SVG 时,必须在标签中包含一个模式(它可能只是在那时才读取)。

因此,用它们自己替换 SVG 标签的包装器的内容是可行的(base作为那个包装器):

$(base).html($(base).html())
于 2012-06-05T09:25:20.917 回答
3

我只是想顺便说一下,我找到了一个更优雅的解决方案,它允许您继续使用带有 SVG 元素的 jQuery,但没有 jQuery SVG 库(不再更新,并且在 jQuery 1.8 或更高版本中存在一些问题)。只需使用这样的函数:

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

它在 SVG 命名空间上创建一个 SVG 元素并用 jQuery 封装它,一旦在正确的命名空间中创建了元素,您就可以在 jQuery 中自由使用它:

然后,您可以通过以下方式使用该功能:

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);

它不像您希望的那样紧凑,因为您必须手动创建每个元素,但它比使用 DOM 方法操作所有内容要好得多。

一个小提示,jQuery .attr() 函数假定所有属性都是小写的,这不是 SVG 元素的情况(例如标签中的viewBox属性)。<svg>为了解决这个问题,当使用大写字母设置属性时,请使用以下内容:

$("svg")[0].setAttribute("viewBox", "0 0 1000 1000");
于 2013-02-06T13:48:37.267 回答