I am creating a bar graph using d3.js. On the on top of each bar I will display some text. When the user hovers over the bar it should show the text. When they hover out the text will disappear. In order to do that I need to group the <text>
and <rect>
elements inside of a <g>
element.
Example
<g class="gbar">
<rect x="0" y="50" width="10" height="50" />
<text x="15" y="40">A</text>
</g>
<g class="gbar">
<rect x="11" y="75" width="10" height="25" />
<text x="16" y="65">B</text>
</g>
<g class="gbar">
<rect x="22" y="25" width="10" height="75" />
<text x="27" y="35">C</text>
</g>
So this way, I can do a .gbar:hover rect, .gbar:hover text { ... }
CSS style to change the color and opacity of both the <rect>
and <text>
elements. For each data item, how can I put the <rect>
and <text>
elements in a <g>
element using d3.js?
Thanks
EDIT: To add more context, this is what I have so far...
var svg = d3.select('.mygraph')
.append('svg')
.attr('height', 100);
svg.selectAll('rect')
.data(dataSet)
.enter()
.append('rect')
.attr('x', calcX)
.attr('y', calcY)
.attr('width', 10)
.attr('height', calcH);
svg.selectAll('text')
.data(dataSet)
.enter()
.append('text')
.text(function (d) {
return d.Text;
})
.attr('x', textX)
.attr('y', textY);
That code produces:
<svg>
<rect x="0" y="50" width="10" height="50" />
<rect x="11" y="75" width="10" height="25" />
<rect x="22" y="25" width="10" height="75" />
<text x="15" y="40">A</text>
<text x="16" y="65">B</text>
<text x="27" y="35">C</text>
</svg>
I am still very new to d3.js.
select selects the first matching element whilst d3. selectAll selects all matching elements. Both functions take a string as its only argument. The string specifies which elements to select and is in the form of a CSS selector string (e.g. div.
The <g> SVG element is a container used to group other SVG elements. Transformations applied to the <g> element are performed on its child elements, and its attributes are inherited by its children. We can create a group element with D3. js by appending a g element using any selection.
With the help of d3. group() method, we can group the iterable data structure into a map where the key is defined as the element from iterable and values as an array. Return value: It returns the map having key as element and value as an array.
selectAll() function in D3. js is used to select all the element that matches the specified selector string. Parameters: This function accepts single parameter HTML tag as a parameter. Return Value: This function returns the selected elements.
This is the standard approach.
First, append the <g>
elements using an "enter" selection:
var groups = svg.selectAll(".groups")
.data(dataset)
.enter()
.append("g")
.attr("class", "gbar");
Then, use that selection to append both your rectangles and your texts:
groups.append('rect')
.attr('x', calcX)
.attr('y', calcY)
.attr('width', 10)
.attr('height', calcH);
groups.append('text')
.text(function (d) {
return d.Text;
})
.attr('x', textX)
.attr('y', textY);
Doing that, your rectangles and texts will be, each pair, inside the same <g>
element.
Here is a simple demo (a very simple code, full of magic numbers). Hover over the bars or the texts:
var data = d3.range(8).map(()=>~~(Math.random()*130));
var svg = d3.select("svg")
var groups = svg.selectAll(".groups")
.data(data)
.enter()
.append("g")
.attr("class", "gbar");
groups.append("rect")
.attr("x", (d,i)=> i*40)
.attr("width", 20)
.attr("y", d=> 150 - d)
.attr("height", d=> d)
.attr("fill", "teal");
groups.append("text")
.attr("x", (d,i)=> i*40)
.attr("y", d=> 145 - d)
.text(d=>d)
.gbar:hover rect{
fill:brown;
}
.gbar:hover text{
fill:brown;
font-weight:700;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
If you inspect the SVG created by this snippet, this is what you get:
<g class="gbar">
<rect x="0" width="20" y="142" height="8" fill="teal"></rect>
<text x="0" y="137">8</text>
</g>
<g class="gbar">
<rect x="40" width="20" y="136" height="14" fill="teal"></rect>
<text x="40" y="131">14</text>
</g>
<g class="gbar">
<rect x="80" width="20" y="89" height="61" fill="teal"></rect>
<text x="80" y="84">61</text>
</g>
//etc...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With