简体   繁体   中英

How can I get “call” to execute for each data element in D3?

Using D3, I'm trying to implement a word wrap plugin for each quotation displayed from myData. The call function on the last line is that.

The problem is that it only works for the first quote. It makes the all other quotes not appear. I'm not sure how to structure the call to happen while enter() would typically renders thing.

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))

You want selection.each() rather than selection.call(). Selection.call will will invoke a function just once, while .each will invoke it for each datum:

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...

Compare to:

selection.call(function[, arguments…]) <>

Invokes the specified function exactly once, passing in this selection along with any optional arguments.

( API Documentation (v4, but both methods exist in v3))

See the following snippet for a comparison of both:

 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> 

To call this function once on each item, you could use .call within the .each. I've used ag to place the text, so that the tspans this utility creates are positioned correctly (otherwise they overlap). The following snippet otherwise uses your code (the word wrap utility is on top as I could not find a cdn for it quickly enough):

 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> 

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM