Angular + d3.js:与SVG文本attr的数据绑定?

时间:2014-03-18 14:18:25

标签: javascript angularjs d3.js

我正在开展一项可视化工作,涉及更新出现在圆圈内的文本元素。类似的东西:

<g>
    <circle></circle>
    <text>My text that needs updating</text>
</g>

除了这个小视觉效果之外,还有一个用作滑块的d3画笔。在brush / brushend上,我需要<text>Update the text here</text>,基于与滑块的x轴上的时间刻度相关联的数据。

我有两个Angular指令。一个包含圆圈,另一个包含滑块。在我的滑块指令中,我正在呼叫:

$rootScope.$emit('brushing');并根据我的数据设置rootScope变量,$rootScope.myNewValue = newValue;发生滑动

然后我在我的另一个指令中监听这个,并将text.attr更新为rootScope var:

$rootScope.$on('brushing', function () { myText.text($rootScope.myNewValue); });

其中:

var myText = svg.append('text')
    .text('I'm trying to update this text..');

...代码的d3部分

以这种方式做事似乎有效,但我想知道在初始化myText时是否有办法直接绑定数据:

var myText = svg.append('text)
    .text($rootScope.myNewValue);

这样值就可以直接更新而无需$ emit和listen。我在指令中试过了scope.$apply,但这似乎没有效果。

在使用带角度的d3时,是否有人遇到过类似的情况?

1 个答案:

答案 0 :(得分:1)

你可以在一个指令中包装D3JS代码然后使用传入的属性并观察它以查看它是否相应更新以相应地更新D3JS代码(保存对svg文本的引用仍然是最好的选择)。有关示例,请参阅下面的我的指令,其中我使用val来更新条形图显示中使用的数据(注意我还没有处理过渡,而且代码有点乱,但希望你看到一般点)< / p>

directive('barChart', function ( /* dependencies */ ) {
  // define constants and helpers used for the directive

  var width = 600,
    height = 80;

  return {
    restrict: 'E', // the directive can be invoked only by using <bar-chart></bar-chart> tag in the template
    scope: { // attributes bound to the scope of the directive
      val: '='
    },
    link: function (scope, element, attrs) {
      // initialization, done once per my-directive tag in template. If my-directive is within an
      // ng-repeat-ed template then it will be called every time ngRepeat creates a new copy of the template.

      // set up initial svg object
      var vis = d3.select(element[0])
        .append("svg")
          .attr("class", "chart")
          .attr("width", width)
          .attr("height", height);


      // whenever the bound 'exp' expression changes, execute this 
      scope.$watch('val', function (newVal, oldVal) {

        // clear the elements inside of the directive
        vis.selectAll('*').remove();
        vis.attr("height", newVal.length*22);

        // if 'val' is undefined, exit
        if (!newVal) {
          return;
        }
        var totalDataSetSize = 0;

        for (var i = 0; i < newVal.length; i++) {
          totalDataSetSize += newVal[i].data.length
        };

        function calcBarWidth(d) {
          return (totalDataSetSize==0)?0:d.data.length/totalDataSetSize*420;
        }

        vis.selectAll("rect")
            .data(newVal)
          .enter().append("rect")
            .attr("y", function(d, i) { return i*20; })
            .attr("width", calcBarWidth)
            .attr("height", function(d) {return 20});

        vis.selectAll("text")
            .data(newVal)
          .enter().append("text")
            .attr("x", function(d) { return calcBarWidth(d)+10})
            .attr("y", function(d, i) { return (i+1)*20; })
            .attr("dy", "-.3em") // vertical-align: middle
            .style("font-size", ".7em")
            .attr("fill", "black")
            .attr("text-anchor", "beginning") // text-align: right
            .text(function(d,i){ return d.data.length.toString() + "  " + d.label})

      },true);
    }
  };
})