d3条形图对齐不同数量元素的刻度线

时间:2017-08-19 19:42:41

标签: d3.js alignment bar-chart

我有一个条形图,单击一个单选按钮时会显示data1.json或data2.json。

data1.json有9个元素,data2.json有4个元素。

问题1:如何进行设置,以便无论数据中的对象或条形数量如何,条形图始终以刻度线为中心?

问题2:如何将x轴降低到预期的水平?我知道这听起来微不足道,但我已经尝试了很多方法。

问题3:我想确保'value'是一个使用

的数字
newdata.foreach(function(d) {
      d.value = +d.value;
    })

但我似乎无法像我期望的那样迭代'newdata'。

这是github heregh-pages demo here

index.html文件

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  .bar {
    fill: steelblue;
  }
  .bar:hover {
    fill: brown;
  }
  .axis text {
    font: 10px sans-serif;
  }
  .axis path,
  .axis line {
    fill: none;
    stroke: #000;
    shape-rendering: crispEdges;
  }
</style>

<body>
  <form>
    <input type="radio" name="inputsrc" id="defaultInput" value="default" checked=""><label for="defaultInput">data1.json</label>
    <input type="radio" name="inputsrc" id="updateInput" value="post"><label for="updateInput">data2.json</label>
  </form>
  <svg id="d3newbie-chart" width="600" height="400">
  </svg>
  <script src="https://d3js.org/d3.v4.min.js"></script>

  <script type="text/javascript">
    var outerWidth = 600,
      outerHeight = 400;
    var margin = {
        top: 40,
        right: 30,
        bottom: 30,
        left: 80
      },
      width = outerWidth - margin.left - margin.right,
      height = outerHeight - margin.top - margin.bottom;
    var x = d3.scaleBand()
      .range([0, width]);
    var y = d3.scaleLinear()
      .range([height, 0]);
    var xAxis = d3.axisBottom(x);
    var yAxis = d3.axisLeft(y)
      .ticks(10, "%");
    var chart = d3.select("#d3newbie-chart")
      .attr("width", outerWidth)
      .attr("height", outerHeight)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    // x-axis
    chart.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

    function defaultFunction() {
      d3.json("data1.json", function(error, newdata) {
        if (error) throw error;
        data = newdata;
        // newdata.foreach(function(d) {
        //   d.value = +d.value;
        // })
        update();
      });
    }
    function updateFunction() {
      d3.json("data2.json", function(error, newdata) {
        if (error) throw error;
        data = newdata;
        update();
      });
    }
    function update(err, newdata) {
      y.domain([0, d3.max(data, function(d) {
        return d.value;
      })]);
      x.domain(data.map(function(d) {
        return d.name
      }));
      // x-axis
      chart.select(".x.axis").remove();
      chart.append("g")
        .attr("class", "x axis")
        .call(xAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Frequency");
      // y-axis
      chart.select(".y.axis").remove();
      chart.append("g")
        .attr("class", "y axis")
        .call(yAxis)
        .append("text")
        .attr("transform", "rotate(-90)")
        .attr("y", 6)
        .attr("dy", ".71em")
        .style("text-anchor", "end")
        .text("Frequency");
      var bar = chart.selectAll(".bar")
        .data(data, function(d) {
          return d.name;
        });
      // new data:
      bar.enter().append("rect")
        .attr("class", "bar")
        .attr("x", function(d) {
          return x(d.name);
        })
        .attr("y", function(d) {
          return y(d.value);
        })
        .attr("height", function(d) {
          return height - y(d.value);
        })
        .attr("width", 20);
      // removed data:
      bar.exit().remove();
      // updated data:
      bar.transition()
        .duration(750)
        .attr("y", function(d) {
          return y(d.value);
        })
        .attr("height", function(d) {
          return height - y(d.value);
        });
    };
    document.getElementById("defaultInput")
      .onclick = defaultFunction;
    document.getElementById("updateInput")
      .onclick = updateFunction;
    defaultFunction();
  </script>
</body>

1 个答案:

答案 0 :(得分:1)

更新了代码:https://jsfiddle.net/5j2nw238/2/

问题1:条形的宽度取决于svg的宽度,以及scaleBand函数paddingInner的给定值,paddingOuter和其他一些人。

https://github.com/d3/d3-scale/blob/master/README.md#band-scales

查看描述这些参数的图像。关键是不要像对.attr("width", 20);那样对条形宽度进行硬编码,而是操纵scaleBand以找到所需的外观。

问题2:

您使用代码正确执行了此操作

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

但是在更新时,您删除了轴并且没有再次应用转换。不要删除轴并重新创建它,只需使用新域更新轴刻度,然后执行chart.select(".x.axis").call(xAxis)。这与数据驱动方式的d3思维方式一致。更改您的数据,让D3处理DOM。

问题3:

函数名称为forEach,而不是foreach。此外,您说您要确保该值是一个字符串,但在变量之前放置+运算符会将其转换为数字,而不是字符串。