Angular + d3.js:使用SVG文本属性进行数据绑定

Angular + d3.js: Data binding with SVG text attr?

本文关键字:属性 文本 数据绑定 SVG 使用 d3 js Angular      更新时间:2023-09-26

我正在进行一个可视化,涉及更新出现在圆圈内的文本元素。比如:

<g>
    <circle></circle>
    <text>My text that needs updating</text>
</g>
伴随着这个小的视觉效果是一个d3画笔被用作滑块。在brush/brushend上,我需要<text>Update the text here</text>,基于与滑块x轴上的时间尺度相关的数据。

我有两个Angular指令。一个包含圆圈,另一个是滑动条。在我的slider指令中,我调用:

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

然后我在我的另一个指令中收听这个,并更新文本。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与Angular?

您可以将D3JS代码包装在指令中,然后使用传入的属性并观察它是否改变以相应地更新D3JS代码(您保存对svg文本的引用仍然可能是最好的选择)。例如,请参阅下面的指令,我使用val来更新条形图显示中使用的数据(注意,我还没有在这里处理过渡,代码有点乱,但希望您能看到总体要点)

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