Javascript D3.js复制我的数据

Javascript D3.js复制我的数据,javascript,d3.js,Javascript,D3.js,我试图为一些与学生相关的数据(下面的示例记录)创建一个数据可视化,但当d3渲染它时,它会遍历数据两次并覆盖它,只在屏幕上留下第二次遍历的结果。我在这里使用了一个行计数器,所以我有一种方法可以根据有多少个矩形来设置每个矩形的y坐标。我觉得这有点把事情搞砸了。如果您能提供帮助,使数据不会重复两次,我们将不胜感激 另外,为了以防万一,这段代码在angular.js指令中 如果我只是在做一些很愚蠢的事情,我道歉 // student records sample... var studentData =

我试图为一些与学生相关的数据(下面的示例记录)创建一个数据可视化,但当d3渲染它时,它会遍历数据两次并覆盖它,只在屏幕上留下第二次遍历的结果。我在这里使用了一个行计数器,所以我有一种方法可以根据有多少个矩形来设置每个矩形的y坐标。我觉得这有点把事情搞砸了。如果您能提供帮助,使数据不会重复两次,我们将不胜感激

另外,为了以防万一,这段代码在angular.js指令中

如果我只是在做一些很愚蠢的事情,我道歉

// student records sample...
var studentData = [
{   
"studentID" : 1001,
"firstName" : "jill",
"lastName" : "smith",
"workLoadDifficulty" : 16,
"smileStartAngle" : -90,
"smileEndAngle" : 90,
},
{   
"studentID" : 1008,
"firstName" : "bob",
"lastName" : "smith",
"workLoadDifficulty" : 99,
"smileStartAngle" : 90,
"smileEndAngle" : -90,
}
];
(function () {
'use strict';
angular.module('learnerApp.directives')
.directive('d3Bars', ['d3', function(d3) {
  return {
    restrict: 'EA',
    scope: {
      data: "=",
      label: "@",
      onClick: "&"
    },
    link: function(scope, iElement, iAttrs) {
      var paddingForShape = 10;
      var rowCounter = -1;
      var height = 400;
      var width = 300;
      var svgContainer = d3.select(iElement[0])
          .append("svg")
          .attr("width", width)
          .attr('height', height);

      // on window resize, re-render d3 canvas
      window.onresize = function() {
        return scope.$apply();
      };
      scope.$watch(function(){
          return angular.element(window)[0].innerWidth;
        }, function(){
          return scope.render(scope.data);
        }
      );

      // watch for data changes and re-render
    scope.$watch('studentData', function(newVals, oldVals) {
        return scope.render(newVals);
      }, true); 

      // define render function
      scope.render = function(data){
        // remove all previous items before render
      svgContainer.selectAll("*").remove();

      var workLoadColor = d3.scale.category10()
            .domain([0,100])
            .range(['#02FA28', '#73FA87', '#C0FAC9','#FAE4C0', '#FAC775', '#FAA823','#FA9A00','#FA8288', '#FC4750', '#FA0511' ])


   var studentRects = svgContainer.selectAll('rect')
      .data(studentData, function(d) { 
        console.log(d.studentID);
        console.log('hello');
        return "keyVal" + d.studentID;
         })
      .enter()
        .append("rect");

      var studentRectAttributes = studentRects
                .attr("x", function(d,i) {
                    return ((i * 50) % width) + paddingForShape;
                })
                .attr("y", function(d,i) {
                    var value = ((i * 50) % width)
                    if (value === 0) {
                      rowCounter = rowCounter + 1;
                    }                    
                    var value = (rowCounter * 50);
                    console.log('Y Val: ', i);
                    console.log(value);
                    return value;
                })                   
                .attr("height", 30)
                .attr("width", 40)
                .style("fill", function(d) {
                  return workLoadColor(d.workLoadDifficulty)
                });


      };
    }
  };
}]);
}());

尝试将选择器更改为
var studentRects=svgContainer。选择所有('rect')
,它将匹配您在
enter()上添加的
元素

**更新**

除了@Wex给出的关键建议外,我还将代码塞进了plunker,并使其正常工作。您的示波器上有一个额外的手表,移除它可以解决问题(不过您可能希望重新查看一些关于进入/退出的d3文档):


点击此处:

如果要执行两次数据联接,则需要指定一个
,这样就不会覆盖当前选择中的元素。您可能需要将
studentRects
定义更改为:

var studentRects = svgContainer.selectAll('rect')
  .data(studentData, function(d) { return d.firstName + ' ' + d.lastName; });
studentRects.enter().append("rect");
请参阅
选择。([values[,key]])

如果未指定键函数,则指定数组中的第一个基准将指定给当前选择中的第一个图元,第二个基准将指定给第二个选定图元,依此类推


谢谢,但恐怕运气不好。我认为这与d3.js中的enter()update()exit()有关,我认为我没有完全理解。但是根据您的建议更新了代码,因为这可能是更好的做法。我刚刚注意到您对angularjs指令的编辑。这很可能就是问题所在。您是否调用d3代码来响应$watch?看这里:angular的新版本有一个$watchCollection方法,它可能会帮助你。哦,多么尴尬,你是对的,不知道我是怎么做到的!!!谢谢你。它起作用了!!作为我关于堆栈溢出的第一个问题,我似乎还不能向上投票,但请向您发送好的想法,谢谢!假设我正确理解了你的问题,并且你有两个studentData数组,你也可以在显示它们之前将两个数组连接起来——这样,你只有一个数据连接。我认为问题是只有一个数组,d3对数据进行了两次检查(d3通常没有问题,但因为有一个
行计数器,你会注意到。另外,不使用键函数会导致新数据无法呈现(b/c它们将共享相同的索引,对吗?)@redmallard-我不确定使用
行计数器将如何影响添加到
enter
selection.wex中的元素。真的。不确定我在想什么(可能行计数器有异味,所以我责备它;)。谢谢-我已更新使用键并将其放入上面的代码中(现在用角度的东西完成代码)但它仍在迭代…仍不确定。不知何故,可能是行计数器的问题?我不确定,因此您的任何其他想法都将不胜感激。也感谢指向文档的链接。看看您是否可以更好地隔离问题。移动部件太多,无法真正指出导致可视化的原因这是我的第一个堆栈问题,所以到处都是。原来是重复的$watch问题。但是你提到的关于键的问题我已经遇到过好几次了,直到现在还没有真正理解-谢谢!
var studentRects = svgContainer.selectAll('rect')
  .data(studentData, function(d) { return d.firstName + ' ' + d.lastName; });
studentRects.enter().append("rect");