【问题标题】:How to stack rects respective of previous rect's height?如何堆叠与先前矩形高度相关的矩形?
【发布时间】:2019-04-17 02:11:44
【问题描述】:

我正在尝试制作一个简单的列可视化,其中矩形的高度由比例确定:

var heightScale = d3.scaleLinear()
    .domain([150,2500])
    .range([10,80]);

我的代码是这样的

var margins = {top:100, left:80, bottom:40, right:20};
var width = 950;
var height = 600;
var totalWidth = width+margins.left+margins.right;
var totalHeight = height+margins.top+margins.bottom;

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

var graphGroup = svg.append("g")
    .attr("transform", "translate(" + margins.left + "," + margins.top + ")");

var q12018Data = [{'fmc': 'UBS', 'value': 2308.78},
 {'fmc': 'Fidelity', 'value': 976.76},
 {'fmc': 'JP Morgan', 'value': 837.19},
 {'fmc': 'Value Partners', 'value': 787.39},
 {'fmc': 'BlackRock', 'value': 664.42},
 {'fmc': 'Krane', 'value': 445.13},
 {'fmc': 'Investec', 'value': 407.40},
 {'fmc': 'Nikko', 'value': 356.07},
 {'fmc': 'Yuanta', 'value': 202.71},
 {'fmc': 'Cathay Securities Invest', 'value': 174.46}];

var q22018Data = [{'fmc': 'UBS', 'value': 2193.05},
 {'fmc': 'BlackRock', 'value': 817.24},
 {'fmc': 'Yuanta', 'value': 676.87},
 {'fmc': 'Fubon', 'value': 660.11},
 {'fmc': 'JP Morgan', 'value': 577.26},
 {'fmc': 'Investec', 'value': 384.65},
 {'fmc': 'Hang Seng', 'value': 289.92},
 {'fmc': 'Cathay Securities Invest', 'value': 289.43},
 {'fmc': 'Pictet', 'value': 232.74},
 {'fmc': 'Nikko', 'value': 224.73}];

var q32018Data = [{'fmc': 'ChinaAMC', 'value': 1074},
 {'fmc': 'Fubon', 'value': 466.32},
 {'fmc': 'Heungkuk', 'value': 458.23},
 {'fmc': 'BlackRock', 'value': 361.34},
 {'fmc': 'UBS', 'value': 350.01},
 {'fmc': 'CSOP', 'value': 263.60},
 {'fmc': 'Legal & General', 'value': 218.79},
 {'fmc': 'SSgA', 'value': 188.35},
 {'fmc': 'Fidelity', 'value': 134.06},
 {'fmc': 'Morgan Stanley', 'value': 112.70}];

var q42018Data = [{'fmc': 'ChinaAMC', 'value': 1994.02},
 {'fmc': 'Fubon', 'value': 808.34},
 {'fmc': 'Heungkuk', 'value': 676.26},
 {'fmc': 'BlackRock', 'value': 668.64},
 {'fmc': 'UBS', 'value': 595.27},
 {'fmc': 'CSOP', 'value': 424.83},
 {'fmc': 'Legal & General', 'value': 380.30},
 {'fmc': 'SSgA', 'value': 366.85},
 {'fmc': 'Fidelity', 'value': 285.09},
 {'fmc': 'Morgan Stanley', 'value': 273.55}];

var q12019Data = [{'fmc': 'UBS', 'value': 938.23},
 {'fmc': 'BlackRock', 'value': 474.45},
 {'fmc': 'Yuanta', 'value': 385.32},
 {'fmc': 'Fubon', 'value': 349.73},
 {'fmc': 'JP Morgan', 'value': 246.86},
 {'fmc': 'Investec', 'value': 235.12},
 {'fmc': 'Hang Seng', 'value': 230.23},
 {'fmc': 'Cathay Securities Invest', 'value': 220.02},
 {'fmc': 'Pictet', 'value': 213.76},
 {'fmc': 'Nikko', 'value': 190.73}];


var heightScale = d3.scaleLinear()
    .domain([150,2500])
    .range([10,80]);

    var column = graphGroup.selectAll("g")
        .data(q12018Data)
      .enter().append("g");

    column.append("rect")
        .attr("width", 150)
        .attr("height", function(d) {return heightScale(d.value)})
        .attr('y', function(d,i) {
          if (i!=0) {
            var prevData = column.data()[i-1];
            var prevHeight = heightScale(prevData.value);
            var currentHeight = heightScale(d.value);
            return prevHeight;
          } else {
            return 0;
          }

        })
        .style('fill','gray');

    column.append("text")
        .attr("x", 75)
        .attr('y', function(d,i) {
          if (i!=0) {
            var prevData = column.data()[i-1];
            var prevHeight = heightScale(prevData.value);
            var currentHeight = heightScale(d.value);
            return prevHeight;
          } else {
            return 0;
          }

        })
        .attr('text-anchor','middle')
        .text(function(d) { return d.fmc; });
<!DOCTYPE html>
<meta charset="utf-8">
<style>

</style>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>

问题

为什么我的前一个矩形的矩形高度计算不正确?结果应该类似于外观上的堆叠条。虽然没有 y 比例,但我只想附加后续的 rect,以便只有几个 px 的填充,比如 2px。

