Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Complex shape with rainbow gradient

I'm trying to draw a figure on a canvas, to be filled with a rainbow-colored gradient. The wanted result is something like this:

Wanted result

Creating the shape itself is pretty easy, just creating a path and drawing the lines. However, actually filling it with a gradient appears to be somewhat more difficult, as it seems only radial and linear gradients are supported.

The closest I have gotten is this:

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var gradient=ctx.createLinearGradient(0,0,0,100);
gradient.addColorStop (0, 'red');
gradient.addColorStop (0.25, 'yellow');
gradient.addColorStop (0.5, 'green');
gradient.addColorStop (0.75, 'blue');
gradient.addColorStop (1, 'violet');
ctx.moveTo(0,40);
ctx.lineTo(200,0);
ctx.lineTo(200,100);
ctx.lineTo(0, 50);
ctx.closePath();
ctx.fillStyle = gradient;
ctx.fill();
<body onload="draw();">
   <canvas id="canvas" width="400" height="300"></canvas>
 </body>

The gradient colors and such are correct, but the gradient should of course be more triangular-like, rather than being rectangular and cropped.

like image 437
Fredrik Jonsén Avatar asked Sep 25 '22 10:09

Fredrik Jonsén


1 Answers

Native html5 canvas doesn't have a way to stretch one side of a gradient fill.

But there is a workaround:

Create your stretch gradient by drawing a series of vertical gradient lines with an increasing length.

enter image description here

Then you can use transformations to draw your stretched gradient at your desired angle

enter image description here

Example code and a Demo:

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var length=200;
var y0=40;
var y1=65
var stops=[
    {stop:0.00,color:'red'},
    {stop:0.25,color:'yellow'},
    {stop:0.50,color:'green'},
    {stop:0.75,color:'blue'},
    {stop:1.00,color:'violet'},
];

var g=stretchedGradientRect(length,y0,y1,stops);

ctx.translate(50,100);
ctx.rotate(-Math.PI/10);
ctx.drawImage(g,0,0);


function stretchedGradientRect(length,startingHeight,endingHeight,stops){
    var y=startingHeight;
    var yInc=(endingHeight-startingHeight)/length;
    // create a temp canvas to hold the stretched gradient
    var c=document.createElement("canvas");
    var cctx=c.getContext("2d");
    c.width=length;
    c.height=endingHeight;
    // clip the path to eliminate "jaggies" on the bottom
    cctx.beginPath();
    cctx.moveTo(0,0);
    cctx.lineTo(length,0);
    cctx.lineTo(length,endingHeight);
    cctx.lineTo(0,startingHeight);
    cctx.closePath();
    cctx.clip();
    // draw a series of vertical gradient lines with increasing height
    for(var x=0;x<length;x+=1){
        var gradient=cctx.createLinearGradient(0,0,0,y);
        for(var i=0;i<stops.length;i++){
            gradient.addColorStop(stops[i].stop,stops[i].color);
        }
        cctx.beginPath();
        cctx.moveTo(x,0);
        cctx.lineTo(x,y+2);
        cctx.strokeStyle=gradient;
        cctx.stroke();
        y+=yInc;
    }
    return(c);
}
#canvas{border:1px solid red; margin:0 auto; }
<h4>Stretched gradient made from vertical strokes</h4>
<canvas id="canvas" width=300 height=200></canvas>
like image 81
markE Avatar answered Oct 03 '22 02:10

markE