最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Group each rect and text in D3 - Stack Overflow

programmeradmin0浏览0评论

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.

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.

Share Improve this question edited Dec 16, 2016 at 23:11 iheartcsharp asked Dec 16, 2016 at 22:59 iheartcsharpiheartcsharp 1,3091 gold badge15 silver badges22 bronze badges 1
  • 2 what d3 code do you have so far? – Robert Longson Commented Dec 16, 2016 at 23:02
Add a comment  | 

2 Answers 2

Reset to default 13

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...

I use group "g" to deal with this problem: Every pair of bar and label is stored in one group. Every time you click on one group, execute the sorting function on both the label and the bar.

var w = 600;
var h = 250;

var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
				11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];

var xScale = d3.scale.ordinal()
				.domain(d3.range(dataset.length))
				.rangeRoundBands([0, w], 0.05);

var yScale = d3.scale.linear()
				.domain([0, d3.max(dataset)])
				.range([0, h]);


var svg = d3.select("body")
			.append("svg")
			.attr("width", w)
			.attr("height", h);


var groups = svg.selectAll("g")
      .data(dataset)
      .enter()
      .append("g");


groups.append("rect")
   .attr("x", function(d, i) {
   		return xScale(i);
   })
   .attr("y", function(d) {
   		return h - yScale(d);
   })
   .attr("width", xScale.rangeBand())
   .attr("height", function(d) {
   		return yScale(d);
   })
   .attr("fill", function(d) {
		return "rgb(0, 0, " + (d * 10) + ")";
   })
   .on("mouseover", function() {
   		d3.select(this)
   			.attr("fill", "orange");
   })
   .on("mouseout", function(d) {
	   d3.select(this)
	   		.transition()
	   		.duration(250)
			.attr("fill", "rgb(0, 0, " + (d * 10) + ")");
   })
   ;


 groups.append("text")
    .text(function(d) {
       return d;
    })
    .attr("text-anchor", "middle")
    .attr("x", function(d, i) {
       return xScale(i) + xScale.rangeBand() / 2;
    })
    .attr("y", function(d) {
       return h - yScale(d) + 14;
    })
    .attr("font-family", "sans-serif")
    .attr("font-size", "11px")
    .attr("fill", "white");
    groups.on("click", function(){
      sortBars();
    })
    ;


var sortBars = function() {
  svg.selectAll("rect")
     .sort(function(a, b) {
       return d3.ascending(a, b);
      })
     .transition()
     .duration(1000)
     .attr("x", function(d, i) {
        return xScale(i);});


  svg.selectAll("text")
     .sort(function(a, b) {
       return d3.ascending(a, b);
      })
     .transition()
     .duration(1000)
     .attr("x", function(d, i) {
        return xScale(i) + xScale.rangeBand() / 2;
     });

};
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

发布评论

评论列表(0)

  1. 暂无评论