D3 路径填充给出了奇怪的结果
D3 path fill is giving weird result
尝试使用 path
元素和 fill
描边以不同颜色绘制具有正负部分的正弦曲线,但得到了 weird/confusing 输出。
- 有99分
- 有399分
这是 D3 代码:
window.onload = function(){
let xy_values =[];
let xy_values2 =[];
let len = 99; //Number of points
let dt = 8*Math.PI/len; //X-Distance between points
for (var i =0; i<len; i++){
let valx = i*dt;
let valy = Math.sin(valx);
if(valy > 0){
// Positive sine
xy_values.push( {key: valx, value: valy} );
xy_values2.push( {key: valx, value: 0.0} );
}else{
//Negative sine
xy_values.push( {key: valx, value: 0.0} );
xy_values2.push( {key: valx, value: valy} );
}
}
draw(xy_values, xy_values2);
}
function draw(cdata, ddata){
var height=200;
var width=800;
let svg=d3.select("#container").append("svg").attr("width", width).attr("height", height);
walkX = d3.scaleLinear()
.domain([0, 30])
.range([40, width ])
walkY = d3.scaleLinear()
.domain([-1, 1])
.range([height-10, 10])
// Add the green regions
svg.append("path")
.datum(cdata)
.attr("fill", "#BFB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return walkX(d.key) })
.y(function(d) { return walkY(d.value) })
);
// Add the red regions
svg.append("path")
.datum(ddata)
.attr("fill", "#FBB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return walkX(d.key) })
.y(function(d) { return walkY(d.value) })
);
// Add scatter points
svg.append('g')
.selectAll("dot")
.data(ddata)
.enter()
.append("circle")
.attr("cx", function (d) { return walkX(d.key); } )
.attr("cy", function (d) { return walkY(d.value); } )
.attr("r", 1.5)
.style("fill", "#69b3a2")
svg.append("g")
.attr("transform", "translate("+ 0 + "," + 10 + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height-10) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height/2) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate(" + 35 +","+ 0 +")")
.call(d3.axisLeft(walkY));
}
问题
是什么导致填充不正确/倾斜填充?
这是因为一些精度问题吗?还是在 D3 中实现 fill
的方式有问题?
Is this because of some precision issue ? or is it a glitch in the way fill is implemented in D3 ?
不,D3 仅用于在 DOM 中创建 SVG 元素而不渲染它们,问题是如何应用 SVG 填充。将填充应用于路径元素时,填充将路径的最后一个点与第一个点连接起来,这就是您看到这种效果的原因。您会看到您试图删除的效果在这两点之间形成了直线。呈现 SVG 的浏览器没有任何指令来为填充提供不同的形状。
解决此问题的一个选项是使用区域生成器而不是线生成器,它允许设置基线的选项。
D3 区域生成器为每个 x 值创建一个具有两个 y 值的路径(指定要填充的区域,而不是路径),在本例中,一个位于基线 (y0),一个位于数据值(y1):
d3.area()
.x(function(d) { return walkX(d.key) })
.y1(function(d) { return walkY(d.value) })
.y0(function() { return walkY(0) })
window.onload = function(){
let xy_values =[];
let xy_values2 =[];
let len = 99; //Number of points
let dt = 8*Math.PI/len; //X-Distance between points
for (var i =0; i<len; i++){
let valx = i*dt;
let valy = Math.sin(valx);
if(valy > 0){
// Positive sine
xy_values.push( {key: valx, value: valy} );
xy_values2.push( {key: valx, value: 0.0} );
}else{
//Negative sine
xy_values.push( {key: valx, value: 0.0} );
xy_values2.push( {key: valx, value: valy} );
}
}
draw(xy_values, xy_values2);
}
function draw(cdata, ddata){
var height=200;
var width=800;
let svg=d3.select("#container").append("svg").attr("width", width).attr("height", height);
walkX = d3.scaleLinear()
.domain([0, 30])
.range([40, width ])
walkY = d3.scaleLinear()
.domain([-1, 1])
.range([height-10, 10])
// Add the green regions
svg.append("path")
.datum(cdata)
.attr("fill", "#BFB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) { return walkX(d.key) })
.y1(function(d) { return walkY(d.value) })
.y0(function() { return walkY(0) })
);
// Add the red regions
svg.append("path")
.datum(ddata)
.attr("fill", "#FBB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) { return walkX(d.key) })
.y1(function(d) { return walkY(d.value) })
.y0(function() { return walkY(0) })
);
// Add scatter points
svg.append('g')
.selectAll("dot")
.data(ddata)
.enter()
.append("circle")
.attr("cx", function (d) { return walkX(d.key); } )
.attr("cy", function (d) { return walkY(d.value); } )
.attr("r", 1.5)
.style("fill", "#69b3a2")
svg.append("g")
.attr("transform", "translate("+ 0 + "," + 10 + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height-10) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height/2) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate(" + 35 +","+ 0 +")")
.call(d3.axisLeft(walkY));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.0/d3.min.js"></script>
<div id="container"></div>
这给了我们:
尝试使用 path
元素和 fill
描边以不同颜色绘制具有正负部分的正弦曲线,但得到了 weird/confusing 输出。
- 有99分
- 有399分
这是 D3 代码:
window.onload = function(){
let xy_values =[];
let xy_values2 =[];
let len = 99; //Number of points
let dt = 8*Math.PI/len; //X-Distance between points
for (var i =0; i<len; i++){
let valx = i*dt;
let valy = Math.sin(valx);
if(valy > 0){
// Positive sine
xy_values.push( {key: valx, value: valy} );
xy_values2.push( {key: valx, value: 0.0} );
}else{
//Negative sine
xy_values.push( {key: valx, value: 0.0} );
xy_values2.push( {key: valx, value: valy} );
}
}
draw(xy_values, xy_values2);
}
function draw(cdata, ddata){
var height=200;
var width=800;
let svg=d3.select("#container").append("svg").attr("width", width).attr("height", height);
walkX = d3.scaleLinear()
.domain([0, 30])
.range([40, width ])
walkY = d3.scaleLinear()
.domain([-1, 1])
.range([height-10, 10])
// Add the green regions
svg.append("path")
.datum(cdata)
.attr("fill", "#BFB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return walkX(d.key) })
.y(function(d) { return walkY(d.value) })
);
// Add the red regions
svg.append("path")
.datum(ddata)
.attr("fill", "#FBB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.line()
.x(function(d) { return walkX(d.key) })
.y(function(d) { return walkY(d.value) })
);
// Add scatter points
svg.append('g')
.selectAll("dot")
.data(ddata)
.enter()
.append("circle")
.attr("cx", function (d) { return walkX(d.key); } )
.attr("cy", function (d) { return walkY(d.value); } )
.attr("r", 1.5)
.style("fill", "#69b3a2")
svg.append("g")
.attr("transform", "translate("+ 0 + "," + 10 + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height-10) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height/2) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate(" + 35 +","+ 0 +")")
.call(d3.axisLeft(walkY));
}
问题
是什么导致填充不正确/倾斜填充?
这是因为一些精度问题吗?还是在 D3 中实现 fill
的方式有问题?
Is this because of some precision issue ? or is it a glitch in the way fill is implemented in D3 ?
不,D3 仅用于在 DOM 中创建 SVG 元素而不渲染它们,问题是如何应用 SVG 填充。将填充应用于路径元素时,填充将路径的最后一个点与第一个点连接起来,这就是您看到这种效果的原因。您会看到您试图删除的效果在这两点之间形成了直线。呈现 SVG 的浏览器没有任何指令来为填充提供不同的形状。
解决此问题的一个选项是使用区域生成器而不是线生成器,它允许设置基线的选项。
D3 区域生成器为每个 x 值创建一个具有两个 y 值的路径(指定要填充的区域,而不是路径),在本例中,一个位于基线 (y0),一个位于数据值(y1):
d3.area()
.x(function(d) { return walkX(d.key) })
.y1(function(d) { return walkY(d.value) })
.y0(function() { return walkY(0) })
window.onload = function(){
let xy_values =[];
let xy_values2 =[];
let len = 99; //Number of points
let dt = 8*Math.PI/len; //X-Distance between points
for (var i =0; i<len; i++){
let valx = i*dt;
let valy = Math.sin(valx);
if(valy > 0){
// Positive sine
xy_values.push( {key: valx, value: valy} );
xy_values2.push( {key: valx, value: 0.0} );
}else{
//Negative sine
xy_values.push( {key: valx, value: 0.0} );
xy_values2.push( {key: valx, value: valy} );
}
}
draw(xy_values, xy_values2);
}
function draw(cdata, ddata){
var height=200;
var width=800;
let svg=d3.select("#container").append("svg").attr("width", width).attr("height", height);
walkX = d3.scaleLinear()
.domain([0, 30])
.range([40, width ])
walkY = d3.scaleLinear()
.domain([-1, 1])
.range([height-10, 10])
// Add the green regions
svg.append("path")
.datum(cdata)
.attr("fill", "#BFB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) { return walkX(d.key) })
.y1(function(d) { return walkY(d.value) })
.y0(function() { return walkY(0) })
);
// Add the red regions
svg.append("path")
.datum(ddata)
.attr("fill", "#FBB")
.attr("stroke", "none")
.attr("stroke-width", 1.5)
.attr("d", d3.area()
.x(function(d) { return walkX(d.key) })
.y1(function(d) { return walkY(d.value) })
.y0(function() { return walkY(0) })
);
// Add scatter points
svg.append('g')
.selectAll("dot")
.data(ddata)
.enter()
.append("circle")
.attr("cx", function (d) { return walkX(d.key); } )
.attr("cy", function (d) { return walkY(d.value); } )
.attr("r", 1.5)
.style("fill", "#69b3a2")
svg.append("g")
.attr("transform", "translate("+ 0 + "," + 10 + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height-10) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate("+ 0 + "," + (height/2) + ")")
.call(d3.axisBottom(walkX));
svg.append("g")
.attr("transform", "translate(" + 35 +","+ 0 +")")
.call(d3.axisLeft(walkY));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.1.0/d3.min.js"></script>
<div id="container"></div>
这给了我们: