Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group each rect and text in D3

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.

like image 409
iheartcsharp Avatar asked Dec 16 '16 22:12

iheartcsharp


People also ask

What do the select () and selectAll () functions in d3 do?

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.

Can we group SVG elements in d3js?

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.

What does d3 group do?

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.

What does d3 selectAll return?

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.


1 Answers

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...
like image 95
Gerardo Furtado Avatar answered Oct 03 '22 16:10

Gerardo Furtado