How do I rotate a single object on an html 5 canvas? - javascript

I'm trying to figure out how to rotate a single object on an html 5 canvas.
For example: http://screencast.com/t/NTQ5M2E3Mzct - I want each one of those cards to be rotated at a different degree.
So far, all I've seen are articles and examples that demonstrate ways to rotate the entire canvas. Right now, I'm guessing I'll have to rotate the canvas, draw an image, and then rotate the canvas back to it's original position before drawing the second image. If that's the case, then just let me know! I just have a feeling that there's another way.
Anyone have any idea?

I ran into the same problem in a recent project (where I kicked rotating aliens all over the place). I just used this humble function that does the same thing and can be used the same way as ctx.rotate but can be passed an angle. Works fine for me.
function drawImageRot(img,x,y,width,height,deg){
// Store the current context state (i.e. rotation, translation etc..)
ctx.save()
//Convert degrees to radian
var rad = deg * Math.PI / 180;
//Set the origin to the center of the image
ctx.translate(x + width / 2, y + height / 2);
//Rotate the canvas around the origin
ctx.rotate(rad);
//draw the image
ctx.drawImage(img,width / 2 * (-1),height / 2 * (-1),width,height);
// Restore canvas state as saved from above
ctx.restore();
}
Yay, my first answer!

Unfortunately in the HTML5 canvas element you can't rotate individual elements.
Animation works like drawing in MS Paint: You draw something, make a screen.. use the eraser to remove some stuff, draw something differently, make a screen.. Draw something else on top, make a screen.. etc etc.
If you have an existing item on the canvas - you'll have to erase it ( use ctx.fillRect() or clearRect() for example ), and then draw the rotated object.
If you're not sure how to rotate it while drawing in the first place:
ctx.save();
ctx.rotate(0.17);
// draw your object
ctx.restore();

To rotate a individual object you have to set the transformation matrix. This is really simple:
var context = document.getElementById('pageCanvas').getContext('2d');
var angle = 0;
function convertToRadians(degree) {
return degree*(Math.PI/180);
}
function incrementAngle() {
angle++;
if(angle > 360) {
angle = 0;
}
}
function drawRandomlyColoredRectangle() {
// clear the drawing surface
context.clearRect(0,0,1280,720);
// you can also stroke a rect, the operations need to happen in order
incrementAngle();
context.save();
context.lineWidth = 10;
context.translate(200,200);
context.rotate(convertToRadians(angle));
// set the fill style
context.fillStyle = '#'+Math.floor(Math.random()*16777215).toString(16);
context.fillRect(-25,-25,50,50);
context.strokeRect(-25,-25,50,50);
context.restore();
}
// Ideally use getAnimationFrame but for simplicity:
setInterval(drawRandomlyColoredRectangle, 20);
<canvas width="1280" height="720" id="pageCanvas">
You do not have a canvas enabled browser
</canvas>

Basically, to make an object rotate properly without having other shape rotating around, you need to:
save the context: ctx.save()
move the pivot point to the desired location: ctx.translate(200, 200);
rotate: context.rotate(45 * Math.PI / 180);
draw the shape, sprite, whatever: ctx.draw...
reset the pivot: ctx.translate(-200, -200);
restore the context to its original state: ctx.restore();
function spinDrawing() {
ctx.save();
ctx.translate(200, 200);
context.rotate(45 * Math.PI / 180);
ctx.draw //your drawing function
ctx.translate(-200, -200);
ctx.restore();
}
Caveats: After you translating , the origin of the canvas changed, which means when you drawing the shape, the coordinate of the shape should be aligned accordingly.
Shapes drawn outside the list mentioned above won´t be affected. I hope it helps.

