为什么减去边距只在设置 svg 宽度时将它们加回去
Why subtract margins only add them back in when setting svg width
在下面的 d3 折线图中,作者创建了一个具有属性 top、right、bottom 和 left 的 margin 对象。
var margin = {top: 20, right: 20, bottom: 60, left: 80}
然后按以下方式设置宽度变量。
width = 700 - margin.left - margin.right // 700 - 80 - 20 = 600
// So, width variable is 600
仅此而已,在设置 svg 的宽度时重新添加边距。
attr('width', width + margin.left + margin.right) // 600 + 80 + 20 = 700
// So, width attr of the svg is 700
为什么不直接设置宽度 700 而不必减去边距? svg 最终被设置为什么。这种模式的目的是什么我以前见过它并试图理解这样做的目的。谢谢。
完整代码如下。
var margin = {top: 20, right: 20, bottom: 60, left: 80},
width = 700 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var svg = d3.select("body") //create Svg element
.append("svg")
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.style("border", "solid 1px red")
.attr("transform","translate(100,0)"); // To align svg at the center in the output tab.
var data = [
{ date:"2020/01/01 00:00:00", patients: 600 },
{ date:"2020/02/01 00:00:00", patients: 500 },
{ date:"2020/03/01 00:00:00", patients: 400 },
{ date:"2020/04/01 00:00:00", patients: 500 },
{ date:"2020/05/01 00:00:00", patients: 300 },
{ date:"2020/06/01 00:00:00", patients: 100 },
{ date:"2020/07/01 00:00:00", patients: 50 },
{ date:"2020/08/01 00:00:00", patients: 500 },
{ date:"2020/09/01 00:00:00", patients: 550 },
{ date:"2020/10/01 00:00:00", patients: 550 },
];
data=data.map(d => ({
date: new Date(d.date),
patients: d.patients
}))
var xscale = d3.scaleTime()
.domain(d3.extent(data, d=>d.date))
.range([0,width]);
var yscale= d3.scaleLinear() // drawing y scale
.domain([0,600])
.range([height,0])
var chart=svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.attr('width', width)
.attr('height', height)
chart.append('g')
.call(d3.axisBottom(xscale).tickFormat(d3.timeFormat("%b")))
.attr('transform', 'translate(0,' + height + ')')
chart.append('g')
.call(d3.axisLeft(yscale))
svg.append("text") // labelling x-axis
.text("Month")
.attr("transform","translate(350,680)");
svg.append("text") // labelling y-axis
.text("Number of patients")
.attr('transform', "translate(40,400) rotate(-90)");
var generator = d3.line()
.x(function (d) { return xscale(d.date); })
.y(function (d) { return yscale(d.patients); });
chart.append('path')
.datum(data)
.attr("d", generator)
.attr("fill","none")
.attr("stroke","blue");
这是 D3 的标准做法,至少可以追溯到版本 3。Mike Bostock 在他的示例中使用了这个约定。我一直觉得它很有用。您举了一个相当简单的例子,但是随着您的 d3 代码变得越来越复杂,您将需要比总 svg 宽度更频繁地引用该绘图宽度。
在下面的 d3 折线图中,作者创建了一个具有属性 top、right、bottom 和 left 的 margin 对象。
var margin = {top: 20, right: 20, bottom: 60, left: 80}
然后按以下方式设置宽度变量。
width = 700 - margin.left - margin.right // 700 - 80 - 20 = 600
// So, width variable is 600
仅此而已,在设置 svg 的宽度时重新添加边距。
attr('width', width + margin.left + margin.right) // 600 + 80 + 20 = 700
// So, width attr of the svg is 700
为什么不直接设置宽度 700 而不必减去边距? svg 最终被设置为什么。这种模式的目的是什么我以前见过它并试图理解这样做的目的。谢谢。
完整代码如下。
var margin = {top: 20, right: 20, bottom: 60, left: 80},
width = 700 - margin.left - margin.right,
height = 700 - margin.top - margin.bottom;
var svg = d3.select("body") //create Svg element
.append("svg")
.attr('width', width + margin.right + margin.left)
.attr('height', height + margin.top + margin.bottom)
.style("border", "solid 1px red")
.attr("transform","translate(100,0)"); // To align svg at the center in the output tab.
var data = [
{ date:"2020/01/01 00:00:00", patients: 600 },
{ date:"2020/02/01 00:00:00", patients: 500 },
{ date:"2020/03/01 00:00:00", patients: 400 },
{ date:"2020/04/01 00:00:00", patients: 500 },
{ date:"2020/05/01 00:00:00", patients: 300 },
{ date:"2020/06/01 00:00:00", patients: 100 },
{ date:"2020/07/01 00:00:00", patients: 50 },
{ date:"2020/08/01 00:00:00", patients: 500 },
{ date:"2020/09/01 00:00:00", patients: 550 },
{ date:"2020/10/01 00:00:00", patients: 550 },
];
data=data.map(d => ({
date: new Date(d.date),
patients: d.patients
}))
var xscale = d3.scaleTime()
.domain(d3.extent(data, d=>d.date))
.range([0,width]);
var yscale= d3.scaleLinear() // drawing y scale
.domain([0,600])
.range([height,0])
var chart=svg.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.attr('width', width)
.attr('height', height)
chart.append('g')
.call(d3.axisBottom(xscale).tickFormat(d3.timeFormat("%b")))
.attr('transform', 'translate(0,' + height + ')')
chart.append('g')
.call(d3.axisLeft(yscale))
svg.append("text") // labelling x-axis
.text("Month")
.attr("transform","translate(350,680)");
svg.append("text") // labelling y-axis
.text("Number of patients")
.attr('transform', "translate(40,400) rotate(-90)");
var generator = d3.line()
.x(function (d) { return xscale(d.date); })
.y(function (d) { return yscale(d.patients); });
chart.append('path')
.datum(data)
.attr("d", generator)
.attr("fill","none")
.attr("stroke","blue");
这是 D3 的标准做法,至少可以追溯到版本 3。Mike Bostock 在他的示例中使用了这个约定。我一直觉得它很有用。您举了一个相当简单的例子,但是随着您的 d3 代码变得越来越复杂,您将需要比总 svg 宽度更频繁地引用该绘图宽度。