【问题标题】:D3 path fill is giving weird resultD3 路径填充给出了奇怪的结果
【发布时间】:2022-01-04 20:55:03
【问题描述】:

尝试使用path 元素和fill 笔划绘制具有不同颜色的正负部分的正弦曲线,但得到一个奇怪/令人困惑的输出。

  • 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 的方式出现故障?

【问题讨论】:

    标签: svg d3.js


    【解决方案1】:

    这是因为某些精度问题吗?还是在 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>

    这给了我们:

    【讨论】:

    • 非常有趣。一个查询:为什么上部区域没有发生倾斜(绿色)?
    • 因为最后一个点足够接近零(或为零),所以顶部路径上的第一个和最后一个点的 y 值没有变化或没有明显变化:连接第一个和最后一个的边点几乎与 y=0 处的轴重叠。
    • 在这种情况下,如果我附加一个 (x_last, 0) 点,那么 fill 将正确显示。这就是fill 的工作原理,谢谢。
    猜你喜欢
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    相关资源
    最近更新 更多