This html/javascript code might shed some light on the matter:
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="233" height="233" style="border:1px solid #d3d3d3;">
your browser does not support the canvas tag </canvas>
<script type="text/javascript">
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var canvasWidth=233;
var canvasHeight=233;
var rectWidth=100;
var rectHeight=150;
var x=30;
var y=30;
var translateX= x+(rectWidth/2);
var translateY= y+(rectHeight/2);
ctx.fillRect(x,y,rectWidth,rectHeight);
ctx.translate(translateX,translateY);
ctx.rotate(5*Math.PI/64); /* just a random rotate number */
ctx.translate(-translateX,-translateY);
ctx.fillRect(x,y,rectWidth,rectHeight);
</script>
</body>
</html>
I find it helpful to see the math related to rotating, I hope this was helpful to you too.

<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="500" height="450" style="border:1px solid #d3d3d3;">
</canvas>
<Button id = "right" onclick = "rotateRight()">Right</option>
<Button id = "left" onclick = "rotateLeft()">Left</option>
<script src = "zoom.js">
</script>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
createRect();
function rotateRight()
{
ctx.save();
ctx.clearRect(0,0,500,450);
ctx.translate(c.width/2,c.height/2);
ctx.rotate(10*Math.PI/180 );
ctx.translate(-c.width/2,-c.height/2);
createRect();
}
function rotateLeft()
{
ctx.save();
ctx.clearRect(0,0,500,450);
ctx.translate(c.width/2,c.height/2);
ctx.rotate(-10*Math.PI/180 );
ctx.translate(-c.width/2,-c.height/2);
createRect();
}
function createRect()
{
ctx.beginPath();
ctx.fillStyle = "#AAAA00";
ctx.fillRect(250,250,90,50);
}
</script>
</body>
</html>

To rotate an object you can use rotate() method. Here the example how to rotate a rectangular object to 135 degrees of clockwise.
<script>
var canvas = document.getElementById('Canvas01');
var ctx = canvas.getContext('2d');
var rectWidth = 100;
var rectHeight = 50;
//create line
ctx.strokeStyle= '#ccc';
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width / 2, canvas.height);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.moveTo(0, canvas.height/2);
ctx.lineTo(canvas.width, canvas.height/2);
ctx.stroke();
ctx.closePath();
// translate ctx to center of canvas
ctx.translate(canvas.width / 2, canvas.height / 2);
// rotate the rect to 135 degrees of clockwise
ctx.rotate((Math.PI / 180)*135);
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, rectWidth, rectHeight);
</script>
</body>
Here the demo and you can try yourself: http://okeschool.com/examples/canvas/html5-canvas-rotate

I found this question because I had a bunch of stuff on a canvas, drawn with canvas lines, painstakingly, and then decided some of them should be rotated. Not wanting to do a whole bunch of complex stuff again I wanted to rotate what I had. A simple solution I found was this:
ctx.save();
ctx.translate(x+width_of_item/2,y+height_of_item/2);
ctx.rotate(degrees*(Math.PI/180));
ctx.translate(-(x+width_of_item/2),-(y+height_of_item/2));
// THIS IS THE STUFF YOU WANT ROTATED
// do whatever it is you need to do here, moveto and lineto is all i used
// I would expect anything to work. use normal grid coordinates as if its a
// normal 0,0 in the top left kind of grid
ctx.stroke();
ctx.restore();
Anyway - it might not be particularly elegant but its a dead easy way to rotate one particular element onto your canvas.
Look at all those rotated elements!

Related

HTML5 Canvas rotate function

