Printing Mapbox GL JS maps in Firefox

I’m making a print/embed thing with Mapbox GL JS, and one of the problems I ran into involved printing with Firefox. As in, it doesn’t print.

Imgur

So, that’s a problem.

One of the neat things about being at/near the cutting edge is the great bugs you get to fiddle with. I’m serious about that. I like bugs. Bug sleuthing is the ultimate in problem solving, and problem solving is why I do what I do. Unless the software is closed source. In which case I hate bugs and I want my money back.

Hunting this particular bug brought me all the way to Bugzilla, which I got to by determining Firefox has problems printing all kinds of WebGL content.

This bug has been around for ~2.5 years, is unassigned, and seems to revolve around Firefox “not waiting for the next frame to actually start rendering…before clearing the framebuffer” when preserveDrawingBuffer is false. preserveDrawingBuffer is a WebGL context attribute.

Setting preserveDrawingBuffer to false is a performance optimization, so I wouldn’t set it to true by default for all browsers, or even for pages where you don’t expect much printing activity. Since my current thing is specifically for printing, I went with this:

1
2
3
4
5
6
7
8
9
10
11
12
13
// Firefox won't print a GL map unless preserveDrawingBuffer is set to true
function fixFirefoxPrint() {
return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
}

// map options
let mapOptions = {
container: 'map', // container id
style: "./style/style.json", //stylesheet location
zoom: 9.5,
center: [-80.83062,35.29418],
preserveDrawingBuffer: fixFirefoxPrint()
};

That sets preserveDrawingBuffer to true for Firefox, so printing works again.

The ideal solution would be to be able to change the preserveDrawingBuffer context attribute on the fly and link it to Firefox’s window.onbeforeprint, but WebGL context attributes are fixed at creation time and can’t be altered per the spec.