سؤال

I am using this bubble chart to build up my own versions. http://bl.ocks.org/mbostock/4063269 Appending multiple copies of the chart on a single page for comparison seems to only append one copy of the chart. It could possibly be appending the same chart over the other. My questions is what in this code is causing only one chart to show up?. And how do you avoid this issue when using multiple copies of the same code(chart) on the same page? Is there a guideline, or some basic principles to prevent this?

 <script>

var diameter = 960,
    format = d3.format(",d"),
    color = d3.scale.category20b();

var bubble = d3.layout.pack()
    .sort(null)
    .size([diameter, diameter])
    .padding(1.5);

var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
    .attr("class", "bubble");

d3.json("DataGreatEnglishWriters.json", function(error, root) {
  var node = svg.selectAll(".node")
      .data(bubble.nodes(classes(root))
      .filter(function(d) { return !d.children; }))
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  node.append("title")
      .text(function(d) { return d.className + ": " + format(d.value); });

  node.append("circle")
      .attr("r", function(d) { return d.r; })
      .style("fill", function(d) { return color(d.packageName); });

  node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.className.substring(0, d.r / 3); });
});

// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) {
  var classes = [];

  function recurse(name, node) {
    if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
    else classes.push({packageName: name, className: node.name, value: node.size});
  }

  recurse(null, root);
  return {children: classes};
}

d3.select(self.frameElement).style("height", diameter + "px");

</script>
<script>

var diameter = 960,
    format = d3.format(",d"),
    color = d3.scale.category20b();

var bubble = d3.layout.pack()
    .sort(null)
    .size([diameter, diameter])
    .padding(1.5);

var svg = d3.select("body").append("svg")
    .attr("width", diameter)
    .attr("height", diameter)
    .attr("class", "bubble");

d3.json("Data.json", function(error, root) {
  var node = svg.selectAll(".node")
      .data(bubble.nodes(classes(root))
      .filter(function(d) { return !d.children; }))
    .enter().append("e")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  node.append("title")
      .text(function(d) { return d.className + ": " + format(d.value); });

  node.append("circle")
      .attr("r", function(d) { return d.r; })
      .attr("stroke" , "grey")
      .style("fill", function(d) { return color(d.packageName); });

  node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .text(function(d) { return d.className.substring(0, d.r / 3); });
});

// Returns a flattened hierarchy containing all leaf nodes under the root.
function classes(root) {
  var classes = [];

  function recurse(name, node) {
    if (node.children) node.children.forEach(function(child) { recurse(node.name, child); });
    else classes.push({packageName: name, className: node.name, value: node.size});
  }

  recurse(null, root);
  return {children: classes};
}

d3.select(self.frameElement).style("height", diameter + "px");

</script>
هل كانت مفيدة؟

المحلول

Looking quickly at your code, it appears that you're just repeating the same code twice, in the same scope. This means that the second time you say var svg = ..., you're overwriting the value of svg. Because the load callback functions are closures, they will both refer to the last-defined value of svg, and the second load will overwrite the first.

This overwriting happens in part because a core concept of D3 is that it will re-use existing DOM nodes if possible - see Thinking with Joins. So the second file that loads looks for .node elements in svg, finds the first set, and reuses them with the new data.

A much better option here would be to wrap the entire thing in a function that takes the file to load, and possible a DOM target to append the SVG to:

function addChart(file, target) {
   var svg = d3.select(target).append('svg');
   // ...

   d3.json(file, function() {
       // ...
   });
}

addChart("DataGreatEnglishWriters.json", "div.foo");
addChart("Data.json", "div.bar");
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top