Reputation: 692
I'm trying to rotate an N sided polygon on the canvas and I'm having issues with the coordinates. The shapes seem to be rotating about an origin which is outside of themselves (I'd like the origin to be the centre of the shape). Any tips would be much appreciated.
var x = 50;
var y = 50;
var tranx;
var trany;
x -= tranx = x + shape.radius;
y -= trany = y + shape.radius;
elem.translate(tranx,trany);
elem.rotate(90 * radian);
var k = 0,
angle = 360/shape.sides;
elem.moveTo(x,y);
for (; k <shape.sides; k++) {
elem.lineTo(x+=Math.cos( ( angle * k )* radian) * shape.radius, y+=Math.sin( ( angle * k )* radian) * shape.radius);
}
Upvotes: 2
Views: 2593
Reputation: 3792
I put together a couple of functions to rotate regular polygons. The first step is generating a list of (x, y) coordinates that's separate from <canvas>
entirely. It's important to note that to get a phase shift (which will ultimately cause the polygon to rotate), you have to add your rotation to the statement within the cosine and sine functions:
Math.cos(rotation + (i * 2 * Math.PI / numberOfSides))
Math.sin(rotation + (i * 2 * Math.PI / numberOfSides))
Here's a working example of generating a canvas with a regular polygon, and rotating the polygon around its own origin:
var canvas = document.querySelector('canvas');
var polygon = {
sides: 3,
radius: 50,
phase: 0
};
document.addEventListener('click', function(e) {
switch (e.target.id) {
case "-side":
polygon.sides--;
break;
case "+side":
polygon.sides++;
break;
case "-phase":
polygon.phase -= Math.PI / 12;
break;
case "+phase":
polygon.phase += Math.PI / 12;
break;
}
drawPolygon(canvas, polygon.sides, polygon.radius, polygon.phase);
});
function generateCoordinates(centerX, centerY, numberOfSides, radius, rotation) {
var coordinates = [];
for (var i = 0; i < numberOfSides; i++) {
coordinates.push({
x: parseFloat((centerX + radius * Math.cos(rotation + (i * 2 * Math.PI / numberOfSides))).toFixed(4)),
y: parseFloat((centerY + radius * Math.sin(rotation + (i * 2 * Math.PI / numberOfSides))).toFixed(4))
})
}
return coordinates;
};
function drawPolygon(canvas, numberOfSides, radius, rotation) {
var context = canvas.getContext('2d');
canvas.height = radius * 2;
canvas.width = radius * 2;
var coordinates = generateCoordinates(radius, radius, numberOfSides, radius, rotation);
context.strokeStyle = "black";
context.beginPath();
coordinates.forEach(function(coordinate, index) {
if (index === 0) {
context.moveTo(coordinate.x, coordinate.y);
} else {
context.lineTo(coordinate.x, coordinate.y);
}
});
context.closePath();
context.stroke();
}
drawPolygon(canvas, polygon.sides, polygon.radius, polygon.phase);
<canvas></canvas>
<div>
<button id="-side">fewer sides</button>
<button id="+side">more sides</button>
</div>
<div>
<button id="-phase">minus phase shift</button>
<button id="+phase">plus phase shift</button>
</div>
Upvotes: 3
Reputation: 868
Well, the first solution, somewhat a hack, would be the following: add a parameter rotation_angle to the shape object. Then your loop should change in the following way:
k=0;
elem.moveTo(
x+=Math.cos( ( angle * k +shape.rotation_angle)* radian) * shape.radius,
y+=Math.sin( ( angle * k +shape.rotation_angle)* radian) * shape.radius);
for(k=1;k<shape.sides;k++){
elem.lineTo(
x+=Math.cos( ( angle * k +shape.rotation_angle)* radian) * shape.radius,
y+=Math.sin( ( angle * k +shape.rotation_angle)* radian) * shape.radius);
}
The second solution rely on assumption that elem is a canvas context and the center of the polygon should be at the coordinate (x,y).
Then I guess, the correct sequence will be the following:
elem.translate(x,y); //Translate the origin to the center of polygon.
elem.rotate(rotation_angle); // Rotate the context around the origin
var k=0;
elem.moveTo(shape.radius,0);
for(k=1;k<shape.sides;k++){
elem.lineTo(Math.cos(k*angle*radian)*shape.radius,
Math.sin(k*angle*radian)*shape.radius);
}
Upvotes: 1