【问题讨论】:

    标签: javascript d3.js svg


    【解决方案1】:

    您没有对这些值进行求和!您只是为每个对象传递单独的值......您必须累积它们。

    我们可以通过简单地声明两个计数器来做到这一点,初始值为零......

    let counterRect = 0,
        counterText = 0;
    

    ...我们稍后会增加,使用:

    .attr('y', function(d, i) {
        let previous = counterRect;
        return (counterRect += heightScale(d.value), previous)
    })
    

    这是您的代码进行了更改(以及矩形的白色边框):

    var margins = {
      top: 100,
      left: 80,
      bottom: 40,
      right: 20
    };
    var width = 950;
    var height = 600;
    var totalWidth = width + margins.left + margins.right;
    var totalHeight = height + margins.top + margins.bottom;
    
    var svg = d3.select('body')
      .append('svg')
      .attr('width', totalWidth)
      .attr('height', totalHeight);
    
    var graphGroup = svg.append("g")
      .attr("transform", "translate(" + margins.left + "," + margins.top + ")");
    
    var q12018Data = [{
        'fmc': 'UBS',
        'value': 2308.78
      },
      {
        'fmc': 'Fidelity',
        'value': 976.76
      },
      {
        'fmc': 'JP Morgan',
        'value': 837.19
      },
      {
        'fmc': 'Value Partners',
        'value': 787.39
      },
      {
        'fmc': 'BlackRock',
        'value': 664.42
      },
      {
        'fmc': 'Krane',
        'value': 445.13
      },
      {
        'fmc': 'Investec',
        'value': 407.40
      },
      {
        'fmc': 'Nikko',
        'value': 356.07
      },
      {
        'fmc': 'Yuanta',
        'value': 202.71
      },
      {
        'fmc': 'Cathay Securities Invest',
        'value': 174.46
      }
    ];
    
    var q22018Data = [{
        'fmc': 'UBS',
        'value': 2193.05
      },
      {
        'fmc': 'BlackRock',
        'value': 817.24
      },
      {
        'fmc': 'Yuanta',
        'value': 676.87
      },
      {
        'fmc': 'Fubon',
        'value': 660.11
      },
      {
        'fmc': 'JP Morgan',
        'value': 577.26
      },
      {
        'fmc': 'Investec',
        'value': 384.65
      },
      {
        'fmc': 'Hang Seng',
        'value': 289.92
      },
      {
        'fmc': 'Cathay Securities Invest',
        'value': 289.43
      },
      {
        'fmc': 'Pictet',
        'value': 232.74
      },
      {
        'fmc': 'Nikko',
        'value': 224.73
      }
    ];
    
    var q32018Data = [{
        'fmc': 'ChinaAMC',
        'value': 1074
      },
      {
        'fmc': 'Fubon',
        'value': 466.32
      },
      {
        'fmc': 'Heungkuk',
        'value': 458.23
      },
      {
        'fmc': 'BlackRock',
        'value': 361.34
      },
      {
        'fmc': 'UBS',
        'value': 350.01
      },
      {
        'fmc': 'CSOP',
        'value': 263.60
      },
      {
        'fmc': 'Legal & General',
        'value': 218.79
      },
      {
        'fmc': 'SSgA',
        'value': 188.35
      },
      {
        'fmc': 'Fidelity',
        'value': 134.06
      },
      {
        'fmc': 'Morgan Stanley',
        'value': 112.70
      }
    ];
    
    var q42018Data = [{
        'fmc': 'ChinaAMC',
        'value': 1994.02
      },
      {
        'fmc': 'Fubon',
        'value': 808.34
      },
      {
        'fmc': 'Heungkuk',
        'value': 676.26
      },
      {
        'fmc': 'BlackRock',
        'value': 668.64
      },
      {
        'fmc': 'UBS',
        'value': 595.27
      },
      {
        'fmc': 'CSOP',
        'value': 424.83
      },
      {
        'fmc': 'Legal & General',
        'value': 380.30
      },
      {
        'fmc': 'SSgA',
        'value': 366.85
      },
      {
        'fmc': 'Fidelity',
        'value': 285.09
      },
      {
        'fmc': 'Morgan Stanley',
        'value': 273.55
      }
    ];
    
    var q12019Data = [{
        'fmc': 'UBS',
        'value': 938.23
      },
      {
        'fmc': 'BlackRock',
        'value': 474.45
      },
      {
        'fmc': 'Yuanta',
        'value': 385.32
      },
      {
        'fmc': 'Fubon',
        'value': 349.73
      },
      {
        'fmc': 'JP Morgan',
        'value': 246.86
      },
      {
        'fmc': 'Investec',
        'value': 235.12
      },
      {
        'fmc': 'Hang Seng',
        'value': 230.23
      },
      {
        'fmc': 'Cathay Securities Invest',
        'value': 220.02
      },
      {
        'fmc': 'Pictet',
        'value': 213.76
      },
      {
        'fmc': 'Nikko',
        'value': 190.73
      }
    ];
    
    let counterRect = 0,
      counterText = 0;
    
    var heightScale = d3.scaleLinear()
      .domain([150, 2500])
      .range([10, 80]);
    
    var column = graphGroup.selectAll("g")
      .data(q12018Data)
      .enter().append("g");
    
    column.append("rect")
      .attr("width", 150)
      .attr("height", function(d) {
        return heightScale(d.value)
      })
      .attr('y', function(d, i) {
        let previous = counterRect;
        return (counterRect += heightScale(d.value), previous)
      })
      .style('fill', 'gray')
      .style("stroke", "white");
    
    column.append("text")
      .attr("x", 75)
      .attr('y', function(d, i) {
        let previous = counterText;
        return (counterText += heightScale(d.value), previous + (heightScale(d.value)/2))
      })
      .attr("dominant-baseline", "central")
      .attr('text-anchor', 'middle')
      .text(function(d) {
        return d.fmc;
      });
    &lt;script src="https://d3js.org/d3.v5.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 太棒了!只是想知道如何将正确的值传递给计数器,以便文本在矩形中显示为垂直居中,而不是在顶部。
    • 只需使用dominant-baseline: central 并加上当前值的一半。再看看sn-p。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 2010-09-25
    • 2012-11-20
    • 2013-04-22
    • 2023-03-14
    • 2018-11-02
    相关资源
    最近更新 更多