Search code examples
htmlcanvastransitiongradientsmoothing

How to display a smoother gradient in HTML5 canvas?


I have a html5 canvas in my web page. I have only put an image and a gradient in it.

Canvas uses thic JS code to draw itself:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.clearRect ( 0 , 0 , canvas.width, canvas.height );
var img = document.getElementById("slika");
ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
var grd = ctx.createLinearGradient(x-400, 0, x, 0)
grd.addColorStop(0.3,"hsla(360, 100%, 100%, 0)");
grd.addColorStop(1,"hsla(360, 100%, 100%, 0.8)");
ctx.fillStyle=grd;
ctx.fillRect(0,0,canvas.width,canvas.height);

ctx.font = "70px Arial";
ctx.fillStyle = "black"
ctx.textAlign = "right";
ctx.fillText(textInput,canvas.width-50,canvas.height-120);

When it displays, the transition isn't very smooth, it just starts somewhere and ends somewhere.

It looks like this:

http://kendaj.net46.net/canvas-StackOverflow.png

I would like the transition to be smoother(I don't mean a wider gradient).

Is there any way to do that?

Thanks for answering.


Solution

  • Use a s-slope based gradient which could be defined using an ease-in-out function. This way the transition between flat and linear is smoothed out. You may need to compensate a little on the width as initial and final values are closer to the flat values than in the linear approach.

    easing

    Example

    result

    var ctx = document.querySelector("canvas").getContext("2d"), img = new Image();
    img.onload = function() {
    
      // init canvas and image
      ctx.canvas.width = this.naturalWidth;
      ctx.canvas.height = this.naturalHeight;
      ctx.drawImage(this, 0, 0);
        
      // gradient using ease-in-out
      var comp = 100;
      var grd = ctx.createLinearGradient(550 - comp, 0, 700 + comp, 0);
      
      for(var t = 0; t <= 1; t += 0.02) {    // convert linear t to "easing" t:
        grd.addColorStop(t, "hsla(360, 100%, 100%, " + easeInOut(t) * 0.8 + ")");
      }
      
      ctx.fillStyle = grd;
      ctx.fillRect(0,0, ctx.canvas.width, ctx.canvas.height * 0.5);
    
      // linear (as before)
      var grd = ctx.createLinearGradient(550, 0, 700, 0);
      grd.addColorStop(0, "hsla(360, 100%, 100%, 0)");
      grd.addColorStop(1, "hsla(360, 100%, 100%, 0.8)");
      ctx.fillStyle = grd;
      ctx.fillRect(0,ctx.canvas.height * 0.5+1, ctx.canvas.width, ctx.canvas.height * 0.5);
    };
    
    function easeInOut(t) {return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1}
    
    img.src = "//i.imgur.com/ESyzwQg.png";
    canvas {width:100%; height:auto}
    <canvas></canvas>