D3分组图表之间的垂直线间距

时间:2018-07-28 11:15:55

标签: javascript d3.js svg graph

问题:

组的数量是动态的,垂直线(分隔符)需要动态填充。使用 x0.rangeBand()获取组宽度。有没有办法动态获得两组之间的空间宽度?

代码和平:

.....

    var slice = svg.selectAll(".chart")
        .data(data)
        .enter().append("g")
        .attr("class", "g")
        .attr("transform", function (d) {
            return "translate(" + x0(d.category) + ",0)";
        });



    // Create rectangles of the correct width
    slice.selectAll("rect")
        .data(function (d) {
            return d.values;
        })
        .enter().append("rect")
        .attr("width", x1.rangeBand())
        .attr("x", function (d) {
            return x1(d.rate);
        })
        .style("fill", function (d) {
            return color(d.rate)
        })
        .attr("y", function (d) {
            return y(0);
        })
        .attr("height", function (d) {
            return height - y(0);
        })
        .on("mouseover", function (d) {
            d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
            tip.show(d);

        })
        .on("mouseout", function (d) {
            tip.hide
            d3.select(this).style("fill", color(d.rate));
        })

    slice.append("line")
        .attr("class", "blabla")
        .attr("x1", x0.rangeBand()+20)
        .attr("x2", x0.rangeBand()+20)
        .attr("y1", 0)
        .attr("y2", height + margin.top + margin.bottom)
        .style("stroke-width", 1)
        .style("stroke", "#000");
.....

这是几个小组的样子

enter image description here

这是许多团体的样子 enter image description here

2 个答案:

答案 0 :(得分:0)

因为我没有理由坚持使用d3v3,而且我无法轻松找到d3v3文档的序数标尺,所以这里是d3v5版本的代码,其竖线位置正确。您必须使用带宽和步骤来计算位置。

这是您other question中的示例的改编:https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad

我将组的数量增加了一倍,看起来不错。

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var x0 = d3.scaleBand()
           .rangeRound([0, width])
           .paddingInner(0.1);

var x1 = d3.scaleBand();

var y = d3.scaleLinear()
    .range([height, 0]);

var xAxis = d3.axisBottom()
    .scale(x0)
    .tickSize(0);

var yAxis = d3.axisLeft()
    .scale(y);

var color = d3.scaleOrdinal()
    .range(["#ca0020","#f4a582","#d5d5d5","#92c5de","#0571b0"]);

var svg = d3.select('body').append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.json("barchart.json", {credentials: 'same-origin'}).then(function(data) {

  var categoriesNames = data.map(function(d) { return d.categorie; });
  var rateNames = data[0].values.map(function(d) { return d.rate; });

  x0.domain(categoriesNames);
  x1.domain(rateNames).range([0, x0.bandwidth()]);
  y.domain([0, d3.max(data, function(categorie) { return d3.max(categorie.values, function(d) { return d.value; }); })]);

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .style('opacity','0')
      .call(yAxis)
  .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .style('font-weight','bold')
      .text("Value");

  svg.select('.y').transition().duration(500).delay(1300).style('opacity','1');

  var slice = svg.selectAll(".slice")
      .data(data)
      .enter().append("g")
      .attr("class", "g")
      .attr("transform",function(d) { return "translate(" + x0(d.categorie) + ",0)"; });

  slice.selectAll("rect")
      .data(function(d) { return d.values; })
  .enter().append("rect")
      .attr("width", x1.bandwidth())
      .attr("x", function(d) { return x1(d.rate); })
      .style("fill", function(d) { return color(d.rate) })
      .attr("y", function(d) { return y(0); })
      .attr("height", function(d) { return height - y(0); })
      .on("mouseover", function(d) {
          d3.select(this).style("fill", d3.rgb(color(d.rate)).darker(2));
      })
      .on("mouseout", function(d) {
          d3.select(this).style("fill", color(d.rate));
      });

  slice.selectAll("rect")
      .transition()
      .delay(function (d) {return Math.random()*1000;})
      .duration(1000)
      .attr("y", function(d) { return y(d.value); })
      .attr("height", function(d) { return height - y(d.value); });

slice.append("line")
        .attr("class", "blabla")
        .attr("x1", (x0.step() - x0.bandwidth())*0.5 + x0.bandwidth())
        .attr("x2", (x0.step() - x0.bandwidth())*0.5 + x0.bandwidth())
        .attr("y1", 0)
        .attr("y2", height + margin.top + margin.bottom)
        .style("stroke-width", 1)
        .style("stroke", "#000");

  //Legend
  var legend = svg.selectAll(".legend")
      .data(data[0].values.map(function(d) { return d.rate; }).reverse())
  .enter().append("g")
      .attr("class", "legend")
      .attr("transform", function(d,i) { return "translate(0," + i * 20 + ")"; })
      .style("opacity","0");

  legend.append("rect")
      .attr("x", width - 18)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", function(d) { return color(d); });

  legend.append("text")
      .attr("x", width - 24)
      .attr("y", 9)
      .attr("dy", ".35em")
      .style("text-anchor", "end")
      .text(function(d) {return d; });

  legend.transition().duration(500).delay(function(d,i){ return 1300 + 100 * i; }).style("opacity","1");

});

答案 1 :(得分:0)

所以诀窍是重新计算填充自身。 V3没有band.step()函数,因此我添加了此方法以获取两项的中间值:

function getMiddle(x0){

    var rng = x0.range();
    var band = x0.rangeBand();
    var padding = 0;

    if(rng.length>1){
        padding = (rng[1]-rng[0] - band) *0.5;
    }
    return band + padding;
}

和用法:

    slice.append("line")
        .attr("x1", getMiddle(x0))
        .attr("x2", getMiddle(x0))
        .attr("y1", 0)
        .attr("y2", height + margin.top + margin.bottom)
        .style("stroke-width", 1)
        .style("stroke", "#000");