Related
JSFiddle example
I've noticed that when updating positions of svg elements in a d3-force diagram, updating the positions of elements using (in the case of circles) the cx and cy attributes is much smoother than using the transform attribute.
In the example JSFiddle, there are two separate force simulations side-by-side. The one on the left updates positions using the transform attribute:
sim_transform.on('tick', function () {
circles_transform.attr('transform', function (d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
});
The one on the right updates positions using the cx and cy attributes of a circle:
sim_position.on('tick', function () {
circles_position
.attr('cx', function (d) {
return d.x;
})
.attr('cy', function (d) {
return d.y;
})
});
The simulations appear identical until they're just about to become static, at which point the one using transforms starts to jitter quite a bit. Any ideas what is causing this? Can it be fixed so that the animation remains smooth using transforms?
It seems to me that the issue you're observing (only reproducible in FireFox, as #altocumulus noted) has something to do with the way FF uses floating numbers for the translate of the transform attribute.
We can see this if we set both simulations to use integers, doing ~~(d.x) and ~~(d.y). Have a look, both will jitter:
var svg = d3.select('svg');
var graph_transform = gen_data();
var graph_position = gen_data();
var force_left = d3.forceCenter(
parseInt(svg.style('width')) / 3,
parseInt(svg.style('height')) / 2
)
var force_right = d3.forceCenter(
2 * parseInt(svg.style('width')) / 3,
parseInt(svg.style('height')) / 2
)
var sim_transform = d3.forceSimulation()
.force('left', force_left)
.force('collide', d3.forceCollide(65))
.force('link', d3.forceLink().id(id));
var sim_position = d3.forceSimulation()
.force('right', force_right)
.force('collide', d3.forceCollide(65))
.force('link', d3.forceLink().id(id));
var g_transform = svg.append('g');
var g_position = svg.append('g');
var circles_transform = g_transform.selectAll('circle')
.data(graph_transform.nodes)
.enter()
.append('circle')
.attr('r', 40);
var circles_position = g_position.selectAll('circle')
.data(graph_position.nodes)
.enter()
.append('circle')
.attr('r', 40);
sim_transform
.nodes(graph_transform.nodes)
.force('link')
.links(graph_transform.links);
sim_position
.nodes(graph_position.nodes)
.force('link')
.links(graph_position.links);
sim_transform.on('tick', function() {
circles_transform.attr('transform', function(d) {
return 'translate(' + (~~(d.x)) + ',' + (~~(d.y)) + ')';
});
});
sim_position.on('tick', function() {
circles_position
.attr('cx', function(d) {
return ~~d.x;
})
.attr('cy', function(d) {
return ~~d.y;
})
});
function id(d) {
return d.id;
}
function gen_data() {
var nodes = [{
id: 'a'
},
{
id: 'b'
},
{
id: 'c'
},
{
id: 'd'
}
]
var links = [{
source: 'a',
target: 'b'
},
{
source: 'b',
target: 'c'
},
{
source: 'c',
target: 'd'
},
{
source: 'd',
target: 'a'
}
];
return {
nodes: nodes,
links: links
}
}
svg {
width: 100%;
height: 500px;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
So, in your original code, it seems like the circles move correctly when using cx and cy, but they jump from integer to integer when using translate (or maybe half pixel, see the last demo). If the hypothesis here is correct, the reason that you just see the effect when the simulation is cooling down is because, at that moment, the movements are smaller.
Demos
Now, if we get rid of the simulation, we can see that this strange behaviour also happens with a very basic transform. To check this, I created a transition for a big black circle, using a linear ease and a very long time (to facilitate seeing the issue). The circle will move 30px to the right. I also put a gridline to make the jumps more noticeable.
(Warning: the demos below are only reproducible in FireFox, you won't see any difference in Chrome/Safari)
If we use cx, the transition is smooth:
var svg = d3.select("svg");
var gridlines = svg.selectAll(null)
.data(d3.range(10))
.enter()
.append("line")
.attr("y1", 0)
.attr("y2", 200)
.attr("x1", function(d) {
return 300 + d * 3
})
.attr("x2", function(d) {
return 300 + d * 3
})
.style("stroke", "lightgray")
.style("stroke-width", "1px");
var circle = svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 98)
.transition()
.duration(10000)
.ease(d3.easeLinear)
.attr("cx", "230")
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="200"></svg>
However, if we use translate, you can see the circle jumping 1px at every move:
var svg = d3.select("svg");
var gridlines = svg.selectAll(null)
.data(d3.range(10))
.enter()
.append("line")
.attr("y1", 0)
.attr("y2", 200)
.attr("x1", function(d) {
return 300 + d * 3
})
.attr("x2", function(d) {
return 300 + d * 3
})
.style("stroke", "lightgray")
.style("stroke-width", "1px");
var circle = svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 98)
.transition()
.duration(10000)
.ease(d3.easeLinear)
.attr("transform", "translate(30,0)")
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="200"></svg>
For you people running this in Chrome/Safari, this is how the last snippet looks like in Firefox. It's like the circle is being moved half a pixel at every change... definitely not as smooth as changing cx:
var svg = d3.select("svg");
var gridlines = svg.selectAll(null)
.data(d3.range(10))
.enter()
.append("line")
.attr("y1", 0)
.attr("y2", 200)
.attr("x1", function(d) {
return 300 + d * 3
})
.attr("x2", function(d) {
return 300 + d * 3
})
.style("stroke", "lightgray")
.style("stroke-width", "1px");
var circle = svg.append("circle")
.attr("cx", 200)
.attr("cy", 100)
.attr("r", 98);
var timer = d3.timer(function(t){
if(t>10000) timer.stop();
circle.attr("cx", 200 + (~~(60/(10000/t))/2));
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="200"></svg>
As this is an implementation issue only visible in FF, it may be worth reporting a bug.
I have a seemingly simple d3.js problem. I am creating a tree from a set of json data. The tree is composed of labels that are composed of a rectangle container that wrap around some text. I would like to change the width of the rectangle according to the length of the text. I understand I should be doing something like this one, but I am struggling to understand how.
Here is my JS code (stripped down of most unnecessary frills):
var rectW = 140, rectH = 40;
// Declare the nodes.
var node = draw.selectAll('g.node')
.data(nodes, function(d) { return d.id; });
// Enter the nodes.
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) { return 'translate(' + source.x0 + ',' + source.y0 + ')'; });
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH);
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.text(function (d) { return d.name; });
As you can see, I create an SVG group to which I append both the container rectangle and the contained text.
Now, I would like to retrieve the length of each text element, and use it to change the width of the corresponding rectangle element. How can I do that? I tried with every possible combination of D3 directives I could think of, but my knowledge of the library is not enough advanced to suit my purposes.
UPDATE
Thanks to Geraldo Furtado's answer, I managed to fix this issue by adding the following:
// This arranges the width of the rectangles
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + 20;
})
// This repositions texts to be at the center of the rectangle
nodeText.attr('x', function() {
return (this.getComputedTextLength() + 20) /2;
})
This is the current structure of your nodes:
<g>
<rect></rect>
<text></text>
</g>
That being the case, the texts are the nextSiblings of the rectangles. Therefore, all you need to get the length of the texts is using nextSibling in the rectangle selection:
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + rectW
})
Here I'm adding rectW to keep the same padding on the left and right, since you're putting the texts to start at rectW / 2.
If you're not sure about the relationship between the texts and rectangles (who is the first child, who is the last child...), you can go up, select the group element and then select the text inside it:
nodeRect.attr("width", function() {
return d3.select(this.parentNode).select("text").node().getComputedTextLength() + rectW
})
Here is a basic demo:
var data = [{
name: "some text",
x: 10,
y: 10
},
{
name: "A very very very long text here",
x: 100,
y: 50
},
{
name: "Another text, this time longer than the previous one",
x: 25,
y: 100
},
{
name: "some short text here",
x: 220,
y: 150
}
];
var svg = d3.select("svg");
var rectW = 140,
rectH = 30;
var node = svg.selectAll(null)
.data(data);
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH)
.style("fill", "none")
.style("stroke", "gray")
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.style("dominant-baseline", "central")
.text(function(d) {
return d.name;
});
nodeRect.attr("width", function() {
return this.nextSibling.getComputedTextLength() + rectW
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>
For storing the computed width and using it later on, you can set another property. For instance:
nodeRect.attr("width", function(d) {
return d.rectWidth = this.nextSibling.getComputedTextLength() + rectW
});
Here is the demo, look at the console:
var data = [{
name: "some text",
x: 10,
y: 10
},
{
name: "A very very very long text here",
x: 100,
y: 50
},
{
name: "Another text, this time longer than the previous one",
x: 25,
y: 100
},
{
name: "some short text here",
x: 220,
y: 150
}
];
var svg = d3.select("svg");
var rectW = 140,
rectH = 30;
var node = svg.selectAll(null)
.data(data);
var nodeLabel = node.enter().append('g')
.attr('transform', function(d) {
return 'translate(' + d.x + ',' + d.y + ')';
});
var nodeRect = nodeLabel.append('rect')
.attr('width', rectW)
.attr('height', rectH)
.style("fill", "none")
.style("stroke", "gray")
var nodeText = nodeLabel.append('text')
.attr('x', rectW / 2)
.attr('y', rectH / 2)
.style("dominant-baseline", "central")
.text(function(d) {
return d.name;
});
nodeRect.attr("width", function(d) {
return d.rectWidth = this.nextSibling.getComputedTextLength() + rectW
});
nodeLabel.each(function(d) {
console.log(d)
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg width="500" height="300"></svg>
You can add the following line at the end of your script, after the text has been set:
nodeRect
.transition()
.attr("width",function(){
return Math.max(rectW,nodeText.node().getComputedTextLength())
}).delay(0).duration(500)
I used Math.max to set it to rectW if its large enough or expand if necessary. You can perhaps adapt that part.
I use this example: https://codepen.io/AndrewGHC/pen/mPXjKr
I have 2 questions:
1) How can I restrict drag-and-drop? For example, I want to restrict movement to 50px around the circle. It should not move beyond 50px away from the circle's starting position.
2) When you refresh the page, you see elements in different places.
One circle may be right, and the next time the left. How can this be avoided? I think I need to set the starting positions.
// Request data, generate bg with Trianglify & set up loading function.
function slowPrint(tgt, i, msg, spd) {
if (i < msg.length) {
$(tgt).append(msg[i]);
i++;
var writeTimer = setTimeout(function() {
slowPrint(tgt, i, msg, spd)
}, spd);
}
}
function writeThis(tgt, msg, spd) {
if ($(tgt).html() === msg) {
return;
}
$(tgt).html('');
slowPrint(tgt, 0, msg, spd);
}
writeThis('#info', 'Loading . . .', 100);
var url = "https://raw.githubusercontent.com/AndrewGHC/kevin-bacon-number/master/kevinBacon.json";
d3.json(url, drawGraph);
// Credit to Trianglify # https://github.com/qrohlf/trianglify
var pattern = Trianglify({
height: $(document).height(),
width: $(document).width(),
cell_size: 40
});
document.body.style.backgroundImage = "url(" + pattern.png() + ")";
// Create the drawGraph callback
function drawGraph(err, data) {
if (err) throw err;
var width = $('#graph').width(),
height = $('#graph').height();
// Prepare the data for the force graph, beinning by creating an array of movies (strings)
var movies = [];
(function() {
data.actors.forEach(function(actor) {
actor.movies.forEach(function(movie) {
if (movies.indexOf(movie) === -1) {
movies.push(movie);
}
});
});
}())
// Create the links array for the force graph, mapping actors to movies. This will draw a line between the two.
var links = [];
(function() {
data.actors.forEach(function(actor, actorIndex) {
actor.movies.forEach(function(movie, movieIndex) {
links.push({
"source": actorIndex,
"target": data.actors.length + movies.indexOf(movie)
});
});
});
}())
// Now prepare the nodes array, concatenating data.actors and the movies array. The order here is important, and movie indices must be converted into objects.
var nodes = data.actors;
movies.forEach(function(movie) {
nodes.push({
"movie": movie
});
});
// Create the SVG canvas & force layout
var canvas = d3.select('#graph')
.append('svg')
.attr("height", height)
.attr("width", width);
var force = d3.layout.force()
.size([width, height])
.nodes(nodes)
.links(links)
.linkDistance(50)
.charge(function(d) {
if (d.name === "Kevin Bacon") {
return -1000;
} else if (d.name) {
return -(d.weight) * 50;
}
return -((d.weight * 50) * 5);
})
.gravity(0.1)
.start();
// Helper function to remove whitespace, later used for assigning IDs
function rmWs(string) {
if (typeof string !== 'string') {
return false;
}
string = string.split(' ').join('');
return string;
}
// Create the links
var link = canvas.selectAll('.link')
.data(links)
.enter().append('line')
.attr('class', 'link');
// Create a colour scale for movie nodes. Find the min and max no. of links for the range of the colour domain.
var arrMax = [];
links.forEach(function(link) {
arrMax.push(link.target.weight);
});
var colour = d3.scale.linear()
.domain([1, d3.max(arrMax)])
.range(["white", "black"])
.interpolate(d3.interpolateHcl);
// Set up the pop up on mouse hover
// Call circles on SVG chart, with colours along a white - black gradient generated based on the max weight & variable sizing. Then place text on these movie elements.
var circleRadius = 17;
var circles = canvas.selectAll('.movies')
.data(nodes)
.enter()
.append('circle')
.attr('r', function(d, i) {
if (d.name) {
return circleRadius;
}
return circleRadius + (d.weight * 2);
})
.attr('stroke', '#777')
.attr('stroke-width', '2px')
.attr('fill', function(d, i) {
return colour(d.weight) || 'black';
})
.call(force.drag)
var text = canvas.selectAll('.moviesText')
.data(nodes)
.enter()
.append('text')
.attr('text-anchor', 'middle')
.text(function(d) {
return d.movie;
});
// Set up clip path for each forthcoming image node to clip rectangular images to circles. Then call images on the canvas.
var clip = canvas.selectAll('clipPath')
.data(nodes)
.enter()
.append('clipPath')
.attr('id', function(d) {
return rmWs(d.name) || rmWs(d.movie)
})
.append('circle')
.attr('r', circleRadius);
var imgWidth = 50,
imgHeight = 50;
var node = canvas.selectAll('.node')
.data(nodes)
.enter()
.append('image')
.attr('xlink:href', function(d) {
return d.thumbnail;
})
.attr("class", "image")
.attr("width", imgWidth)
.attr("height", imgHeight)
.attr("clip-path", function(d) {
return "url(#" + (rmWs(d.name) || rmWs(d.movie)) + ")"
})
.call(force.drag);
// Handle operations on each tick.
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});
node.attr("x", function(d) {
return d.x - (imgWidth / 2);
})
.attr("y", function(d) {
return d.y - (imgHeight / 2);
});
clip.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
circles.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
text.attr('x', function(d) {
return d.x;
})
.attr('y', function(d) {
return d.y - 30;
})
});
// When all initial calculations are done, print title to replace 'Loading . . .'
force.on('end', function() {
writeThis('#info', 'D3 Force Graph - Distance from Kevin Bacon', 100);
})
}
#import url(https://fonts.googleapis.com/css?family=Questrial' rel='stylesheet' type='text/css);
#header {
text-align: center;
font-family: 'Jockey One', sans-serif;
}
#graph {
margin: 15px auto;
background: white;
height: 750px;
width: 750px;
-webkit-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75);
box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.75);
}
.link {
stroke: #777;
stroke-width: 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.1/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="header">
<h2 id="info"></h2>
</div>
<div id="graph"></div>
Here is how you can restrict your dragging:
First, set your drag functions:
var drag = force.drag()
.on("dragstart", dragstarted)
.on("drag", dragged);
Then, in dragstarted, get the current x and y positions:
function dragstarted(d) {
currentX = d.x;
currentY = d.y;
}
Finally, in the dragged function, set your rules:
function dragged(d) {
d.px = (d.px > currentX + 50) ? currentX + 50 : d.px;
d.py = (d.py > currentY + 50) ? currentY + 50 : d.py;
d.px = (d.px < currentX - 50) ? currentX - 50 : d.px;
d.py = (d.py < currentY - 50) ? currentY - 50 : d.py;
}
Here is the Pen: https://codepen.io/anon/pen/eBzyYd?editors=0010
PS: Here at SO is a good practice dealing with 1 problem at a time, one question per problem. So, I suggest you post your second problem as a separate question.
Hello I currently have a stacked bar chart in d3,js that currently won't transition.
The chart is able to update but unfortunately no transition :(
I am under the feeling that there is a 1 line fix to this.
Please help!!!
Took this from
http://bl.ocks.org/anotherjavadude/2940908
<!DOCTYPE html>
<html>
<head>
<title>Simple Stack</title>
<script src="http://d3js.org/d3.v3.js"></script>
<style>
svg {
border: solid 1px #ccc;
font: 10px sans-serif;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div id="viz"></div>
<script type="text/javascript">
var w = 960,
h = 500
// create canvas
var svg = d3.select("#viz").append("svg:svg")
.attr("class", "chart")
.attr("width", w)
.attr("height", h )
.append("svg:g")
.attr("transform", "translate(10,470)");
x = d3.scale.ordinal().rangeRoundBands([0, w-800])
y = d3.scale.linear().range([0, h-100])
z = d3.scale.ordinal().range(["blue", "lightblue"])
// console.log("RAW MATRIX---------------------------");
// 3 columns: ID,c1,c2
var matrix = [
[ 1, 5871, 8916]
];
// console.log(matrix)
var matrix2 = [
[ 1, 21, 800]
];
function rand_it(x){
return Math.floor((Math.random() * x) + 1);
}
function render(matrix){
var t = d3.transition()
.duration(300);
// remove
svg.selectAll("g.valgroup")
.remove();
svg.selectAll("rect")
.transition(t)
.remove();
var remapped =["c1","c2"].map(function(dat,i){
return matrix.map(function(d,ii){
return {x: ii, y: d[i+1] };
})
});
console.log("NEW ONE !!!\n",matrix[0]);
// console.log("LAYOUT---------------------------");
var stacked = d3.layout.stack()(remapped)
x.domain(stacked[0].map(function(d) { return d.x; }));
y.domain([0, d3.max(stacked[stacked.length - 1], function(d) { return d.y0 + d.y; })]);
// Add a group for each column.
var valgroup = svg.selectAll("g.valgroup")
.data(stacked)
.enter().append("svg:g")
.classed("valgroup", true)
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// Add a rect for each date.
var rect = valgroup.selectAll("rect")
.data(function(d){return d;})
.enter().append("svg:rect")
.transition(t)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
// column
rect.selectAll("rect")
.transition() // this is to create animations
.duration(500) // 500 millisecond
.ease("bounce")
.delay(500)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
};
render(matrix);
setInterval( function() { render([[1, rand_it(10), rand_it(50)]]); console.log("2"); }, 5000 );
</script>
</body>
</html>
You are not using the transition() correctly. A transition changes from a previous value to a final value. So, in this code:
var something = svg.append("something").attr("x", 10);
something.transition().duration(500).attr("x", 20);
The x attribute of something will change from 10 to 20 in 500ms.
But when you do, as you did:
var rect = valgroup.selectAll("rect")
.data(function(d){return d;})
.enter().append("svg:rect")
.transition(t)
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
Where are the previous values? This is an "enter" selection. To make things more complicated, you did:
svg.selectAll("rect")
.transition(t)
.remove();
In the beginning of the function, so, there is no rectangle to make any transition.
I made a few changes in your code, removing the remove() and creating some "update" selections: https://jsfiddle.net/gerardofurtado/3ahrabyj/
Please have in mind that this is not an optimised code, even less a beautiful code: I made just the bare minimum changes to make the transitions to work, you'll have to make a lot of improvements here.
I am making an interactive tool for creating Sunburst diagrams like this one with d3.js, svg and JQuery. The code for drawing the diagram is from that page, with a few minor modifications. I'm trying to draw text labels on the sections of the diagram, but although the elements are showing up in the Web Inspector (Chrome), they aren't visible on screen. I have tried to adapt code from here, and to some extent this has worked (Web Inspector says the elements exist), but I am mystified as to why the elements themselves don't show up. This is my code - the section for drawing labels is near the bottom. I would just use the code from the example page with labels, but the layout is very different and I'd have to start from scratch again.
var width = 850,
height = 850,
radius = Math.min(width, height) / 2;
var svg = d3.select("#vis-wrap")
.insert("svg", "*")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height * 0.52 + ")");
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); });
var path = svg.datum(data).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", function(d) {return d.color;} )
.style("fill-rule", "evenodd")
.each(stash);
// Problem here
path.insert("text", "*")
.attr("transform", function(d) { return "rotate(" + (d.x + d.dx / 2 - Math.PI / 2) / Math.PI * 180 + ")"; })
.attr("x", function(d) { return Math.sqrt(d.y); })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d) { return d.name; });
d3.selectAll("input[name=mode]").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(1500)
.attrTween("d", arcTween);
});
// Stash the old values for transition.
function stash(d) {
d.x0 = d.x;
d.dx0 = d.dx;
}
// Interpolate the arcs in data space.
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);
};
}
d3.select(self.frameElement).style("height", height + "px");
You're making the text a child of the path i.e.
<path ...>
<text>something</text>
</path>
I'm afraid that's not valid. You need to make the text element a sibling.
Confusingly you've called the <g> element you've created svg but it want's to be a child of that i.e.
svg.insert("text")
rather than path.insert("text")