如何让 "call" 对 D3 中的每个数据元素执行?
How can I get "call" to execute for each data element in D3?
我正在尝试使用 D3 为 myData 中显示的每个引文实现一个自动换行插件。最后一行的调用函数就是那个。
问题是它只适用于第一个报价。它使所有其他引号不出现。我不确定如何构造在 enter() 通常会呈现内容时发生的调用。
var quote=svg.selectAll("text.quote").data(myData);
quote.exit().remove()
quote.enter().append("text")
quote
.attr("class","quote")
.attr("x", function (d,i){ return xScale(i);})
.attr("y", function(d){ return yScale(d.y);})
.text(function(d, i){return d.quote;})
.call(d3.util.wrap(125))
您需要 selection.each() 而不是 selection.call()。 Selection.call 将只调用一次函数,而 .each 将为每个数据调用它:
selection.each(function) <>
Invokes the specified function for each selected element, in order,
being passed the current datum (d), the current index (i), and the
current group (nodes), with this as the current DOM element
(nodes[i]). This method can be used to invoke arbitrary code for each
selected element...
比较:
selection.call(function[, arguments…]) <>
Invokes the specified function exactly once, passing in this selection
along with any optional arguments.
(API Documentation (v4, 但两种方法都存在于 v3))
请参阅以下代码段以比较两者:
var data = [10,20,30,40];
var selection = d3.select("body").selectAll(null)
.data(data)
.enter()
.append("p")
.each(function(d) {
console.log("each: " + d); // d is datum
})
.call(function(d) {
console.log("call: ")
console.log(d.data()); // d is selection
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
要对每个项目调用一次此函数,您可以在 .each 中使用 .call。我使用 g 来放置文本,以便此实用程序创建的 tspan 位置正确(否则它们会重叠)。以下代码段以其他方式使用您的代码(自动换行实用程序位于顶部,因为我无法足够快地找到它的 cdn):
d3.util = d3.util || {};
d3.util.wrap = function(_wrapW){
return function(d, i){
var that = this;
function tspanify(){
var lineH = this.node().getBBox().height;
this.text('')
.selectAll('tspan')
.data(lineArray)
.enter().append('tspan')
.attr({
x: 0,
y: function(d, i){ return (i + 1) * lineH; }
})
.text(function(d, i){ return d.join(' '); })
}
function checkW(_text){
var textTmp = that
.style({visibility: 'hidden'})
.text(_text);
var textW = textTmp.node().getBBox().width;
that.style({visibility: 'visible'}).text(text);
return textW;
}
var text = this.text();
var parentNode = this.node().parentNode;
var textSplitted = text.split(' ');
var lineArray = [[]];
var count = 0;
textSplitted.forEach(function(d, i){
if(checkW(lineArray[count].concat(d).join(' '), parentNode) >= _wrapW){
count++;
lineArray[count] = [];
}
lineArray[count].push(d)
});
this.call(tspanify)
}
};
var wrap = d3.util.wrap(11);
var svg = d3.select("body")
.append("svg")
.attr("height",400)
.attr("width",400);
var myData = ["text 1","text 2","text 3"]
var quote = svg.selectAll("text.quote").data(myData);
quote.enter().append("g")
quote.attr("class","quote")
.attr("transform", function (d,i){ return "translate(20," + (i * 40 + 20) + ")" })
.append("text")
.text(function(d, i){return d})
.each(function() {
d3.select(this).call(d3.util.wrap(11));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
我正在尝试使用 D3 为 myData 中显示的每个引文实现一个自动换行插件。最后一行的调用函数就是那个。
问题是它只适用于第一个报价。它使所有其他引号不出现。我不确定如何构造在 enter() 通常会呈现内容时发生的调用。
var quote=svg.selectAll("text.quote").data(myData);
quote.exit().remove()
quote.enter().append("text")
quote
.attr("class","quote")
.attr("x", function (d,i){ return xScale(i);})
.attr("y", function(d){ return yScale(d.y);})
.text(function(d, i){return d.quote;})
.call(d3.util.wrap(125))
您需要 selection.each() 而不是 selection.call()。 Selection.call 将只调用一次函数,而 .each 将为每个数据调用它:
selection.each(function) <>
Invokes the specified function for each selected element, in order, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i]). This method can be used to invoke arbitrary code for each selected element...
比较:
selection.call(function[, arguments…]) <>
Invokes the specified function exactly once, passing in this selection along with any optional arguments.
(API Documentation (v4, 但两种方法都存在于 v3))
请参阅以下代码段以比较两者:
var data = [10,20,30,40];
var selection = d3.select("body").selectAll(null)
.data(data)
.enter()
.append("p")
.each(function(d) {
console.log("each: " + d); // d is datum
})
.call(function(d) {
console.log("call: ")
console.log(d.data()); // d is selection
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
要对每个项目调用一次此函数,您可以在 .each 中使用 .call。我使用 g 来放置文本,以便此实用程序创建的 tspan 位置正确(否则它们会重叠)。以下代码段以其他方式使用您的代码(自动换行实用程序位于顶部,因为我无法足够快地找到它的 cdn):
d3.util = d3.util || {};
d3.util.wrap = function(_wrapW){
return function(d, i){
var that = this;
function tspanify(){
var lineH = this.node().getBBox().height;
this.text('')
.selectAll('tspan')
.data(lineArray)
.enter().append('tspan')
.attr({
x: 0,
y: function(d, i){ return (i + 1) * lineH; }
})
.text(function(d, i){ return d.join(' '); })
}
function checkW(_text){
var textTmp = that
.style({visibility: 'hidden'})
.text(_text);
var textW = textTmp.node().getBBox().width;
that.style({visibility: 'visible'}).text(text);
return textW;
}
var text = this.text();
var parentNode = this.node().parentNode;
var textSplitted = text.split(' ');
var lineArray = [[]];
var count = 0;
textSplitted.forEach(function(d, i){
if(checkW(lineArray[count].concat(d).join(' '), parentNode) >= _wrapW){
count++;
lineArray[count] = [];
}
lineArray[count].push(d)
});
this.call(tspanify)
}
};
var wrap = d3.util.wrap(11);
var svg = d3.select("body")
.append("svg")
.attr("height",400)
.attr("width",400);
var myData = ["text 1","text 2","text 3"]
var quote = svg.selectAll("text.quote").data(myData);
quote.enter().append("g")
quote.attr("class","quote")
.attr("transform", function (d,i){ return "translate(20," + (i * 40 + 20) + ")" })
.append("text")
.text(function(d, i){return d})
.each(function() {
d3.select(this).call(d3.util.wrap(11));
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>