作为d3.treemap()
的一部分:
在svg
元素中嵌套了groups
。每个组都有一个rect
和text
,其中一个孩子是tspan
。
像这样:
<g><rect></rect><text><tspan>Text here</tspan></text></g>
treemap
具有动画效果,并且随着值的改变矩形的大小也随之变化。要求tspan
中的文本始终居中。文本元素的中心的计算如下:
const calculateCenterOfTextInRectangle = (tspanNode) => {
const rectangleNode = tspanNode.parentElement.previousSibling.previousSibling; // tspan is in text element and 2 nodes above is the rectangle
const centerX = (rectangleNode.getAttribute('width') / 2) - (tspanNode.getComputedTextLength() / 2);
const centerY = (rectangleNode.getAttribute('height') / 2) + (19 / 2); // 19 is the font-size in pixel
return {centerX: centerX,
centerY: centerY}; };
如果矩形的height
和width
不变,则可以正常工作。但是用户可以选择其他选项,该选项会更改矩形的大小并触发此d3.transition()
:
treemap(root.sum(sum)); // new values
cell.transition()
.duration(750)
.attr('transform', (d) => 'translate(' + d.x0 + ',' + d.y0 + ')')
.selectAll('rect')
.attr('width', (d) => d.x1 - d.x0)
.attr('height', (d) => d.y1 - d.y0);
这不会更改需要更改的文本的位置-因此,我提出了一个临时解决方案:
setInterval(
() => {
cell.selectAll('tspan')
.attr('x', function() { return calculateCenterOfTextInRectangle(this).centerX; }) // center x and y. Not using Es6 function because of this context which is the tspan element.
.attr('y', function() { return calculateCenterOfTextInRectangle(this).centerY; });
},
0.1
);
问题是使用setInterval
方法时Web应用程序的响应速度较慢。是否可以在不使用transition
的情况下在setInterval
函数中实现文本居中?
答案 0 :(得分:2)
在过渡过程中使用calculateCenterOfTextInRectangle
的问题在于,即使在为矩形设置新值后调用它,也会得到 initial 值,即预期的行为。
让我们在此演示中看到它,检查控制台:
var svg = d3.select("svg");
var g = svg.append("g");
var rect = g.append("rect")
.attr("stroke", "black")
.attr("fill", "white")
.attr("x", 0)
.attr("y", 0)
.attr("width", 50)
.attr("height", 150);
var text = g.append("text")
.text("foo")
.attr("x", function() {
return calculateCenterOfTextInRectangle(this).centerX
})
.attr("y", function() {
return calculateCenterOfTextInRectangle(this).centerY
});
var gTransition = g.transition()
.duration(5000);
gTransition.select("rect")
.attr("width", 150)
.attr("height", 40);
gTransition.select("text")
.attr("x", function() {
console.log(calculateCenterOfTextInRectangle(this).centerX)
return calculateCenterOfTextInRectangle(this).centerX
})
.attr("y", function() {
console.log(calculateCenterOfTextInRectangle(this).centerY)
return calculateCenterOfTextInRectangle(this).centerY
})
function calculateCenterOfTextInRectangle(tspanNode) {
const rectangleNode = tspanNode.previousSibling;
const centerX = (rectangleNode.getAttribute('width') / 2) - (tspanNode.getComputedTextLength() / 2);
const centerY = (rectangleNode.getAttribute('height') / 2) + (19 / 2); // 19 is the font-size in pixel
return {
centerX: centerX,
centerY: centerY
};
};
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>
这里有不同的解决方案。可能不太需要计算机的工作只是将新的x
和y
值传递给文本,您可以轻松地计算出这些文本(因为您具有矩形的新值)。
但是,如果您想使用转换本身,则可以使用tween
(这会占用更多的计算机资源),如下所示:
transition.select("text")
.tween("positioning", function() {
var self = this;
var rectangleNode = this.previousSibling;
return function() {
d3.select(self)
.attr("x", (rectangleNode.getAttribute('width') / 2) - (self.getComputedTextLength() / 2))
.attr("y", (rectangleNode.getAttribute('height') / 2) + (19 / 2))
}
})
这是一个演示:
var svg = d3.select("svg");
var g = svg.append("g");
var rect = g.append("rect")
.attr("stroke", "black")
.attr("fill", "white")
.attr("x", 0)
.attr("y", 0)
.attr("width", 50)
.attr("height", 150);
var text = g.append("text")
.attr("x", function() {
return calculateCenterOfTextInRectangle(this).centerX
})
.attr("y", function() {
return calculateCenterOfTextInRectangle(this).centerY
})
.text("foo");
var gTransition = g.transition()
.duration(5000);
gTransition.select("rect")
.attr("width", 150)
.attr("height", 40);
gTransition.select("text")
.tween("positioning", function() {
var self = this;
var rectangleNode = this.previousSibling;
return function() {
d3.select(self)
.attr("x", (rectangleNode.getAttribute('width') / 2) - (self.getComputedTextLength() / 2))
.attr("y", (rectangleNode.getAttribute('height') / 2) + (19 / 2))
}
})
function calculateCenterOfTextInRectangle(tspanNode) {
const rectangleNode = tspanNode.previousSibling;
const centerX = (rectangleNode.getAttribute('width') / 2) - (tspanNode.getComputedTextLength() / 2);
const centerY = (rectangleNode.getAttribute('height') / 2) + (19 / 2); // 19 is the font-size in pixel
return {
centerX: centerX,
centerY: centerY
};
};
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg></svg>