function drawNumbers(){
var rad, num;
cx.font= "30px Arial";
cx.textAlign = "center";
cx.textBaseline = "middle";
//numbers around the inner circumference
for(num=1; num < 13; num++){
rad = num * Math.PI/6; //angle for every number
cx.rotate(rad);
cx.translate(0, -175);
cx.rotate(-rad);
cx.fillText(num.toString(),0,0);
cx.rotate(rad);
cx.translate(0, 175);
cx.rotate(-rad);
}
}
function drawHands(){
//getting the time
var time = new Date();
var hours = time.getHours();
var minutes = time.getMinutes();
var seconds = time.getSeconds();
//setting the radians based on the time
//hour hand
hours %= 12;
hours = (hours * Math.PI/6) + (minutes * Math.PI/360) + (seconds * Math.PI/21600);
hands(hours, radius * 0.04, radius * 0.5);
//minute hand
minutes = (minutes * Math.PI/30) + (seconds * Math.PI/1800);
hands(minutes, radius * 0.03, radius * 0.65);
//second hand
seconds = (seconds * Math.PI/30);
hands(seconds, radius * 0.01, radius * 0.68);
}
function hands(ang, width, length){
cx.beginPath();
cx.lineWidth = width;
cx.lineJoin = "round";
cx.lineCap = "round";
cx.moveTo(0, 0);
cx.rotate(ang);
cx.lineTo(0, -length);
cx.stroke();
cx.rotate(-ang);
}
I was learning the HTML5 canvas in W3Schools and the tutorial was teaching how to make a working clock.
1. I just don't understand how the extra rotates work in the functions.
2. When applying a rotate function, does it always rotate from the center of origin (0, 0) of the canvas?
When you call the rotate function it rotates the entire canvas, imagine holding a painting and then tilting it. It happens around the origin always. The way to rotate around a different point is to translate the entire canvas first, then rotate it.
Going back to the painting analogy, if we have rotated our painting, once we have drawn our line, we need to then restore the painting to being upright. Thus we rotate(-ang). If we had translated we would also have to undo our transation in a similar manner.
Rotating and why we undo rotates
In the code below you can see I'm drawing a base black rectangle, and then calling a function which rotates the canvas by 0.5 radians and draws another rectangle twice. I haven't undone my rotation so the 3rd rectangle is actually rotated at 1 radian.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
To fix this we modify the drawRotatedRectangle() function to undo all translations and rotations that it made:
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
ctx.rotate(-0.5);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
Now we see the red (hidden) rectangle and the green rectangle are at the same angle.
Rotating around a different point to the origin
To demonstrate how we can rotate around a different location to the origin, we can first translate where our context origin is and then rotate our canvas. Below I move the origin to the center of the base rectangle, rotate the canvas and draw a rotated rectangle ontop of the base rectangle. Again the translations and rotations are restored in order of most recently applied.
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
// Move origin to center of rectangle
ctx.translate(30, 25);
// Rotate 0.5 radians
ctx.rotate(0.5);
// Draw rectangle where the center of the rectangle is the origin
ctx.fillRect(-30, -25, 60, 50);
// Undo our rotate
ctx.rotate(-0.5);
// Undo our translate
ctx.translate(-30, -25);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
Edit - Handling Rounding Errors
As Kaiido mentioned in the comments, the rotate(a) function will round the input it is given so simply doing the reverse rotate(-a) function will not return you to the original transformation.
The solution they suggested is to set the transformation matrix to the desired location with setTransform(), in these example we are only returning to the original transform of the canvas so we can use the identity matrix:
ctx.setTransform(1,0,0,1,0,0)
Alternitively, you can also use save() and restore() methods. These will act like pushing the current state of the canvas context to a stack and when you restore() it will pop the latest state from the stack returning you to the previous transform. This article by Jakob Jenkov explains this method further with some examples.

How to detect if a mouse pointer hits a line already drawn on an HTML 5 canvas

