How can I avoid polygon edge stitching artifacts in HTML5 Canvas?
I maintain parallel Flash and HTML5/Canvas renderers for the OpenHeatMap open-source project. I'm plagued by an inconsistency in the rendering of filled polygons with fractional coordinates between the two versions. If you render two polygons that share an edge, Canvas will show a visible join along that edge, whereas Flash will seamlessly meld the two together, with no difference visible if they're the same color. I've put together a minimal page here to show the issue:
http://web.mailana.com/labs/stitchingbug/
[Gak, spam prevention stops this from being an image, but see here for a screenshot web.mailana.com/labs/stitchingbug.png ]
The source, along with a Flash project doing the same thing, is here:
github.com/petewarden/stitchingbug
The fundamental issue is that it's impossible to do any complex polygonal rendering if you can't stitch 开发者_如何学JAVApolygons together without seams. I don't know exactly what Flash's fill rules are, but they produce the correct results, as do 3D renderers. Does anyone have a client-side fix to work around this problem? It's cross-browser, which makes it seem deliberate, so any references to the rules used would also be appreciated. Here's the Canvas code:
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(0,0,0)';
ctx.beginPath()
ctx.moveTo(0, 0);
ctx.lineTo(50.5, 0);
ctx.lineTo(50.5, 100);
ctx.lineTo(0, 100);
ctx.closePath();
ctx.fill();
ctx.beginPath()
ctx.moveTo(50.5, 0);
ctx.lineTo(100, 0);
ctx.lineTo(100, 100);
ctx.lineTo(50.5, 100);
ctx.closePath();
ctx.fill();
This is an old question, but I had the same problem.
I find that drawing a single line between the two polygons (or an outline around them) solves the problem (in firefox and chrome at least).
That seems to fill the gap in chrome and firefox at least. It is sufficient to call ctx.stroke()
after ctx.fill()
, or draw a single line as follows:
ctx.beginPath()
ctx.moveTo(50.5, 0);
ctx.lineTo(50.5, 100);
ctx.stroke();
and be sure to set the strokeStyle of course.
Have you considered truncating all drawing coords? It shouldn't reduce quality, and it might fix your issue.
You could also draw a line over the troubling area to make the issue invisible.
If all else fails, that should work.
I can see the same issue in Chrome 41.0.2272.89 m even when the coordinates are all integers: http://jsfiddle.net/xgd03fyb/
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.lineWidth = 0;
context.fillStyle = 'black';
context.beginPath();
context.moveTo(100, 100);
context.lineTo(200, 200);
context.lineTo(200, 100);
context.closePath();
context.fill();
context.beginPath();
context.moveTo(100, 100);
context.lineTo(100, 200);
context.lineTo(200, 200);
context.closePath();
context.fill();
I suspected that the problem might be caused by clockwise / counter-clockwise mismatch, as in some libraries I used to use in the past this would affect which edges are being drawn as solid, which as transparent, and which as antialiased. However, changing the order of lineTo() calls in the second triangle does not seem to have any effect.
I've also tried chaning the fillStyle (the argument passed to fill()) from "evenodd"
from the default "nonzero"
, with no luck.
It's not clear for me from the spec https://html.spec.whatwg.org/multipage/scripting.html#dom-context-2d-fill how this should work so I've filed the bug to learn more: https://www.w3.org/Bugs/Public/show_bug.cgi?id=28217
精彩评论