I'm trying to animate the update of a D3 chart where I have rectangles with wrapped text inside them. If I do this without a transition, everything functions as expected. When I add a transition though, the text does not wrap at all. It looks like it would if the wrap function was never called.
To make things weirder, if I step through the debugger, I can see that is in fact going into the wrap function. At the end of the wrap function, the displayed result actually looks as it should. However, once I step out of the function and back into the D3 library code, it reverts back to the unwrapped view.
My best guess here is that the wrap function takes a while and causing some sort of issue with the transition, but I'm not sure.
Here are the relevant snippits of the redraw
function, which gets called when I want to update the page:
MyChart.prototype.redraw = function(taskList) {
var that = this;
var svg = d3.select("svg");
var chart = svg.select(".chart");
var blocks = chart.selectAll(".block")
.data(myData, this.keyFunction);
blocks.transition()
.attr("transform", function(d) {
return rectTransform(d, that.xScale, that.yScale);
})
.attr("height", function(d) {
return that.yScale.bandwidth() - GRIDLINE_WIDTH;
})
.attr("width", function(d) {
return Math.max(that.xScale(new Date(d.date).addDays(1)) -
that.xScale(new Date(d.date)) -
GRIDLINE_WIDTH, 0);
});
blocks.exit().remove();
// update block labels
var blockLabels = svg.selectAll('.blockLabel')
.data(myData, this.keyFunction);
blockLabels.transition()
.attr('visibility', function(d) {
if (new Date(d.date) < that.xScale.domain()[0] ||
new Date(d.date) >= that.xScale.domain()[1])
return 'hidden';
return 'visible';
})
.attr("transform", function(d) {
return rectLabelTransform(d, that.xScale, that.yScale);
})
.text(function(d) {
return getBlockText(d);
})
// 50 pixels for now, later will update to actual rect width
.call(wrap, 50);
return this;
}
And here is the wrap
function, taken from this Mike Bostock example :
function wrap(text, width) {
text.each(function(d) {
var text = d3.select(this);
// quickly ignore short labels
if (text.text().length < 10) {
text.attr('dy', '0.35em');
return;
}
var words = text.text().split(/\s+/).reverse();
var word;
var line = [];
var lineNumber = 0;
var lineHeight = 0.9; // ems
var y = text.attr("y");
var dy = parseFloat(text.attr("dy"));
var tspan = text.text(null)
.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", dy + "em");
while (!!(word = words.pop())) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan")
.attr("x", 0)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
// re-center if only one line
if (lineNumber < 1) tspan.attr('dy', '0.35em');
});
}
I'm thinking that I could try improving the speed of the wrap function, or, worst-case, just ditch the animations. But I'm curious as to what the specific issue is..
EDIT--------
Mark's answer did help, however when I change .call(wrap, 200)
to .call(wrap, function(d) {return 200;})
it breaks again. I'm assuming this is timing thing, but this behavior seems pretty strange to me that such a small change could have such a large impact. Any ideas?
Your wrap
function is being called within the transition. I think you really mean this:
blockLabels.transition()
.text(function(d) {
return getBlockText(d);
})
.call(wrap, 50)
.attr('visibility', function(d) {
if (new Date(d.date) < that.xScale.domain()[0] ||
new Date(d.date) >= that.xScale.domain()[1])
return 'hidden';
return 'visible';
})
.attr("transform", function(d) {
return rectLabelTransform(d, that.xScale, that.yScale);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.