0

I have a 400x300 HTML Canvas and I'm trying to draw a sun using a circle and 7 triangles. To draw the triangles, I do a translate, rotate, translate as indicated on this SO Answer. However, some of the triangles overlap as though they have the same angle.

http://codepen.io/ralrom/pen/bgZYRO

I can't figure out what's wrong, I checked the calculated radians and they all fall between 0 and 2*PI.

var drawSun = function () {

    // Circle
    context.beginPath();
    context.arc(75, 75, 30, 0, Math.PI * 2, true);
    context.closePath();
    context.fill();

    context.save();

    // Triangles
    for (var i = 0; i < 7; i++) {

        // Rotate the canvas around a point
        angle = i * 360 / 7;
        console.log(angle, angle * Math.PI / 180);
        context.translate(75, 75);
        context.rotate(angle * Math.PI / 180);
        context.translate(-75, -75);

        // Draw the triangle
        context.beginPath();
        context.fillStyle = 'rgba(0,0,0,0.5)';
        context.moveTo(60, 35);
        context.lineTo(75, 15);
        context.lineTo(90, 35);
        context.closePath();
        context.fill();

        context.restore();
    }
}
Community
  • 1
  • 1
ralrom
  • 433
  • 3
  • 9

1 Answers1

2

Sometimes the answers here have lots of points but really are not that good. Using ctx.setTransform makes it a lot easier to deal with transformations as it completely replaces the existing transform. Thus there is no need to save the state to know where you are.

It also helps when rendering objects to always layout their coordinates around their own center of rotation. You move that center to where you need it.

Anyways below is how you can do it. The function will handle different point counts and is a little more organised without needless close paths, save restores and conversion from Deg to radians.

var ctx = canvas.getContext('2d');

var drawSun = function(x,y,rad,count) {
  var drawRay = function(ang){
    // Half width, note I get width from 2PI*r but as I need half I drop the 2
    var width = (Math.PI * (rad + 5)) / count;
    ctx.setTransform(1,0,0,1,x,y);
    ctx.rotate(ang);  
    ctx.beginPath();
    ctx.moveTo(-width, rad + 5);
    ctx.lineTo(0, rad + 20);
    ctx.lineTo(width, rad + 5);
    ctx.fill();
  }
  ctx.fillStyle = "#F90";
  ctx.setTransform(1,0,0,1,x,y); // move sun center to where it should be.
  ctx.beginPath();
  ctx.arc(0, 0, rad, 0, Math.PI * 2, true); // draw sun at 0,0
  ctx.fill();

  for (var i = 0; i < count; i++) {
    drawRay((i / count) * Math.PI * 2);
    // if you want to draw with first ray top center 
    // you need to offset by half a step
    //drawRay(((i / count)-(count/2)) * Math.PI * 2);
  }
  // done and if you want you can reset to the default transform with
  // ctx.setTransform(1,0,0,1,0,0);
}
drawSun(100,100,30,7);
<canvas id="canvas" width=200 height=200></canvas>
Blindman67
  • 51,134
  • 11
  • 73
  • 136