I am trying to figure out how one can detect if the user's mouse hits a line on an HTML 5 canvas with jQuery.
Here is the code that generates the canvas lines:
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
window.onload = function(){
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.moveTo(40,0);
ctx.lineTo(40,360);
ctx.stroke();
ctx.moveTo(80,400);
ctx.lineTo(80,40);
ctx.stroke();
ctx.moveTo(120,0);
ctx.lineTo(120,360);
ctx.stroke();
ctx.moveTo(160,400);
ctx.lineTo(160,40);
ctx.stroke();
};
</script>
I'm using a modified jQuery script that I actually found in another question on here, but now I can't figure out how to detect the line, mainly the difference in color from white to black, in the canvas. I know that this can be done with images, but I haven't seen anyone with something like this.
I guess my real question is, is there a way to detect color changes on a canvas element with jQuery?
Its possible to do with javascript. In fact you aren't using any jQuery in your example above. An easy way to do it is by grabbing the pixel data from the canvas, and checking the alpha at the specified x and y position. If the alpha isn't set to 0, then you have something drawn on the canvas. Below is a function I put together real quick that does that.
Live Demo
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
width = 400;
height = 400;
canvas.width = canvas.height = 200;
// draw
ctx.moveTo(40, 0);
ctx.lineTo(40, 360);
ctx.stroke();
ctx.moveTo(80, 400);
ctx.lineTo(80, 40);
ctx.stroke();
ctx.moveTo(120, 0);
ctx.lineTo(120, 360);
ctx.stroke();
ctx.moveTo(160, 400);
ctx.lineTo(160, 40);
ctx.stroke();
function detectLine(x, y) {
var imageData = ctx.getImageData(0, 0, width, height),
inputData = imageData.data,
pData = (~~x + (~~y * width)) * 4;
if (inputData[pData + 3]) {
return true;
}
return false;
}
canvas.addEventListener("mousemove", function(e){
var x = e.pageX,
y = e.pageY;
console.log(detectLine(x, y));
});
console.log(detectLine(40, 100));
console.log(detectLine(200, 200));

JavaScript Rotate

I need to rotate an image before loading it into a canvas.
As far as I know, I cant rotate it using the canvas.rotate(), since that rotates the entire scene.
Is there a good JS way to rotate an image? [not the browser dependent ways]
not exactly, you can save the scene, rotate image then restore scene:
var canvas = document.getElementById('canvas');
canvas.width = 600;
canvas.height = 400;
var ctx = canvas.getContext('2d');
var image = new Image();
image.src = 'https://www.google.ro/images/srpr/logo3w.png';
drawRotatedImage(image, 275, 95, 25);
function drawRotatedImage(image, x, y, angle) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle * (Math.PI/180));
ctx.drawImage(image, -(image.width/2), -(image.height/2));
ctx.restore();
}
JSFiddle Example
well for u can use a css property transform to rotate, scale and translate html elements instead of using canvas for this you should use transform="rotate(xdeg)" if you want to rotate the image x degrees for continuously rotating the image use the following code.
see this your code
<html>
<img id="t1" src="1.png">
</html>
and this is your javascript code
<script>
var im;
var w,h;
var t=0;
window.onload=function()
{
im=document.getElementById('t1');
w=im.width;
h=im.height;
im.style.transform=im.style.webkitTransform|im.style.mozTransform|im.style.oTransform|i m.style.transform;
update();
};
function update()
{
im.style.transform="rotate("+t+"deg)";
t+=10;
setTimeout("update()",100);
}
</script>

How to rotate one image in a canvas?

