d3.js在条形图中添加第二个标签

时间:2019-05-24 18:52:31

标签: javascript d3.js

第二部分问题:

我有一个使用多个数组创建的条形图。这些排列包含棒球队的获胜百分比;相关团队的颜色;和他们的名字。

我可以在图表上创建一组标签,名称或获胜百分比。但是,我不能同时将两者同时使用。见下文。 win%

Team names

我使用的代码是:

let WinsLabel = svgContainer.selectAll("text")
    .data(d3.zip(TeamArray, WinPercArray, Colours));    

WinsLabel.enter()
    .append("text")
        .attr("fill", "black")
        .attr("x", function(d, i) {
            return 45 + (i * 50);
        })
        .attr("y", 700)
        .transition()
        .duration(1000)
        .attr("x", function(d,i){
            return 70 + (i*50);
        })
        .attr("y", function(d){
            return 685 - d[1];
        })
        .attr("text-anchor","middle")
        .attr("font-family", "sans-serif")
        .attr("font-size", "15px")
        .attr("fill", "black")
        .text(function(d){
            return d[1]/10 + "%";
        });
let TeamLabel = svgContainer.selectAll("text")
    .data(d3.zip(TeamArray, WinPercArray, Colours));

TeamLabel.enter()
    .append("text")
        .attr("fill", "black")
        .attr("x", function(d, i) {
            return 45 + (i * 50);
        })
        .attr("y", 700)
        .transition()
        .duration(1000)
        .attr("x", function(d,i){
            return 70 + (i*50);
        })
        .attr("y", function(d){
            return 700 - d[1]/2;
        })
        .attr("text-anchor","middle")
        .attr("font-family", "sans-serif")
        .attr("font-size", "15px")
        .attr("fill", "white")
        .text(function(d){
            return d[0];
        });

当我同时使用两个脚本运行代码时,仅显示win%,但没有显示名称。为了显示名称,我必须删除第一个标签。

我的问题的两部分是:

  1. 如何让两组标签同时显示?
  2. 如何获取在矩形/条形中垂直排列的名称?

1 个答案:

答案 0 :(得分:1)

D3代表数据驱动的东西;它的核心原理是基于链接元素/选择和数据。设置数据(var selection = selectAll(...).data(...)时,您需要考虑以下3种情况:

  1. 某些现有元素可以链接到新数据中的某些项目。您使用selection
  2. 访问它们
  3. 某些元素无法链接到新数据中的任何项目。您使用selection.exit()
  4. 访问它们
  5. 新数据中的某些项目无法链接到所选内容中的任何元素。您可以使用selection.enter()
  6. 来访问它们

在最简单的情况下,数据和元素之间的链接是通过索引建立的,即选择中的第一个元素与数据数组中的第一项链接,第二个与第二个链接,依此类推。当且仅当(在此按索引的上下文中)该数据项的索引大于选择的大小时,d3才能找到该数据项的元素(=被放入.enter()选择中)。

在您的初始选择上

let WinsLabel = svgContainer.selectAll("text")
.data(d3.zip(TeamArray, WinPercArray, Colours));

选择为空,因为还没有文本标签。由于其为空,因此所有要创建的占位符都位于.enter()选择中。但是,在下次选择其他标签类型

let TeamLabel = svgContainer.selectAll("text")
 .data(d3.zip(TeamArray, WinPercArray, Colours));

选择的大小取决于所传递数据的大小,因此.enter()选择为空;包含所有旧元素(百分比标签TeamLabel标签)的text选择,但是它们的数据值已重新分配。


安德鲁(Andrew)提出了一种分配课程的解决方案,但就我个人而言,我会将与同一团队相关的所有元素都放在一个小组中。

var TeamArray = ["Yankees",  "Rays", "RedSox", "Jays","Orioles", "Twin", "Indians", "WhiteSox", "Detroit", "Royals", "Astros", "Rangers", "A's", "Angels","Mariners"];
var WinPercArray = [653, 609, 540, 400, 300, 667, 521, 458, 383, 347, 660, 511, 500, 458, 442];
var Colours = ["#003087", "#092C5C", "#BD3039", "#134A8E", "#DF4601", "#002B5C", "#0C2340", "#C4CED4", "#FA4616", "#BD9B60", "#EB6E1F", "#C0111F", "#003831", "#003263", "#005C5C"];

var data = d3.zip(TeamArray, WinPercArray, Colours);

var svg = d3.select('body').append('svg').attr('height', 300).attr('width', 800);

var teams = svg.selectAll('g.teams')
  .data(data);

var scale = d3.scaleLinear()
  .domain([0, 1000])
  .range([200, 0]);

var teamsEnter = teams.enter()
  .append('g')
  .classed('team', true)
  .attr('transform', function(d, i){
    return 'translate(' + (i*50) + ',0)';
  })
  
teamsEnter.append('rect')
   .attr('width', 50)
   .attr('y', function(d) { return scale(d[1]); })
   .attr('height', function(d) { return scale(0) - scale(d[1]); })
   .style('fill', function(d) { return d[2]; });
   
teamsEnter.append('text')
   .attr('x', 25)
   .attr('y', function(d) { return scale(d[1]) - 30; })
   .text(function(d){ return d[0]; });

teamsEnter.append('text')
   .attr('x', 25)
   .attr('y', function(d) { return scale(d[1]) - 15; })
   .text(function(d){ return d[1]; });
text {
  text-anchor: middle;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

组以某种方式充当内部项目的封装,因此您可以在思维上将绑定到组的数据(即何时创建/更新/删除它)与处理子级时发生的实际逻辑分开