问题
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