Calculate rotation of canvas gradient
Asked Answered
F

1

10

I'm trying to use a gradient to fill an area of a canvas, but I would like to be able to set the angle of the gradient.

I know this is possible by using different values in the creation of the gradient (ctx.createLinearGradient(x1, y1, x2, y2)) as seen here:

Gradient creation graphic

But I can't seem to get my head around the maths needed to convert an angle (radians) to a gradient size that will produce the same angle (The angle I'm referring to is perpendicular to the direction of the gradient, so a 0 radian angle would show the gradient on the right)

In short, how can I convert (quantity) of radians into an X by Y shape?

$(document).ready(function(){
    var canvas = document.getElementById("test");
    var ctx = canvas.getContext("2d");
    var angle = 0.5;
    
    ctx.beginPath();
    ctx.moveTo(100, 100);
    ctx.arc(100, 100, 100, 0, -angle, true);
    ctx.lineTo(100, 100);
    ctx.closePath();

    // Convert angle into coordinates to tilt the grad
    // grad should be perpendicular to the top edge of the arc
    var grad = ctx.createLinearGradient(0, 0, 0, 100);
    
    grad.addColorStop(0, "rgba(0,0,0,0)");
    grad.addColorStop(1, "rgba(0,0,0,0.8)");
    ctx.fillStyle = grad;
    ctx.fill();
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="test" width="500" height="500"></canvas>

(So no one wastes their time: I specifically don't want to use a context.rotate() in this case)

Filamentary answered 14/5, 2016 at 12:0 Comment(2)
hey @DBS, did you manage to get it work? i'm trying it with canvas, especially konva but can't seem to replicate the effect of CSS linear gradient. if u have any ideas, lmk. here's the codesandbox if u wanna take a look → codesandbox.io/s/linear-gradient-in-react-konva-cpgrk?file=/src/…Ciscaucasia
can you check out my question which is quite similar → #67347204Ciscaucasia
G
13

You can use the angle with cos and sin to define the line that gives the gradient. The only thing left then is to give the length:

var length = 100, angle = 0;
ctx.createLinearGradient(x, y, x + Math.cos(angle) * length, y + Math.sin(angle) * length);

The gradient will be rendered along (perpendicular) to the line given.

Not stated, but if you need to calculate the length of the line depending on the angle and box you can use the law of sines to do so (used in this way). The example below uses a fixed radius. You can also use max length from (x1, x2) by calculating the hypotenuse: length = Math.sqrt(diffX*diffX + diffY*diffY);.

Example

var ctx = c.getContext("2d"),
    x1 = 150, y1 = 150, x2, y2, angle,
    length = 150;

render();
cAngle.oninput = render;

function render() {
  
  angle = +cAngle.value / 180 * Math.PI;

  // calculate gradient line based on angle
  x2 = x1 + Math.cos(angle) * length;
  y2 = y1 + Math.sin(angle) * length;
  
  // create and render gradient
  ctx.fillStyle = ctx.createLinearGradient(x1, y1, x2, y2);
  ctx.fillStyle.addColorStop(0, "#fff");
  ctx.fillStyle.addColorStop(1, "#07f");
  ctx.fillRect(0, 0, 300, 300);
  
  // show definition line
  ctx.beginPath();
  ctx.moveTo(x1, y1);
  ctx.lineTo(x2, y2);
  ctx.stroke();
}
<label>Angle: <input id=cAngle max=359 type=range value=0></label><br>
<canvas id=c height=300></canvas>
Gastongastralgia answered 14/5, 2016 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.