score:3

Accepted answer

Here is a version of your code which displays the actual counts:

var width = 300,
    height = 300,
    radius = Math.min(width, height) / 2,
    color = d3.scale.category20c();

var svg = d3.select("body").append("svg")
  .attr("width", width)
  .attr("height", height)
  .append("g")
  .attr("transform", "translate(" + width / 2 + "," + height * .50 + ")");

var partition = d3.layout.partition()
    .sort(null)
    .size([2 * Math.PI, radius * radius])
    .value(function(d) { return 1; });

var arc = d3.svg.arc()
    .startAngle(function(d) { return d.x; })
    .endAngle(function(d) { return d.x + d.dx; })
    .innerRadius(function(d) { return Math.sqrt(d.y); })
    .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });

d3.json("https://raw.githubusercontent.com/d3/d3-hierarchy/master/test/data/flare.json", function(error, root) {

  if (error) throw error;

  // Deep copy of the root object (for use by the mouseover function)
  // since the d3 partitioning will modify root and only keep
  // partitioning details:
  var initialData = JSON.parse(JSON.stringify(root));
  
  var data = root;
  
  var path = svg.datum(root).selectAll("path")
    .data(partition.nodes)
	  .enter()
	  .append("path")
	  .attr("display", function(d) { return d.depth ? null : "none"; }) // hide inner ring
	  .attr("d", arc)
    .style("stroke", "#fff")
	  .style("fill-rule", "evenodd")
    .style("fill", howToFill)
	  .each(stash)
	  .on("mouseover", onMouseOver)
	  .on("mouseout", onMouseOut);


  var value = function(d) { return d.value; };
  
  // Let's move the onMouseOver function inside the json extractor in order
  // to easily work with "initialData":
  function onMouseOver(d) {
  	d3.select(this)
  	svg.append("text")
  	.style("text-anchor", "middle")
  	//.text(function() { return d.name + " - " + d.value; });
    .text(function() {
      return d.name + " - " + sumValue(findElem(initialData, d.name, d.depth, 0));
    });
  }
});

function stash(d) {
  d.x0 = d.x;
  d.dx0 = d.dx;
}

function arcTween(a) {
  var i = d3.interpolate({x: a.x0, dx: a.dx0}, a);
  return function(t) {
    var b = i(t);
    a.x0 = b.x;
    a.dx0 = b.dx;
    return arc(b);
  };
}

function howToFill(d) {
  if ( d.name == "-" ) {
    return "#fff";
  } else {
    return color((d.children ? d : d.parent).name);
  }
}

function onMouseOut(d) {
	d3.select(this)
	svg
  .select("text")
	.remove();
}

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

function findElem(elmt, name, searchedDepth, currDepth) {
  if (currDepth > searchedDepth)
    return undefined
  else if (elmt.name == name && searchedDepth == currDepth) {
    return elmt;
  }
  else if (elmt.children) {
    var result = elmt.children.map(c => findElem(c, name, searchedDepth, currDepth + 1)).filter(x => x);
    return result.length == 1 ? result[0] : undefined;
  }
  else
    return undefined;
}

function sumValue(elmt) {
  try {
    if (elmt.children)
      return elmt.children.map(c => sumValue(c)).reduce((a, b) => a + b, 0);
    else
      return elmt.value;
  } catch(err) {
    // The try catch is there to hide the exception due to the "data"
    // value which is not supported. Not sure how to cleanly fix this
    // corner case:
    return "error";
  }
}
<meta charset="utf-8">
<head>
  <link rel="stylesheet" type="text/css" href="main.css">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
</head>
<body>
  <script type="text/javascript" src="chart.js"></script>
</body>


During the mouseover, let's first find back the actual data element which is hovered. The thing is, the d3 layout partitioning removes data information from the model... So that's why we need to get back to the original data to find back the node in question:

function findElem(elmt, name, searchedDepth, currDepth) {
  if (currDepth > searchedDepth)
    return undefined
  else if (elmt.name == name && searchedDepth == currDepth) {
    return elmt;
  }
  else if (elmt.children) {
    var result = elmt.children.map(c => findElem(c, name, searchedDepth, currDepth + 1)).filter(x => x);
    return result.length == 1 ? result[0] : undefined;
  }
  else
    return undefined;
}

Which is called from the mouseover function this way:

.text( function() {
  return d.name + " - " + sumValue(findElem(initialData, d.name, d.depth, 0));
});

where initialData is a deep copy of the json (otherwise, since the extracted json root is modified by the partitioning, we would loose original data information).

Notice the usage of the depth in order to handle the fact that different nodes can have the same label (for instance there are several nodes at different depths named "data").


Once we have the node in question, we can recursively sum all children values this way:

function sumValue(elmt) {
  if (elmt.children)
    return elmt.children.map(c => sumValue(c)).reduce((a, b) => a + b, 0);
  else
    return elmt.value;
}

Related Query

More Query from same tag