SVG fills a non-filling border

See the following SVG file:

<?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> 

If you try this, the two triangles will have a thin gray area that separates them. I want to get rid of them, because I have hundreds of small triangles, and then the dividing lines are visible as a grid in the area that should be covered with triangles. I noticed that Mathematica SVG export has exactly this problem.

I tried to fill the outline with the same color and width 1. But then the triangles overflow. Therefore, the appearance depends on the order in which the triangles are colored.

Is there any clean solution or at least an improvement to this problem?

+1
source share
3 answers

This is the result of the rasterization strategy used, and there is no easy fix.

One fix is ​​to stroke the triangles, but with a very thin stroke. For example, here is one in 0.2px increments:

Demo: http://jsfiddle.net/Qw2HL/

Alternatively, you can increase your graphics and display the stroked versions under the actual content.

Demo: 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 } 

(You can do this automatically through JS if you are working in a user agent such as a web browser where it is available.)


This demonstration clearly shows the problem.

Problem: 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> 

Here we have two vertical edges exactly on top of each other. In the first case, they are precisely aligned with the pixel grid. The left form fills all the pixels to the left exactly, the correct form fills all the pixels to the right exactly and does not fill in the blank.

In the second case, however, both shapes are located directly between the pixel border. Since our shape overlaps these pixels by 50%, anti-aliasing tells us in this case that we need to fill the pixels that we overlap at exactly 50% opacity. Thus, the left shape fills this common column of pixels with an opacity of 50%, and then the correct form fills the common column with pixels, which are an additional opacity of 50%.

Unfortunately, opacity is created by multiplying rather than adding. Pixel rgba(0,0,0,0.5) overtop rgba(0,0,0,0.5) creates rgba(0,0,0,0.75) , NOT rgba(0,0,0,1) .

This is the essence of the problem, and it is not specific to SVG. For example, see

When you select an infinitely accurate vector image in a grid with a finite pixel, information is lost. You need to hack it.

+1
source

what you see is an artifact of vector graphics mapping for raster devices. to compensate for this, slightly disturb one of the triangles involved in an amount of less than 1 unit.

Example

(code below): Translate the purple polygon by moving it 0.2 units along the x axis.

note that the quality of the result - in addition to the obvious factors - will depend on the scaling factor. in this example, I see that the dividing line disappears with a zoom level> 150% in chrome 25.

 <?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> 

another option would be to change some triangles to pentagons, an adjacent trapezoidal region covering the dividing line between the triangles (see code below), which works for scaling factors> 67%. Are there any restrictions on the triangles and their orientation in the plane (like one right angle, sides on the orthogonal lattice)?

 <?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> 
+1
source

I had the same problem with the space between the polygons dividing the edge. Here are two triangles dividing one edge with different opacity:

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

... space is more visible when polygons have higher opacity. As suggested in other answers, adding a stroked outline to your polygons helps, but the correct stroke width depends on the opacity of the polygon.

Using a constant stroke width of 1px:

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

Using stroke width = polygon_alpha ^ 6:

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

... I found the stroke width equation only empirically using this Perl script, so you can try it yourself:

 #!/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>"; 
+1
source

All Articles