score:5
In your solution:
x.append('dt')
.text(d=>d[0]);
x.append('dd')
.text(d=>d[1]);
All elements appended with an enter().append()
cycle are appended to the parent, in the order they are appended, which for you runs like this: first all the dt
s, then all the dd
s, as you have seen. The placeholder nodes (these are not the appended elements) created by the enter statement do not nest children in a manner it appears you might expect them to.
Despite the fact that d3 doesn't include methods to achieve what you are looking for with methods as easy as a simple selection.append()
method, the desired behavior can be achieved fairly easily with standard d3 methods and an extra step or two. Alternatively, we can build that functionality into d3.selection ourselves.
For my answer I'll finish with an example that uses your data structure and enter pattern, but to start I'll simplify the nesting here a bit - rather than a nested append I'm just demonstrating several possible methods for appending ordered siblings. To start I've also simplified the data structure, but the principle remains the same.
The first method might be the most straightforward: using a selection.each()
function. With the enter selection (either with a parent or the entered placeholders), use the each method to append two separate elements:
var data = [
{name:"a",description:"The first letter"},
{name:"b",description:"The second letter"}
];
d3.select("body")
.selectAll(null)
.data(data)
.enter()
.each(function(d) {
var selection = d3.select(this);
// append siblings:
selection.append("dt")
.html(function(d) { return d.name; });
selection.append("dd")
.html(function(d) { return d.description; })
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
But, perhaps a more elegant option is to dig into d3.selection() and toy with it to give us some new behaivor. Below I've added a selection.appendSibling()
method which lets you append a paired sibling element immediately below each item in a selection:
d3.selection.prototype.appendSibling = function(type) {
var siblings = this.nodes().map(function(n) {
return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
})
return d3.selectAll(siblings).data(this.data());
}
It takes each node in a selection, creates a new paired sibling node (each one immediately after the original node in the DOM) of a specified type, and then places the new nodes in a d3 selection and binds the data. This allows you to chain methods onto it to style the element etc and gives you access to the bound datum. See it in action below:
// modify d3.selection so that we can append a sibling
d3.selection.prototype.appendSibling = function(type) {
var siblings = this.nodes().map(function(n) {
return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
})
return d3.selectAll(siblings).data(this.data());
}
var data = [
{name:"a",description:"The first letter"},
{name:"b",description:"The second letter"}
];
d3.select("body")
.selectAll(null)
.data(data)
.enter()
.append("dt")
.html(function(d) { return d.name; })
.appendSibling("dd") // append siblings
.html(function(d) { return d.description; }) // modify the siblings
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Of course it is probably wise to keep the siblings in separate selections so you can manage each one for updates/entering/exiting etc.
This method is very easily applied to your example, here's a nested solution using data that is structured like you expect and the appendSibling method:
// modify d3.selection so that we can append a sibling
d3.selection.prototype.appendSibling = function(type) {
var siblings = this.nodes().map(function(n) {
return n.parentNode.insertBefore(document.createElement(type), n.nextSibling);
})
return d3.selectAll(siblings).data(this.data());
}
var data = [
{volumeInfo: {"a":1,"b":2,"c":3}},
{volumeInfo: {"α":1,"β":2}}
]
var items = d3.select("body")
.append('ol')
.selectAll('li')
.data(data)
.enter()
.append('li')
.append('dl')
.selectAll()
.data(d=>Object.entries(d.volumeInfo)).enter();
var dt = items.append("dt")
.text(function(d) { return d[0]; })
var dd = dt.appendSibling("dd")
.text(function(d) { return d[1]; })
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
score:0
Example for data
would be useful. But instead of appending to x
, have you tried appending directly to dt
itself?
x.append('dt').text(d=>d[0]).append('dd')
score:1
Here is a possibility using the .html
appender (instead of .append
):
var data = [
{ "volumeInfo": { "key1": "value1", "key2": "value2" }, "some": "thing" },
{ "volumeInfo": { "key3": "value3", "key4": "value4", "key5": "value5" } }
];
d3.select("body")
.append('ol')
.selectAll('li')
.data(data)
.enter()
.append('li')
.append('dl')
.html( function(d) {
// Produces: <dt>key1</dt><dd>value1</dd><dt>key2</dt><dd>value2</dd>
return Object.entries(d.volumeInfo).map(r => "<dt>" + r[0] + "</dt><dd>" + r[1] + "</dd>").join("");
});
dt { float: left; width: 100px; }
dd { margin-left: 100px; }
<script src="https://d3js.org/d3.v5.min.js"></script>
which produces this tree:
<ol>
<li>
<dl>
<dt>key1</dt>
<dd>value1</dd>
<dt>key2</dt>
<dd>value2</dd>
</dl>
</li>
<li>
<dl>
<dt>key3</dt>
...
</dl>
</li>
</ol>
Note that this is not exactly in the spirit of d3 and makes it difficult to work with appended children (adding class, style, other children, ...).
Source: stackoverflow.com
Related Query
- How do I create a tree layout using JSON data in d3.v4 - without stratify()
- how to create labels for data in donut chart using d3.js
- How to create a choropleth of the world using d3?
- how to create multiline chart using dc.js
- How do I create a <dl> using d3.js
- How to create a responsive map using d3
- How to create a histogram using d3.js and crossfilter data?
- How to create correlogram using D3 as in the example picture
- How do I create a minimap of an SVG using D3 v5 and show the current viewport dimensions?
- How to create a flow layout in SVG using D3.js?
- how to create pie chart using dc.js
- How to create vertically grouped bar chart in d3.js using json data?
- How do I create a multiline chart using d3js with json formatted for nvd3?
- How to create a stacked bar chart using dc.js?
- How to create d3 graph using data from Rails database
- How to create a line break in an HTML element using D3.js
- How to create responsive svg using d3.js
- How to create a stacked barchart using d3?
- How to create a % difference arrow line with value in a bar chart using D3.js
- How so create complex SVG shapes using D3JS?
- How to create SVG with grid lines using D3JS
- How to create multi-polygon intersecting a circle / necklace using d3.js?
- How to create a javascript function using Scala.js?
- How to create a graph like StackOverflow reputation graph using d3.js?
- How to dynamically create append svg line using d3js?
- How to create a heatmap with numbers using Leaflet map?
- How to create bubble charts using NVD3
- Using D3js, how can I create a flare.json structure from my database?
- D3.js Heatmap: How to read from a nested json and create a Heatmap using D3
- Using d3, how can I create a histogram or bar plot where the last bar is the count of all values greater than some number?
More Query from same tag
- Tooltip fetching incorrect data
- Iterating through multi-dimensional arrays with d3.js
- Formatting nvd3 line chart axis
- generate D3 html pages with R?
- D3: hide voronoi strokes that fall 'in the sea'
- How to set count to zero for missing keys in D3 nest()
- d3.js place holder graphic when dragging the SVG element
- D3: How to define responsibility text?
- How to display sum total for currently selected series in NVD3.js Pie Chart?
- Issue highlighting node in d3 network with jQuery datepicker
- Is it ever beneficial to generate layout of an html page in excel as oppose to creating in css?
- React and d3 Importing data in react Component - Cannot read property 'length' of undefined
- htmlwidgets: TypeError: results is undefined
- Gradient smoothing in a long SVG object
- Resetting zooming properties d3
- Unable to add grid lines to bar chart
- d3.js data not bound the first time
- How to allow the browser to redirect to another page when clicked on each of a country in the map?
- Appending lines to D3 bar chart - absolutely nothing happens
- Issue styling a d3 js tree chart in a DIV
- labels inside the heatmap rects
- Problems displaying table inside a shape in d3.js
- bar chart not coinciding with axes in d3.js
- Export standalone offline html plot of matplotlib figures using mpld3
- How to create semi circle with d3.shape that start at 9pm and ends at 6am
- cubism.js last hour axis
- Not able to parse Date in unix time format
- Dots of Scatterplot in d3 are not rendering
- make axis of radar chart conditional to existence of value
- How to have a text label on links in d3 force directed graphs