D3 - How to associate the same data with multiple objects?

I'm trying to draw multiple shapes using the same data in the selection, so let's say that I have:

myData = [ { shape: 'rect', attr: { width: 100, height: 100, x: 100, y:100 } } , { shape: 'circle', attr: {cx, cy, etc...} } ] node.selectAll('*').data([myData]); myData.obj.forEach(function(obj) { // Append different shapes based on data var shape = node.enter().append(obj.shape); Object.keys(obj.attrs).forEach(function(attr) { // Bind attrs to shapes based on data shape.attr(attr, obj.attrs[attr]); }); }); 

Here node is an element of 'g', myData is a single data object. My goal is to change the child shapes inside g based on myData, so later, if I connect another myData and call this function again, they can be updated. But I believe that somehow myData is only bound to the first form added. Is there a way to easily bind the same data to multiple forms?

+4
source share
3 answers

Maybe you need the .datum() function in d3. One of its specific use cases is to bind the same date to multiple DOM elds (i.e. Bind one date to the entire d3 selection).

For example, d3.selectAll('div').datum({foo: 'bar'}) will associate the same object {foo: 'bar'} with all the <div>...</div> elements existing in the document.

Quoting directly from https://github.com/mbostock/d3/wiki/Selections#datum

selection.datum([value]) ... If value is specified, sets the element bound data to the specified value for all selected elements. If value is a constant, all elements are given the same data [sic]

(Ironically, he refers to a constant datum as "data" in the explanation of the .datum () function!)

However, this is the literal answer to your question; there may be a more constructive answer to your question that might explain the β€œregular” d3 way of handling your overall goal ... In this case, you should probably consult some tutorials, for example

http://mbostock.imtqy.com/d3/tutorial/circle.html

+2
source

I would create a g element to write to myData :

 groups = d3.select('body').append('svg') .selectAll('g').data(myData).enter() .append('g'); 

and add shapes to these elements of the group individually:

 groups.append('rect') groups.append('circle') 
+2
source

TL; DR;

Use the function of the argument "key" Selection.data.

A key function can be specified to control which data item is assigned to which item "This function is evaluated for each selected item, in order, [...] The key function is then also evaluated for each new data item, [...] returned The string is a data key.

(Search for "If the key function is not specified ...")

More details ...

D3 binds data to elements. By default, the join-by-index method is used (the first element found is mapped to a datum with index 0, etc.). If joining by index is not enough for proper identification of elements, you should use the Selection.data key so that D3 properly synchronizes the input data set at the rendering stages: update (the result of calling the data () method), creating a selection input, "delete" (exit the selection).

Let's say we need to draw a legend, given the following data set ...

 const dataSet = [ [ 15, "#440154" ] [ 238.58, "#414487" ] // ... ] 

first we decided to draw a colored square using the <rect> element.

 const updateSelection = d3.select('rect').data(dataSet); // join-by-index strategy is enough here so there is no need to supply the key fn arg // Key function could be 'd => d[0]' (given data source cannot produce two entries // with value at index 0 being the same, uniqness is garanteed) updateSelection.enter() .append('rect') .attr('width', 15).attr('height', 15) .merge(updateSelection) .style('fill', d => d[1]) ; // Dispose outdated elements updateSelection.exit().remove(); 

Now we need to draw a <text> element for each given data element to visually represent the numerical values. Saving the connection strategy by index (by default) will force D3 to draw both rectangular and text elements first, but since only one element can be attached to a specific data key, only the first element found will be taken into account during the update phase, and any other element having the same data key will be at the end of the selection and will be removed from the DOM as soon as the Selection removal method is called.

... If several elements have the same key, duplicate elements are placed in the output selection ...

The solution is to combine the numeric value with the nodeName element.

 // Notice how the selector has changed const updateSelection = d3.select('rect, text').data(dataSet, function(d) { // Concatenate the numeric value with the element nodeName return '${d[0]}:${this.nodeName}'; }) , enterSelection = updateSelection.enter() ; // Add rect element enterSelection .append('rect').attr('width', 15).attr('height', 15) .merge(updateSelection) .style('fill', d => d[1]) ; // Add text label enterSelection .append('text') .merge(updateSelection) .text(d => d[0]) ; // Garbage collection updateSelection.exit().remove(); 
0
source

Source: https://habr.com/ru/post/1492153/


All Articles