I just came across some unexpected behaviour on the HTML Canvas element; I tried to strip the problem down as much as I could. In short, it appears the ctx.fillText fails to render the text in specific regions of the canvas.
This is the smallest script I could write to consistently reproduce the bug (I tested it on different machines, OSs and browsers). It creates a black canvas (1.25×1.25 in drawing space units, 1000×1000 in pixels, the drawing space origin is in the middle) and draws red dots as the mouse passes over it, but there are several horizontal stripes in which it fails to do so.
// define boundaries of drawing space
const left = -.625;
const tops = -.625;
const scale = 800;
const width = 1.25;
const height = 1.25;
// create canvas
let canvas = document.createElement("canvas");
canvas.width = scale * width;
canvas.height = scale * height;
canvas.style.backgroundColor = "black";
document.body.appendChild(canvas);
// create context
let ctx = canvas.getContext("2d");
ctx.scale(scale, scale);
ctx.translate(-left, -tops);
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.font = `.03px arial`;
ctx.fillStyle = "rgba(208, 64, 64, 1)";
// coordinates follow mouse
addEventListener("mousemove", event => {
let mouseX = left + event.layerX / scale;
let mouseY = tops + event.layerY / scale;
ctx.fillText(".", mouseX, mouseY);
});
You can paste it in your dev-tools in about:blank and see for yourself. In any case here's a gif too:
As you can see, there are several horizontal stripes left untouched, even though I pass over them with the mouse. Also, the entirety of the bottom 80% of the canvas is unaffected.
A few important notes:
mousemove event is not the culprit, mouseX and mouseY update properly and smoothly.ctx.strokeText method, which works fine.ctx.fillPath.Am I doing something wrong? Or is this actually a bug?
The problem is the extremely small font size you're trying to render. You shouldn't use values like .03px - it makes sense for renderers to not be able to render something like that correctly, considering the typical smallest paintable size on a display is 1 pixel (a little smaller than that on high DPI displays, but probably not much less than .25px). It may work for painting simple lines, but rendering is more complicated than that (e.g. hinting).
Try the following values:
scale = 80width = 12.5height = 12.5ctx.font = `.3px arial`;Alternatively, try to paint a dot or a square rather than a "." string.
As a side note, I was able to reproduce the problem on Chrome, but on Firefox it actually renders fine.