当所有值均为 0 时,零刻度在轴上垂直居中

gar*_*hdn 3 d3.js

我注意到从 d3 版本 4 更新到版本 5 时行为发生了变化。在 v4 中,当数据集包含 y 轴的所有零值时,“0”刻度线会正确对齐到图表底部。

<head>
  <!-- load the d3.js library -->
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <style>
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 2px;
    }
  </style>
</head>

<script>
  var margin = {
      top: 50,
      right: 50,
      bottom: 50,
      left: 50
    },
    width = window.innerWidth - margin.left - margin.right,
    height = window.innerHeight - margin.top - margin.bottom;

  var n = 21;
  // An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
  // var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })
  var dataset = d3.range(n).map(function(d) {
    return {
      "y": 0
    }
  })

  var xScale = d3.scaleLinear()
    .domain([0, n - 1])
    .range([0, width]);

  var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, d => d.y)])
    .range([height, 0]);

  var line = d3.line()
    .x(function(d, i) {
      return xScale(i);
    })
    .y(function(d) {
      return yScale(d.y);
    })
    .curve(d3.curveMonotoneX)

  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 + ")");

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

  svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));

  svg.append("path")
    .datum(dataset)
    .attr("class", "line")
    .attr("d", line);
</script>
Run Code Online (Sandbox Code Playgroud)

对于我的用例,这是预期的行为。

在v5中,在相同条件下,“0”与y轴中心对齐。

<head>
  <!-- load the d3.js library -->    	
  <script src="https://d3js.org/d3.v5.min.js"></script>
  <style>
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 2px;
    }
  </style>
</head>

<script>
var margin = {top: 50, right: 50, bottom: 50, left: 50}
  , width = window.innerWidth - margin.left - margin.right 
  , height = window.innerHeight - margin.top - margin.bottom;

var n = 21;
// An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
// var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })
var dataset = d3.range(n).map(function(d) { return {"y": 0 } })

var xScale = d3.scaleLinear()
    .domain([0, n-1])
    .range([0, width]);

var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, d => d.y)])
    .range([height, 0]);

var line = d3.line()
    .x(function(d, i) { return xScale(i); }) 
    .y(function(d) { return yScale(d.y); })
    .curve(d3.curveMonotoneX)

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 + ")");

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

svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));

svg.append("path")
    .datum(dataset)
    .attr("class", "line")
    .attr("d", line);
</script>
Run Code Online (Sandbox Code Playgroud)

这两个示例之间的唯一区别是加载的 d3 版本。

有什么方法可以在 d3 的当前版本(v5)中保留 v4 中表现出的相同行为吗?

Ger*_*ado 5

这不是D3 v4 和 v5 之间的区别。实际上,这个变化是在 D3 v5.8 中引入的。

看一下这里,这是使用 D3 v5.7 的代码:

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.js"></script>
  <style>
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 2px;
    }

  </style>
</head>

<script>
  var margin = {
      top: 50,
      right: 50,
      bottom: 50,
      left: 50
    },
    width = window.innerWidth - margin.left - margin.right,
    height = window.innerHeight - margin.top - margin.bottom;

  var n = 21;
  // An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
  // var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })
  var dataset = d3.range(n).map(function(d) {
    return {
      "y": 0
    }
  })

  var xScale = d3.scaleLinear()
    .domain([0, n - 1])
    .range([0, width]);

  var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, d => d.y)])
    .range([height, 0]);

  var line = d3.line()
    .x(function(d, i) {
      return xScale(i);
    })
    .y(function(d) {
      return yScale(d.y);
    })
    .curve(d3.curveMonotoneX)

  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 + ")");

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

  svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));

  svg.append("path")
    .datum(dataset)
    .attr("class", "line")
    .attr("d", line);

</script>
Run Code Online (Sandbox Code Playgroud)

现在使用 D3 v5.8 的相同代码:

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.8.0/d3.js"></script>
  <style>
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 2px;
    }

  </style>
</head>

<script>
  var margin = {
      top: 50,
      right: 50,
      bottom: 50,
      left: 50
    },
    width = window.innerWidth - margin.left - margin.right,
    height = window.innerHeight - margin.top - margin.bottom;

  var n = 21;
  // An array of objects of length N. Each object has key -> value pair, the key being "y" and the value is a random number
  // var dataset = d3.range(n).map(function(d) { return {"y": d3.randomUniform(1)() } })
  var dataset = d3.range(n).map(function(d) {
    return {
      "y": 0
    }
  })

  var xScale = d3.scaleLinear()
    .domain([0, n - 1])
    .range([0, width]);

  var yScale = d3.scaleLinear()
    .domain([0, d3.max(dataset, d => d.y)])
    .range([height, 0]);

  var line = d3.line()
    .x(function(d, i) {
      return xScale(i);
    })
    .y(function(d) {
      return yScale(d.y);
    })
    .curve(d3.curveMonotoneX)

  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 + ")");

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

  svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));

  svg.append("path")
    .datum(dataset)
    .attr("class", "line")
    .attr("d", line);

</script>
Run Code Online (Sandbox Code Playgroud)

可以在 D3 v5.8 的发行说明中找到说明:

D3 规模

对于折叠域,请使用域或范围的中点而不是start。(强调我的)

因此,恐怕您无能为力,除非回到 D3 v5.7 或更低版本。

事实上,D3 v5.8 与 v5.7 非常不同(并且不向后兼容,例如,请参阅新的比例构造函数,或新方法join),以我的愚见,它应该被命名为 D3 v6.0(当然,在语义版本控制之后,它仍然被命名为 v5,因为没有重大更改)。可以说,从 v5.7 到 v5.8 的差异比从 v4 到 v5 的差异更多。