I still get requests for an HTML5 implementation of OpenHeatMap, so I guess I've done a terrible job of telling people about the Canvas-based renderer I've had in there since it launched. The confusion comes about because I default to Flash if your browser has it installed, since it's usually faster and there's still one problem with the Canvas implementation that I haven't been able to fix.
If you look at the screenshot above, you'll see pale white lines within the states. Those are boundaries between the internal polygons that they're made of, and in the Flash version they don't show up. The fundamental problem is that 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/
The source, along with a Flash project doing the same thing and producing the expected results, is here:
http://github.com/petewarden/stitchingbug
The fundamental issue is that it's impossible to do any complex polygonal rendering if you can't stitch polygons together without seams. I don't know exactly what Flash's fill rules are, but they produce the correct results, as do the 3D renderers I've used in the past. 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();
Anybody have any insights on this? I'd love to deprecate the Flash version, but I need to understand what's going on here, and I'm at a dead end. I'd love to hear there's something obvious I'm doing wrong.
Update – Thanks for the suggestions. I purposely simplified the example to avoid alpha, but that's the issue that most of the 'stroke()' approaches I'd already tried hit. I've included code to demo that below. I'm really not trying to be a jerk about this, honestly I'd love to know that I'm an idiot, as long as I find a solution. The public humiliation will be worth it, I swear.
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.strokeStyle = 'rgba(0,0,0,0.5)'
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.stroke();
ctx.beginPath()
ctx.moveTo(50.5, 0);
ctx.lineTo(100, 0);
ctx.lineTo(100, 100);
ctx.lineTo(50.5, 100);
ctx.closePath();
ctx.fill();
ctx.stroke();
Add:
ctx.strokeStyle = ‘rgb(0,0,0)’;
and after ctx.fill():
ctx.stroke();
Thanks for the article. Although it’s fairly old now, it still seems relevant. I’m joining many polygons using the same coords for the common edges, and I still get visible seams. For my needs, the fills will have transparency and so using strokes is not an option. Any new info on this issue?