D3 text on mouseover

元气小坏坏 提交于 2019-12-08 07:26:44

问题


I'm working on a sunburst diagram in D3 and I can't figure out how to add the text on mouseover. The text works if I add it 'statically' to the page, but if I move the code that add the text and put it in a 'mouseOver' function, no text shows up. Why? (in the following snippet you find both the working and the non-working codeblocks.

Thanks AC

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  margin: auto;
  position: relative;
  width: 960px;
}

form {
  position: absolute;
  right: 10px;
  top: 10px;
}

path {
  stroke: #fff;
  fill-rule: evenodd;
}

</style>
<body>
<form>
  <label><input type="radio" name="mode" value="size"> Size</label>
  <label><input type="radio" name="mode" value="count" checked> Count</label>
</form>
<script src="/d3/d3.v3.min.js"></script>
<script>


var width = 960,
    height = 700,
    radius = Math.min(width, height) / 2;

var x = d3.scale.linear()
    .range([0, 2 * Math.PI]);

var y = d3.scale.sqrt()
    .range([0, radius]);

var 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 / 2 + 10) + ")");

var partition = d3.layout.partition()
    .sort(null)
    .value(function(d) { return 1; });

var arc = d3.svg.arc()
    .startAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x))); })
    .endAngle(function(d) { return Math.max(0, Math.min(2 * Math.PI, x(d.x + d.dx))); })
    .innerRadius(function(d) { return Math.max(0, y(d.y)); })
    .outerRadius(function(d) { return Math.max(0, y(d.y + d.dy)); });

// Keep track of the node that is currently being displayed as the root.
var node;
function computeTextRotation(d) {
  return (x(d.x + d.dx / 2) - Math.PI / 2) / Math.PI * 180;
}

d3.json("get it here: http://bl.ocks.org/metmajer/raw/5480307/flare.json", function(error, root) {
  node = root;
  var path = svg.datum(root).selectAll("path")
      .data(partition.nodes)
    .enter().append("path")
      .attr("d", arc)
      .style("fill", function(d) { return color((d.children ? d : d.parent).name); })
      .on("click", click)
      .on("mouseover", mouseOver)
      .each(stash);

    //THIS WORKS: LOAD THE PAGE AND YOU'LL SEE THE LABELS
    var text = svg.datum(root).selectAll("text").data(partition.nodes);
    var textEnter = text.enter().append("text").text(function(d) { return d.name; })
    .attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
    .attr("x", function(d) { return y(d.y); })
    .attr("dx", "6") // margin
    .attr("dy", ".35em") // vertical-align
    .text(function(d) { return d.name; });

  d3.selectAll("input").on("change", function change() {
    var value = this.value === "count"
        ? function() { return 1; }
        : function(d) { return d.size; };

    path
        .data(partition.value(value).nodes)
      .transition()
        .duration(1000)
        .attrTween("d", arcTweenData);
  });

  //THIS DOESN'T WORK: NOTHING HAPPENS ON MOUSEOVER :(
  function mouseOver(d) {
    d3.select(this).append("text")
    .attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
    .attr("x", function(d) { return y(d.y); })
    .attr("dx", "6") // margin
    .attr("dy", ".35em") // vertical-align
    .text(function(d) { return d.name; });
  }

  function click(d) {
    node = d;
    path.transition()
      .duration(1000)
      .attrTween("d", arcTweenZoom(d))
;     .each("end", function(e, i) {
  }
});

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

// Setup for switching data: stash the old values for transition.
function stash(d) {
  d.x0 = d.x;
  d.dx0 = d.dx;
}

// When switching data: interpolate the arcs in data space.
function arcTweenData(a, i) {
  var oi = d3.interpolate({x: a.x0, dx: a.dx0}, a);
  function tween(t) {
    var b = oi(t);
    a.x0 = b.x;
    a.dx0 = b.dx;
    return arc(b);
  }
  if (i == 0) {
   // If we are on the first arc, adjust the x domain to match the root node
   // at the current zoom level. (We only need to do this once.)
    var xd = d3.interpolate(x.domain(), [node.x, node.x + node.dx]);
    return function(t) {
      x.domain(xd(t));
      return tween(t);
    };
  } else {
    return tween;
  }
}

// When zooming: interpolate the scales.
function arcTweenZoom(d) {
  var xd = d3.interpolate(x.domain(), [d.x, d.x + d.dx]),
      yd = d3.interpolate(y.domain(), [d.y, 1]),
      yr = d3.interpolate(y.range(), [d.y ? 20 : 0, radius]);
  return function(d, i) {
    return i
        ? function(t) { return arc(d); }
        : function(t) { x.domain(xd(t)); y.domain(yd(t)).range(yr(t)); return arc(d); };
  };
}

</script>

回答1:


On mouseover your function is getting called, but nothing is visible.

The reason you are appending the text with in the path DOM. Which is incorrect!

 function mouseOver(d) {
    d3.select(this).append("text")//you are appending text DOM inside the path
    .attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
    .attr("x", function(d) { return y(d.y); })
    .attr("dx", "6") // margin
    .attr("dy", ".35em") // vertical-align
    .text(function(d) { return d.name; });
  }

So as per this the output will be like this which is incorrect

<path d="M-343.02889638233785,-69.50666332601034A350,350 0 0,1 -340.90417092981470361071496A313.04951684997053,313.04951684997053 0 0,0 -306.8143722230556,-62.168649634460294Z" style="fill: rgb(158, 202, 225);">
         <text transform="rotate(192.2727272727272)" x="313.04951684997053" dx="6" dy=".35em" class="mylabel">IRenderer</text>
</path>

The correct way is this:

function mouseOver(d) {
            d3.select(this.parentNode).append("text")//appending it to path's parent which is the g(group) DOM
              .attr("transform", function() {
                return "rotate(" + computeTextRotation(d) + ")";
              })
              .attr("x", function() {
                return y(d.y);
              })
              .attr("dx", "6") // margin
              .attr("dy", ".35em") // vertical-align
              .attr("class", "mylabel")//adding a label class
              .text(function() {
                return d.name;
              });
          }

Note On mouse out of the path i am calling

  function mouseOut() {
    d3.selectAll(".mylabel").remove()//this will remove the text on mouse out
  }

Working code here

Hope this helps!



来源:https://stackoverflow.com/questions/34179006/d3-text-on-mouseover

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