D3.js: Is this good practise for data-DOM-binding?

可紊 提交于 2019-12-24 07:48:51

问题


I'm trying to grasp the D3 basics. I understand that it's crucial to get the binding right.

So I did a simple web page with update, enter and exit operations. Every time the data changes (modified, added, removed) I call a function where the data is bound to svg-objects in the update, enter and exit ways.

I wonder if my approach is a good one?

<html>
<head>

<style>
  .drawarea { border-style: solid; }
</style>

<script src="https://d3js.org/d3.v4.min.js"></script>

<script>
var data, drawArea;

function init(){
  data = [{"px" : 25, "py" : 25, "s" : 5}, {"px" : 25, "py" : 50, "s" : 5}, {"px" : 25, "py" : 75, "s" : 10} ];

  drawArea = d3.select("#drawareadiv").append("svg:svg")
    .attr("class", "drawarea")
    .attr("width", 500)
    .attr("height", 250);

  draw();
}

function draw(){
  var domRects = drawArea.selectAll("rect");

  // update
  domRects
    .data(data)
    .attr("x", function(d) { return d.px; })
    .attr("y", function(d) { return d.py; })
    .attr("width", function(d) { return d.s; })
    .attr("height", function(d) { return d.s; });

  // enter
  domRects
    .data(data)
    .enter()
    .append("svg:rect")
    .attr("x", function(d) { return d.px; })
    .attr("y", function(d) { return d.py; })
    .attr("width", function(d) { return d.s; })
    .attr("height", function(d) { return d.s; });

   // exit
   domRects
     .data(data)
     .exit()
     .remove();
}

function updateDataAndBinding(){
  for(i=0; i<data.length; i++)
    data[i].px += 10;
  draw();
}

function enterDataAndBinding(){
  var px = 25;
  var py = 25 * (data.length+1);
  var s = Math.floor(data.length/2)*5+5;
  data.push({"px" : px, "py" : py, "s" : s});
  draw();
}

function exitDataAndBinding(){
  data.splice(data.length-1, 1);
  draw();
}

</script>

</head>

<body onload="init()">
<div id="drawareadiv"></div>
<button onclick="updateDataAndBinding()">updateDataAndBinding</button>
<button onclick="enterDataAndBinding()">enterDataAndBinding</button>
<button onclick="exitDataAndBinding()">exitDataAndBinding</button>
</body>

</html>

回答1:


I'd suggest two things:

  1. Don't bind the data again and again. Do this just one time:

    var domRects = drawArea.selectAll("rect").data(data);
    
  2. As this is D3 v4.x, use merge to deal with the "enter" and "update" selections together:

    // enter + update
    domRects.enter()
        .append("svg:rect")
        .attr("x", function(d) { return d.px; })
        .attr("y", function(d) { return d.py; })
        .attr("width", function(d) { return d.s; })
        .attr("height", function(d) { return d.s; })
        .merge(domRects)
        .attr("x", function(d) { return d.px; })
        .attr("y", function(d) { return d.py; })
        .attr("width", function(d) { return d.s; })
        .attr("height", function(d) { return d.s; });
    

Here is the demo (click "run code snippet"):

<style>
  .drawarea { border-style: solid; }
</style>

<script src="https://d3js.org/d3.v4.min.js"></script>

<script>
var data, drawArea;

function init(){
  data = [{"px" : 25, "py" : 25, "s" : 5}, {"px" : 25, "py" : 50, "s" : 5}, {"px" : 25, "py" : 75, "s" : 10} ];

  drawArea = d3.select("#drawareadiv").append("svg:svg")
    .attr("class", "drawarea")
    .attr("width", 500)
    .attr("height", 200);

  draw();
}

function draw(){
  var domRects = drawArea.selectAll("rect").data(data);

  // enter
  domRects.enter()
    .append("svg:rect")
    .attr("x", function(d) { return d.px; })
    .attr("y", function(d) { return d.py; })
    .attr("width", function(d) { return d.s; })
    .attr("height", function(d) { return d.s; })
		.merge(domRects)
		.attr("x", function(d) { return d.px; })
    .attr("y", function(d) { return d.py; })
    .attr("width", function(d) { return d.s; })
    .attr("height", function(d) { return d.s; });

   // exit
   domRects.exit()
     .remove();
}

function updateDataAndBinding(){
  for(i=0; i<data.length; i++)
    data[i].px += 10;
  draw();
}

function enterDataAndBinding(){
  var px = 25;
  var py = 25 * (data.length+1);
  var s = Math.floor(data.length/2)*5+5;
  data.push({"px" : px, "py" : py, "s" : s});
  draw();
}

function exitDataAndBinding(){
  data.splice(data.length-1, 1);
  draw();
}

</script>

</head>

<body onload="init()">
<div id="drawareadiv"></div>
<button onclick="updateDataAndBinding()">updateDataAndBinding</button>
<button onclick="enterDataAndBinding()">enterDataAndBinding</button>
<button onclick="exitDataAndBinding()">exitDataAndBinding</button>
</body>

Other than that, your approach seems to be a good (and standard) one.



来源:https://stackoverflow.com/questions/40042232/d3-js-is-this-good-practise-for-data-dom-binding

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!