Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript and Canvas: How to get rid of that Moiré effect in my gyroscope

just out of fun I made that little toy top (gyroscope?), using Javascript and Canvas. Unfortunately there's an ugly Moiré effect on it (see screenshot below). http://jsfiddle.net/8bac4s9v/1/

function draw() {
    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    ctx.imageSmoothingEnabled = false;

    var colors = [
        ['blue', 'yellow'],
        ['white', 'pink'],
        ['green', 'red'],
        ['white', 'black'],
        ['green', 'blue'],
        ['red', 'green', 'blue']
    ];

    for (var i = 0; i < 12; i++) {
        for (var cIdx = 0, p = 0; p < 120; p += 20, cIdx++) {
            var cols = colors[cIdx];
            for (var r = p; r < p + 20; r++) {
                ctx.beginPath();
                ctx.arc(125, 125, r, (i - 1) * Math.PI / 6.0, i * Math.PI / 6.0);
                ctx.strokeStyle = cols[i % cols.length];
                ctx.stroke();
            }
        }
    }
}

I guess, that moiré effect comes from anti-aliasing. So I thought, I could get rid of that Moiré effect when I switch off anti-aliasing with ctx.imageSmoothingEnabled = false. But no, nothing changes.

Any ideas?

Thanks, Bernhard

This is how it looks: enter image description here

like image 652
Bernie Avatar asked Nov 16 '14 20:11

Bernie


2 Answers

The effect you're seeing basically is aliasing, so if anything, you would want to enable anti-aliasing. However, the imageSmoothingEnabled property is only used for pattern fills or drawImage, so it doesn't have any effect here.

For your example, instead of drawing 1px-wide concentric circles that change colors for every 20px increase in radius, I would recommend that you instead just draw 20px-wide concentric circles. That will solve the aliasing effect, and it also gets rid of one of your inner loops, so it should be a bit more efficient. Here's an updated fiddle - besides removing the loop, I also adjusted the boundary conditions on the loops as well:

http://jsfiddle.net/foskc95k/2/

ctx.lineWidth = 21;

for (var i = 0; i < 12; i++) {
    for (var cIdx = 0, r = 10; r <= 110; r += 20, cIdx++) {
        var cols = colors[cIdx];
        ctx.beginPath();
        ctx.arc(125, 125, r, (i - 1) * Math.PI / 6.0, i * Math.PI / 6.0);
        ctx.strokeStyle = cols[i % cols.length];
        ctx.stroke();
    }
}

Note also that I'm actually using a lineWidth of 21px instead of 20px because it seems to leave a 1px wide gap otherwise (I'm not sure why).

like image 110
Sergey K Avatar answered Nov 17 '22 01:11

Sergey K


You can increase the lineWidth of the context, eg ctx.lineWidth=2, that will solve the Moiré effect.

...
var ctx = c.getContext("2d");
ctx.imageSmoothingEnabled = false;
ctx.lineWidth=2;
...

http://jsfiddle.net/p4obo996/

But I think your gyroscope implementation is not very good. You should find a solutions that uses ctx.fillStyle and ctx.fill() instead of ctx.strokeStyle to set the color.

like image 2
Bavo Van Geit Avatar answered Nov 16 '22 23:11

Bavo Van Geit