I am having trouble creating a group g, along with two child SVG components (text and rect) for each data entry in a 1D array.
allCorrespondingYValues is an array like [1,2,3,4]
selection.selectAll("g.y-crosshair-tooltip").data(allCorrespondingYValues)
.join('g')
.attr("class", "y-crosshair-tooltip")
.attr("transform", d => "translate(" + (width - margin.right) + "," + (yScale(d)) + ")")
//.select("text").join('text') // Method 1: Nothing appears, just 1 'g' per data
//.join("text") // Method 2: Nothing appears, just 1 'g' per data
//.append("text") // Method 3: this will continuously append a new text element inside the parent 'g' every time the crosshair moves and the function this code is contained in is called
//.selectAll("text").data(d => d).join("text") // Method 4: Throws errors.
.selectAll("text").data([null]).join("text") // Method 5: This works and creates only 1 child text element for the 'g', but the text is always null because its referencing the null dataset, not the parent dataset.
.attr("dx", -15) // position relative to its group
.attr("dy", -15)
.attr("fill", "black")
.text(d => "$" + d)
The four methods I tried are in the code above, and the comments next to each explains the problems with them. I am most surprised that Method 1 does not work, because Mike's Selection guide mentions that "select also propagates data from parent to child, whereas selectAll does not" and "Data is bound to elements... Inherited from a parent via append, insert, or select." So I would have expected that by using .select("text").join('text')
, I could just reference the data from the parent. Instead, the resulting DOM shows that nothing is added to the parent 'g'.
So my two questions are...
I have found a couple similar stackoverflow questions, but most are older and use enter() instead of join(), or have 2D data arrays, so things like Method 4 would work... whereas for me, I am trying to reference the exact same data from parent to child.
Thank you!
You are attempting to use the "short-hand" version of join
which just isn't suitable for your purpose and your attempts just complicate the code. Instead, use the regular version where you can specify explicit functions:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.js"></script>
</head>
<body>
<svg></svg>
<script>
d3.select("svg")
.attr("width", 300)
.attr("height", 300)
.selectAll("g")
.data([1,2,3,4])
.join(
(enter) => {
const g = enter.append("g")
.attr("transform", (d, i) => "translate(" + (i * 16) + ", 20)");
g.append("text")
.text(d => d);
//<-- append more to the g here...
});
</script>
</body>
</html>