从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>
对于我的用例,这是预期的行为。
在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>
两个示例之间的唯一区别是所加载的d3版本。
有什么办法可以保持d3当前版本(v5)在v4中表现出的相同行为?
答案 0 :(得分:3)
这与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>
使用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>
有关说明,请参见D3 v5.8的release notes:
D3-Scale :
对于折叠的域,请使用域或范围的中点,而不要使用开始。 (重点是我的)
因此,除非返回D3 v5.7或更低版本,否则恐怕您无能为力。
事实上,D3 v5.8与v5.7如此不同(并且不向后兼容,例如,请参见新的scale构造函数或新的join
方法),以我的拙见被命名为D3 v6.0。可以说,从v5.7到v5.8的差异要大于从v4到v5的差异。
答案 1 :(得分:0)
在yScale域的定义中,只有一个值(零)。因此,该值正确显示在轴的中间。
您可以通过调整域来解决此问题,但轴上会出现更多滴答声。
只有一个示例(您可以添加任何其他数字):
var yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, d => d.y)+1])
.range([height, 0]);
答案 2 :(得分:0)
在 d3 v7 中遇到了同样的问题 - 解决方法是设置一个有效范围,如 previously answered 并有条件地显示刻度线和标签。
const height = *HEIGHT OF YOUR CHART*
const dataMax = Math.max(...*YOUR DATA*)
const dataMin = Math.min(...*YOUR DATA*)
const dataMinMaxZero = dataMax === 0 && dataMin === 0
const scaleMax = dataMinMaxZero ? 1 : dataMax;
const yScale = d3.scaleLinear()
.domain([dataMin, scaleMax])
.range([height, 0]);
const yAxis = d3.axisLeft(yScale)
d3.select("#yaxis").call(yAxis);
if (dataMinMaxZero) {
d3.select("#yaxis").selectAll(".tick").style("opacity", 0);
} else {
d3.select("#yaxis").selectAll(".tick").style("opacity", 1);
}