d3js:使用if条件基于变量为每个条添加多种颜色

时间:2016-09-30 00:41:06

标签: javascript if-statement d3.js

我创建了一个水平条形图。

每个条形的宽度基于对象变量体积。后来我意识到我需要让每个条形成一个堆栈条,2类对象变量是 vol1 & vol2 ,其中 vol1 + vol2 = 音量

我想知道是否有一种直接的方法可以根据 vol1 &和分配 2种颜色每个条 vol2 值而不是通常的堆叠条形方法,您需要(a)根据类别在数组中排列数据,(b)定义 x,y,y0 (c )为每个阵列条指定不同的颜色。

数据结构:

var data = [
{ "merchant": "A",
  "volume": 100,
  "vol1": 48,
  "vol2": 52
},
{...},
{...}
];

绘制图表的具体代码是:

    var bar = d3.select(".mainGroup").selectAll(".bar")
            .data(data_merchantTop100Vol);

    bar.attr("x", 0)
        .attr("y", d => y(d.merchant))
        .attr("height", y.rangeBand())
        .transition().duration(50)
        .attr("width", d => x(d.volume));

    bar.enter().append("rect")
        .attr("class", "bar")
        .attr("x", 0)
        .attr("y", d => y(d.merchant))
        .attr("height", y.rangeBand())
        .transition().duration(50)
        .attr("width", d => x(d.volume))
        // THIS PART IS TO FILL 2 COLORS TO THE 2 SECTIONS OF EACH BAR
        // .style("fill", function(d) {
        //     if(d.Vol1) { return "blue"}
        //     else if (d.vol2) { return "red"};
        // })

简而言之,我想使用if-condition着色方法而不是典型的堆叠条形法创建水平堆叠条。想法灵感:http://www.d3noob.org/2013/01/select-items-with-if-statement-in-d3js.html

当前水平条形图:
enter image description here

期望的结果:
enter image description here

2 个答案:

答案 0 :(得分:2)

您可以尝试使用正确的百分比填充gradients的矩形,但这会使解决方案复杂化。最简单的方法是为每种颜色使用一个矩形。您无需重新排列数据:

// Vol1 bars
    bar.enter().append("rect")
        .attr("class", "bar")
        .attr("x", 0)
        .attr("y", d => y(d.merchant))
        .attr("height", y.bandwidth())
        .transition().duration(50)
        .attr("width", d => x(d.vol1))
    .style("fill", "blue")

// Vol2 bars
    bar.enter().append("rect")
        .attr("class", "bar")
        .attr("x", d => x(d.vol1))
        .attr("y", d => y(d.merchant))
        .attr("height", y.bandwidth())
        .transition().duration(50)
        .attr("width", d => x(d.vol2))
    .style("fill", "red")

答案 1 :(得分:1)

如果你真的,真的想用一个条形图做这个,你必须设置自定义渐变,可以按百分比分割颜色:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>

  <script>
    var data = [{
      volume: Math.random() * 400,
      vol1: Math.random() * 400,
      vol2: Math.random() * 400
    }, {
      volume: Math.random() * 400,
      vol1: Math.random() * 400,
      vol2: Math.random() * 400
    }, {
      volume: Math.random() * 400,
      vol1: Math.random() * 400,
      vol2: Math.random() * 400
    }, {
      volume: Math.random() * 400,
      vol1: Math.random() * 400,
      vol2: Math.random() * 400
    }];

    var height = 400,
      width = 600,
      color1 = "orange",
      color2 = "steelblue",
      barHeight = 20;

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

    var defs = svg.append("defs");

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

    g.append("rect")
      .attr("width", function(d) {
        return d.volume
      })
      .attr("height", barHeight)
      .attr("x", 10)
      .attr("y", function(d, i) {
        return i * (barHeight + 5);
      })
      .style("fill", function(d, i) {

        var p = (d.vol1 / (d.vol1 + d.vol2)) * 100,
          grad = defs.append("linearGradient")
          .attr("id", "grad_" + i);

        grad.append("stop")
          .attr("offset", "0%")
          .attr("stop-color", color1);
        grad.append("stop")
          .attr("offset", (p) + "%")
          .attr("stop-color", color1);
        grad.append("stop")
          .attr("offset", (p) + "%")
          .attr("stop-color", color2);
        grad.append("stop")
          .attr("offset", "100%")
          .attr("stop-color", color2);

        return "url(#grad_" + i + ")";
      });
      
    g.append("text")
      .attr("x", function(d) {
        return d.volume + 12
      })
      .attr("y", function(d, i) {
        return (i * (barHeight + 5)) + 13;
      })
      .text(function(d){
        var p1 = (d.vol1 / (d.vol1 + d.vol2)) * 100,
            p2 = (d.vol2 / (d.vol1 + d.vol2)) * 100;
        
        return Math.round(p1) + "% and " + Math.round(p2) + "%";
      })
      .style("stroke", "none")
      .style("fill", "black")
      .style("font-family", "arial")
      .style("font-size", "12px");
  </script>

</body>

</html>