SVG支持最新版本的angularjs和d3js

时间:2014-06-25 12:06:53

标签: javascript angularjs svg d3.js

我想在联合使用angularjs和d3js时报告一个相当奇怪的行为。以下plunker说明了它:Plunker

这是执行大部分工作的指令:

.directive('element1', function() {
    return {
        restrict: 'E',
        replace: true,
        template: '<svg></svg>',
        link: function (scope, element, attrs) {
          var rootElmt = d3.select(element[0]);
          rootElmt.append("g")
            .selectAll("text")
            .data(["Hello World"])
            .enter()
            .append("text")
            .attr("x", 20)
            .attr("y", 20)
            .text(function(d) {
              return d;
            });

          rootElmt.selectAll("text")[0]
            .forEach(function(d) {
              console.log("text length: ", d.getComputedTextLength());
            });

        }
    }
});         

你肯定会注意到自定义元素指令element1在获得的结果的基础上做了很多不必要的工作 - 实际上,我在一个更复杂的软件中发现了一个问题的核心,这个设备是在某种程度上需要。

plunker产生预期的结果,即显示SVG文本字符串,并记录应用于后者的getComputedTextLength()的结果。 plunker使用angularjs v1.2.0rc3。

现在,如果您注释1.2.0rc3脚本加载子句,并取消注释1.2.17(即一个相当新版本)的子句,则代码会遇到错误,由getComputedTextLength未定义引起。

此错误可以追溯到文本对象的属性:虽然SVGTextElement对象提供的角度较旧版本(即来自SVG原型链),但较新的版本会带来HTMLUnknownElement对象 - 导致明显缺少getComputedTextLength方法。

这可能是angularjs和d3之间错综复杂的互动的原因吗?也许我的指令代码不符合最近的angularjs最佳实践?

感谢您提前寻求帮助!

1 个答案:

答案 0 :(得分:1)

问题的根源在于您在Angular模板中创建SVG节点,而不是推迟到D3代码在指令中创建它:

template: '<svg></svg>',

这似乎与Angular issue #7383有关,似乎已在版本1.2.16中引入。

我看到1.3分支(尚未发布)即将推出feature #7265来恢复此支持:

  

以前,模板始终被认为是有效的HTML节点。在某些情况下,最好使用SVG或MathML或其他语言。

要在Angular 1.2.x中解决此问题,您只需从指令中删除模板属性,然后从D3代码创建SVG节点:

// create it here instead:
var rootElmt = d3.select(element[0]).append('svg');