I am making an HTML5 canvas game, and I wish to rotate one of the images.
var link = new Image();
link.src='img/link.png';
link.onload=function(){
ctx.drawImage(link,x,y,20,20); // draws a chain link or dagger
}
I wish to rotate this image. The standard way of rotating image was to set a rotation on the canvas context object. However, that rotates the entire game! I don't want to do that, and only wish to rotate this one sprite. How do I do that?
Use .save() and .restore() (more information):
link.onload=function(){
ctx.save(); // save current state
ctx.rotate(Math.PI); // rotate
ctx.drawImage(link,x,y,20,20); // draws a chain link or dagger
ctx.restore(); // restore original states (no rotation etc)
}
You might want to put a translate(); there because the image is going to rotate around the origin and that is in the top left corner by default so you use the translate(); to change the origin.
link.onload=function(){
ctx.save();
ctx.translate(x, y); // change origin
ctx.rotate(Math.PI);
ctx.drawImage(link,-10,-10,10,10);
ctx.restore()
}
Your original "solution" was:
ctx.save();
ctx.translate(x,y);
ctx.rotate(-this.angle + Math.PI/2.0);
ctx.translate(-x, -y);
ctx.drawImage(this.daggerImage,x,y,20,20);
ctx.restore();
However, it can be made more efficient (with no save or restore) by using this code:
ctx.translate(x,y);
ctx.rotate(-this.angle + Math.PI/2.0);
ctx.drawImage(this.daggerImage,x,y,20,20);
ctx.rotate(this.angle - Math.PI/2.0);
ctx.translate(-x, -y);
Look at my solution. It's full example and the easiest to understand.
var drawRotate = (clockwise) => {
const degrees = clockwise == true? 90: -90;
let canvas = $('<canvas />')[0];
let img = $(".img-view")[0];
const iw = img.naturalWidth;
const ih = img.naturalHeight;
canvas.width = ih;
canvas.height = iw;
let ctx = canvas.getContext('2d');
if(clockwise){
ctx.translate(ih, 0);
} else {
ctx.translate(0, iw);
}
ctx.rotate(degrees*Math.PI/180);
ctx.drawImage(img, 0, 0);
let rotated = canvas.toDataURL();
img.src = rotated;
}
Here i made a working example from one of my games. u can get the image from Here.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="100" height="100"></canvas>
<script type="text/javascript">
var ctx = document.getElementById('canvas').getContext('2d');
var play = setInterval('Rotate()',16);
var i = 0;
var shipImg = new Image();
shipImg.src = 'ship.png';
function Rotate() {
ctx.fillStyle = '#000';
ctx.fillRect(0,0,100,100);
ctx.save();
ctx.translate(50, 50);
ctx.rotate(i / 180 / Math.PI);
ctx.drawImage(shipImg, -16, -16);
ctx.restore();
i += 10;
};
</script>
</body>
</html>
I ended up having to do:
ctx.save();
ctx.translate(x,y);
ctx.rotate(-this.angle + Math.PI/2.0);
ctx.translate(-x, -y);
ctx.drawImage(this.daggerImage,x,y,20,20);
ctx.restore();

How to set a custom clipping zone for HTML5 Canvas?

I need to draw on a rectangle minus a circle. If the circle clipping is not possible, a polygonal clipping zone could be enough for my need.
How do I set a custom clipping zone for HTML5 Canvas?
You should read Compositing in the Canvas tutorial, it explains how you draw a rectangle minus a circle and similar figures.
I think you are looking for destination-out:
<!DOCTYPE html>
<html>
<head>
<script>
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.fillStyle = "#09f";
ctx.fillRect(15,15,70,70);
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "#f30";
ctx.beginPath();
ctx.arc(75,75,35,0,Math.PI*2,true);
ctx.fill();
}
</script>
</head>
<body>
<canvas id="canvas" width="400" height="300"/>
</body>
</html>
See it in action on jsFiddle.
Also you can use "clip" and than - "clear". Something like that:
drawRectangle(ctx);
walkCirclePath(ctx);
ctx.clip();
ctx.clear();
But antialiasing dont work in such way;
Well.
It was hard.
The best solution I found to draw every where except in a circle is
c.save();
c.beginPath();
c.moveTo(0, 0);
c.lineTo(x, 0);
c.arc(x, y, 75, - Math.PI / 2, Math.PI * 2 - Math.PI / 2, 1);
c.lineTo(x, 0);
c.lineTo(1000, 0);
c.lineTo(1000, 500);
c.lineTo(0, 500);
c.clip();
c.drawImage(window.tBitmap[0], x - 100, y - 100);
c.restore();
I can't believe taht there is not a better solution. But it's works for my need.

Categories