【问题标题】:SVG fill not filling boundarySVG填充不填充边界
【发布时间】:2013-03-26 07:17:03
【问题描述】:

查看以下 SVG 文件:

<?xml version="1.0"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
<polygon points="10,10 10,390 390,390 10,10" style="fill:rgb(140,90,90)" />
<polygon points="10,10 390,390 390,10 10,10" style="fill:rgb(90,140,90)" />
</svg>

如果你试试这个,这两个三角形有一个薄的灰色区域,将它们分开。我想摆脱这些,因为我有数百个小三角形,然后分隔线在该区域上显示为网格,应该被三角形覆盖。我注意到,Mathematica 的 SVG 导出正是存在这个问题。

我尝试用相同颜色和宽度 1 的笔触填充轮廓。但是,三角形过度填充。因此,外观取决于绘制三角形的顺序。

是否有任何干净的解决方案或至少可以改进此问题?

【问题讨论】:

    标签: svg


    【解决方案1】:

    这是使用光栅化策略的结果,没有简单的解决方法。

    一种解决方法是描边三角形,但描边非常非常细。例如,这是一个 0.2px 笔划的:

    演示:http://jsfiddle.net/Qw2HL/

    或者,您可以将您的图形加倍并在实际内容下方呈现描边版本。

    演示:http://jsfiddle.net/Qw2HL/1/

    <g id="underlay">
      <polygon class="t1" points="10,10 10,390 390,390 10,10" />
      <polygon class="t2" points="10,10 390,390 390,10 10,10" />
    </g><g id="content">
      <polygon class="t1" points="10,10 10,390 390,390 10,10" />
      <polygon class="t2" points="10,10 390,390 390,10 10,10" />
    </g>
    
    .t1 { fill:rgb(140,90,90); stroke:rgb(140,90,90) }
    .t2 { fill:rgb(90,140,90); stroke:rgb(90,140,90) }
    #underlay polygon { stroke-width:1px }
    #content  polygon { stroke:none      }
    

    (如果您在用户代理(如可用的网络浏览器)中运行,则可以通过 JS 自动执行此操作。)


    这个演示很清楚地显示了这个问题。

    问题:http://jsfiddle.net/tbCxT/

    <svg xmlns="http://www.w3.org/2000/svg">
      <g id="aligned">
        <polygon class="a" points="10,10 10,100 100,100, 100,10" />
        <polygon class="b" points="100,10 100,100 200,100, 200,10" />
      </g>
      <g id="shifted" transform="translate(0.5,110)">
        <polygon class="a" points="10,10 10,100 100,100, 100,10" />
        <polygon class="b" points="100,10 100,100 200,100, 200,10" />
      </g>
    </svg>
    

    这里我们有两个垂直的边缘正好在彼此的顶部。在第一种情况下,它们在像素网格上完全对齐。左侧形状完全填充左侧的所有像素,右侧形状完全填充右侧的所有像素,并且都不填充间隙。

    然而,在第二种情况下,两个形状都位于像素边界之间。由于我们的形状与这些像素重叠了 50%,因此抗锯齿告诉我们,在这种情况下,我们应该将重叠的像素填充为 50% 的不透明度。所以左边的形状用 50% 不透明度填充这个共享的像素列,然后右边的形状用另外 50% 不透明度的像素填充共享列。

    不幸的是,不透明度是通过乘法而不是加法建立的。 rgba(0,0,0,0.5) 的像素在rgba(0,0,0,0.5) 之上产生rgba(0,0,0,0.75),而不是rgba(0,0,0,1)

    这是问题的症结所在,它并不特定于 SVG。例如,参见:

    当您将无限精确的矢量图像采样到有限像素网格时,信息会丢失。你需要破解它来解决它。

    【讨论】:

    • 谢谢。我已经想到了细笔画方法,并且现在在我的项目中使用它来导出 SVG(搜索“Euler Math Toolbox”)。但是对于太细的笔触,背景会透出来。顺便说一下,我需要它用于带有排序三角形的 3D 图形。我的感觉是,这根本不应该发生。三角形之间的抗锯齿像素应混合并完全填充间隙。
    • @Rene 请看我的编辑。我理解“这不应该发生”的愿望和感觉。但是,它确实如此,并且出于完全正当的理由。
    • 我想到了你的评论。不透明度是这样工作的,你是对的。因此,不能完全完美地处理抗锯齿。
    • 很高兴您同意。这个答案是否因此回答了您的问题?
    【解决方案2】:

    您所看到的似乎是将矢量图形映射到位图设备的产物。为了补偿它,稍微扰动其中一个三角形,其量小于 1 个单位。

    示例(代码见下文):通过沿 x 轴移动 0.2 个单位来平移紫色多边形。

    请注意,除了明显的因素外,结果的质量将取决于缩放系数。在给定的示例中,我可以看到分隔线在 chrome 25 中以 >=150% 的缩放级别消失。

    <?xml version="1.0"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
    <polygon points="10.2,10   10.2,390 390.2,390 10.2,10" style="fill:rgb(140,90,90)" />
    <polygon points="  10,10    390,390   390,10    10,10" style="fill:rgb(90,140,90)" />
    </svg>
    

    另一种选择可能是将一些三角形更改为五边形,这是一个相邻的梯形区域,覆盖三角形之间的分隔线(参见下面的代码),适用于大于 67% 的缩放系数。三角形及其在平面中的方向是否有任何限制(例如一个直角,正交晶格上的边)?

    <?xml version="1.0"?>
    <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
    <svg xmlns="http://www.w3.org/2000/svg" width="400" height="400">
    <polygon points="10,10  10,390  390,390 390,389.6 10.4,10 10,10" style="fill:rgb(140,90,90)" />
    <polygon points="10,10      390,390 390,10  10,10"               style="fill:rgb(90,140,90)" />
    </svg>
    

    【讨论】:

      【解决方案3】:

      我在共享一条边的多边形之间的空间方面遇到了同样的问题。这是两个共享一条边的三角形,具有不同的不透明度:

      http://jsfiddle.net/YfH9N/embedded/result/

      ...当多边形具有更高的不透明度时,空间更明显。正如其他答案中所建议的那样,向多边形添加描边轮廓会有所帮助,但描边的正确宽度取决于多边形的不透明度。

      使用恒定的 1px 笔画宽度:

      http://jsfiddle.net/LKQHf/embedded/result/

      使用描边宽度 = polygon_alpha ^ 6:

      http://jsfiddle.net/ekwk3/2/embedded/result/

      ...我只是使用这个 Perl 脚本凭经验找到了笔画宽度的公式,所以你可以自己尝试一下:

      #!/usr/bin/perl
      
      print "<?xml version=\"1.0\" standalone=\"no\"?>
      <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">
      <svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"1100\" height=\"100\">
      ";
      
      for (my $alpha = 0; $alpha<=1; $alpha+=0.025) {
          my $alpha_str = sprintf("%.3f", $alpha);
          my $alpha_stroke = 1;#$alpha ** 6;
          my $alpha_stroke_str = sprintf("%.3f", $alpha_stroke);
          my $stroke_width = $alpha ** 6;
          my $stroke_width_str = sprintf("%.3fpx", $stroke_width);
      
          print "
          <g transform=\"translate(".($alpha*1000).",0)\">    
              <polygon points=\"20,10 25,49 6,40\" style=\"fill:rgb(255,100,0);fill-opacity:$alpha_str;stroke:rgb(255,100,0);stroke-width:$stroke_width_str;stroke-opacity:$alpha_stroke_str\" />
              <polygon points=\"20,10 25,49 40,4\" style=\"fill:rgb(255,100,0);fill-opacity:$alpha_str;stroke:rgb(255,100,0);stroke-width:$stroke_width_str;stroke-opacity:$alpha_stroke_str\" />
          </g>\n";
      }
      
      print "</svg>";
      

      【讨论】:

        猜你喜欢
        • 2014-06-14
        • 1970-01-01
        • 2016-03-04
        • 2020-09-19
        • 1970-01-01
        • 2018-07-30
        • 2015-04-04
        • 2017-01-26
        • 1970-01-01
        相关资源
        最近更新 更多