首页 > 解决方案 > d3.js 向条形图添加第二个标签

问题描述

2部分问题:

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

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

团队名称

我正在使用的代码是:

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. 如何让名称在矩形/条中垂直排列?

标签: javascriptd3.js

解决方案


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

  1. 一些现有元素可以链接到新数据中的某些项目。您使用它们访问它们selection
  2. 某些元素无法链接到新数据中的任何项目。您使用它们访问它们selection.exit()
  3. 新数据中的某些项目无法链接到选择中的任何元素。您通过使用访问它们selection.enter()

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

在您最初的选择中

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>

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


推荐阅读