matthew_360
matthew_360

Reputation: 6061

Canvas fill color bug in chrome

Here's a picture of the issue. I'm drawing this color wheel, and using

    var context = canvas.getContext("2d");
    ...
    context.fillStyle = "rgba(" + r + ", " + g + ", " + b + ", 1)";
    context.fill();

for each little differently colored section in the wheel.

the order of the browsers here are:
Chrome | Firefox | IE

Chrome | Firefox | IE

And for whatever reason it looks all messed up in Chrome. I'm not even really sure how to properly describe this issue so it's hard to look to see if this is a known issue.

edit: here's a fiddle https://jsfiddle.net/mattlokk/7whrmo8r/3/

edit 2: seems to only be happening in Chrome version 58.x, and it seems to work fine on some machines no matter what Chrome version.

Upvotes: 1

Views: 992

Answers (1)

Blindman67
Blindman67

Reputation: 54026

Workaround

Yes there does seam to be a bug with the arc function in chrome (I used Canary 60)

1st workaround

As a bug is not something you can solve you need to use a workaround. In this case a simple solution is to create a shadow function for arc.

// x,y center of arc
// r is radius
// start and end are in radians
// dir (optional) if truthy true draw path anti clock wise.
// returns undefined;
function arcFix (x, y, r, start, end, dir) {
    var ang;
    var step = 1 / r;
    if (dir) {
      end -= step / 2; // end bumped down by half a step to ensure rounding error does not miss end
      for (ang = start; ang > end; ang -= step) {  
          context.lineTo(
              Math.cos(ang) * r + x,
              Math.sin(ang) * r + y,
          );
      }
    } else {
      end += step / 2; // end bumped up half a step to ensure rounding error does not miss end
      for (ang = start; ang < end; ang += step) {  
          context.lineTo(
              Math.cos(ang) * r + x,
              Math.sin(ang) * r + y,
          );
      }
    }    
}

Add the above function and in the code where you render each colour segment replace the two ctx.arc calls calling the above function

context.beginPath();
context.moveTo(innerX1, innerY1);
context.lineTo(outerX1, outerY1);
// use shadow function
arcFix(centerX, centerY, (outerRadius - 1), startRadians, endRadians);
context.lineTo(innerX2, innerY2);
// use shadow function
arcFix(centerX, centerY, (innerRadius + 1), endRadians, startRadians, true);

Please note that the arcFix function is not a complete replacement for arc and has only been tested for this particular situation. You should test it (as you should test all code) if you use it else where.

2nd workaround

Removing the +1 and -1 from the radius fixes the problem as well. Not that you have incorrectly used the 2D context as the effect is creating a alpha gradient and that should not happen no matter where you add path segments.

context.lineTo(outerX1, outerY1);
context.arc(centerX, centerY, outerRadius , startRadians, endRadians);
//                                       ^ remove - 1
context.lineTo(innerX2, innerY2);
context.arc(centerX, centerY, innerRadius , endRadians, startRadians, true);
//                                       ^ remove + 1

Upvotes: 1

Related Questions