I am using ctx.translate(x, y) to move Camera in canvas game. But for some reason, that doesn't work.
This is what I am using:
setCameraPos: function(x, y) {
//ctx.save()
ctx.translate(x, y)
ctx.setTransform(1, 0, 0, 1, 0, 0)
//ctx.restore()
}
It doesn't work at all. It does not change position of camera.
Any errors? No errors at all.
I am using Electron 3.0.3 Beta.
I accept any libraries.
const canvas = document.getElementById('main')
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'red'
ctx.fillRect(0, 0, 30, 30)
// This doesn't work | VVV
ctx.translate(20, 20)
ctx.setTransform(1, 0, 0, 1, 0, 0)
#main {
background-color: black;
}
<canvas id="main">
</canvas>
From what you gave, the translate operation won't work anywhere, not just in Electron.
ctx.setTransform() method sets the transformation matrix to absolute values, the current matrix is discarded and the passed values are the ones to which your matrix will get set.
1, 0, 0, 1, 0, 0 are the values of the native matrix transform (i.e untransformed).
So calling ctx.setTransform(1, 0, 0, 1, 0, 0) will reset your tranform matrix to its default and make all calls to relative translate(), rotate() or transform() useless.
These methods are meant to be relative because they add up to the current matrix values. For instance,
ctx.translate(10, 10);
// here next drawing will be offset by 10px in both x and y direction
ctx.translate(40, -10);
// this adds up to the current 10, 10, so we are now offset by 30, 0
If you want your translate to work, don't call setTransform here, or even replace it with setTransform(1, 0, 0, 1, 20, 20)
Also, in your snippet, you are setting the transformation matrix after you did draw. The transformations will get applied only on next drawings, not on previous ones.
Now, you might be in an animation loop, and need your matrix to get reset at every loop.
In this case, call ctx.setTransform(1,0,0,1,0,0) either at the beginning of your drawing loop, either as the last op, and call translate() before drawing.
const canvas = document.getElementById('main');
const ctx = canvas.getContext('2d');
let x = 0;
ctx.fillStyle = 'red'
anim();
function draw() {
// reset the matrix so we can clear everything
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
//set the transform before drawing
ctx.translate(x - 30, 20)
//which is actually the same as
//ctx.setTransform(1, 0, 0, 1, x, 20);
ctx.fillRect(0, 0, 30, 30);
}
function anim() {
x = (x + 2) % (canvas.width + 60);
draw();
requestAnimationFrame(anim);
}
#main {
background-color: black;
}
<canvas id="main"></canvas>
Related
I'm trying to make a simple multiplayer game with HTML, and I can't figure out how to fix the problem with only 1 player being shown. Here's the relevant code:
socket.on('newpos', function(data){
var transform = ctx.getTransform();
var camX, camY;
for(var i = 0 ; i < data.player.length; i++){
ctx.translate(camX, camY);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,10000,10000);
ctx.setTransform(transform);
ctx.drawImage(background, 0, 0, 10000,10000);
ctx.setTransform(1, 0, 0, 1, 0, 0);
if(ID == data.player[i].id){
camX = -data.player[i].x + canvas.width / 2;
camY = -data.player[i].y + canvas.height / 2;
}
ctx.translate(camX,camY);
ctx.drawImage(img, (data.player[i].x),(data.player[i].y),32,32);
});
The code here loops through all the players on the server. It draws the different player's perspectives, but only the last player that joined is visible.
I've tried changing the transforms in different places and everything else I could think of, not sure what to do.
That's because you clear the entire canvas at every iteration, so only the last is visible
Take out/change the position of
ctx.clearRect(0,0,10000,10000)
Also the above code as of now should give an error since it appears the closing bracket of the for loop is missing
I'm using ctx.globalCompositeOperation = 'destination-over'. Though the text still goes behind.
Game.setup();
ctx = Game.context;
if (AllImagesLoaded === true) {
loading = false;
clearInterval(int);
BackgroundsA.push(true);
ctx.globalCompositeOperation = 'destination-over';
Interact = new text(window.innerWidth / 2, window.innerHeight / 2 - 200, 'Press F to Interact', 'white', '30px Verdana');
Sprites.push(new sprite(window.innerWidth / 2 - 275, window.innerHeight / 2 - 315, 'idle_jack/frame_1.PNG', 600, 600, 5));
Player = new component(window.innerWidth / 2, window.innerHeight / 2 - 100, 'rgba(0, 0, 0, 0)', 50, 150);
ctx.globalCompositeOperation = 'source-over';
Backgrounds.push(new background(0, 0, 'Backgrounds/Test/test2.jpg'));
ctx.globalCompositeOperation = 'destination-over';
The "new [KEYWORDS]" are functions for filling or drawing text/components/images.
Please help!
Why don't you draw everything from behind, i.e. firstly draw the backgrounds of the game, then text and at the end player and all of the game objects ?
However if you do want to draw everything like you're trying to now, then try changing global composite operation just before drawing, it's not clear if new Background() will actually draw the background or not from your code. Here is an article to read about global composite operation:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
I'm trying to make it so that when I clicked the button to change the radius size, it would change all the circle's radius size into a random size between 5-10.
I've already tried to draw 2 circles (1 black, 1 blue) and call then tried to change the radius to a new random radius size between 5-10. After adding my function, I cannot see the 2 circles I have drawn. Any feedback is greatly appreciated.
<canvas width="300" height="300" id="myCanvas" style="border: 1px solid black"></canvas>
<button id="changeRadius">Change Size</button>
<script>
var number = Math.min(Math.max(paraseInt(number), 5), 10);
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
ctx.translate(100,120);
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.translate(140,120);
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
document.getElementById("changeRadius").onclick = function() {
ctx.clearRect
ctx.translate(100,120);
ctx.beginPath();
ctx.arc(0, 0, "number", 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.translate(140,120);
ctx.beginPath();
ctx.arc(0, 0, "number", 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
if (event.keycode == s){
ctx.translate(100,120);
ctx.beginPath();
ctx.arc(0, 0, 5, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.translate(140,120);
ctx.beginPath();
ctx.arc(0, 0, 5, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
}else if (event.keycode == b) {
ctx.translate(100,120);
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
ctx.translate(140,120);
ctx.beginPath();
ctx.arc(0, 0, 10, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
}
}
</script>
There are many simple mistakes in the code.
1.
Where you call clearRect, you have:
ctx.clearRect
but it needs to be:
ctx.clearRect(x, y, width, height);
where x, y, width and height define the rectangle that you want to clear. To clear the whole canvas, use:
ctx.clearRect(0, 0, canvas.width, canvas.height);
2.
You have misspelled parseInt as paraseInt.
3.
Where you have put "number" as the radius in the calls to ctx.arc... I don't even know what you are trying to achieve. It looks like a placeholder? Anyway, it needs to be an actual number, not just the string "number".
Perhaps you intended to use the variable number that you create at the top and never use?
ctx.arc(0, 0, "number", 0, 2 * Math.PI);
becomes
ctx.arc(0, 0, number, 0, 2 * Math.PI);
(notice no " characters)
4.
You never actually update the value of number, so even the above won't do anything.
Michael, your question has been on SO for some time but hopefully this answer might still be useful to you as well as others still learning JavaScript. Once I addressed basic syntax issues listed by Mat, the missing circles became visible. At that point I discovered three things.
images drawn on your canvas may not appear where you expect them.
a variable declared and initialised as number in your first
statement does not generate a valid number let alone a random number.
your code has if and if else statements that will not do anything
without an event handler.
#1
Your code uses ctx.arc() to draw a basic circle and ctx.translate() to move it into position on the canvas. With ctx.translate() two parameters x and y determine how far to move the circle; x is the distance to move in the horizontal direction; y is the distance to move in the vertical direction.
The problem is that you no longer know the position coordinates on the canvas after the move. For this reason the origin needs to be reset before proceeding to the next ctx.translate() operation.
To reset the origin use CanvasRenderingContext2D.setTransform()e.g.
ctx.setTransform(1, 0, 0, 1, 0, 0);
from Mozilla MDN
The CanvasRenderingContext2D.setTransform() method of the Canvas 2D
API resets (overrides) the current transformation to the identity
matrix, and then invokes a transformation described by the arguments
of this method. This lets you scale, rotate, translate (move), and
skew the context.
This API is designed for animated drawing with a variety of methods for transforming 2D shapes dynamically. For the purposes of your code it is enough to understand that by clearing the identity matrix you restore 0,0 (the canvas origin) as the reference for x and y values used in any drawing operation that follows. Before you use ctx.translate() reset the origin. Watch the difference this will make when the code launches.
effect of origin reset at launch
without / with
Whenever a new image is drawn the entire canvas must first be cleared using ctx.clearRect()and it is important to reset the origin before doing so. Click the 'Change Size' button in each example to see that the entire screen is cleared with an origin reset. Without a reset the origin of the cleared rectangle will align with the centre of the last circle drawn i.e. the cleared rectangle eats into the lower right quadrant of the circle.
effect of origin reset on clearing the canvas
without / with
#2
The second problem can be demonstrated by inserting alert(number) following the first instruction. When the code runs, alert reports a NaN message (i.e. not a number). Also, random values lie within a range from 0.0 to 1.0 but for your purposes can be scaled to a range from 5.0 to 10.0 (for more see here and here).
The code below shows getNewRadius(), a function that generates a random number whenever the 'Change Size' button is clicked. Before the function is called constants and variables are declared and initialised. Every time the function is called, i.e. with every mouse click, it returns a new random value of radius which is then passed as an argument to the next drawing function.
For clarity I renamed your variable number to the more self-explanatory radius and replaced magic numbers in your code with some aptly named constant or var.
#3
Statements within the scope of your if and else if tests will never be executed. Testable values are potentially created at runtime by a keyboard event (i.e. event.keycode). But in your code no handler has been set up to listen for such an event. Moreoever, Mozilla MDN advises that keyCode is obsolete and makes the following recommendation
MDN Warning: This attribute is deprecated; you should use
KeyboardEvent.key instead, if available.
For a more comprehensive summary of keyboard event options see here.
The code below includes a basic function called setMaxOrMinRadius(e) that allows maximum or minimum radius values to be selected by typing on a keyboard. In keeping with your initial code, typing s will select minRadius, typing b will select maxRadius. This function will only be recognised if a key is pressed and the event listener has been initialised. If the event listener detects a keystroke it will now be able to switch to the function and recognise which key has been pressed.
Acknowledgement
This answer is a collaborative effort between fellow retiree and former colleague Bob Douglas and myself. We have been learning JavaScript together for two months. We welcome suggestions for improvement.
Code
<canvas width="300" height="300" id="myCanvas" style="border: 1px solid black"></canvas>
<button id="changeRadius">Change Size</button>
<script>
const maxRadius = 10;
const minRadius = 5;
var range = maxRadius - minRadius;
var radius = maxRadius;
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
document.addEventListener('keydown', setMaxOrMinRadius);
drawCircles(maxRadius);
document.getElementById("changeRadius").onclick = function() {
clearCanvas();
radius = getNewRadius();
drawCircles(radius);
}
function setMaxOrMinRadius(e) {
clearCanvas();
switch (e.which) {
case 83: // type 's'
drawCircles(minRadius);
break;
case 66: // type 'b'
drawCircles(maxRadius);
break;
}
}
function getNewRadius() {
var radius = (Math.random() * minRadius) + range;
return radius;
}
function drawCircles(radius) {
drawBlueCircle(radius);
drawBlackCircle(radius);
}
function clearCanvas(){
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset origin
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function drawBlackCircle (radius) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset origin
ctx.translate(100,120);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
}
function drawBlueCircle (radius) {
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset origin
ctx.translate(140,120);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
}
I`m new with canvas so thanks for your patience.
I wrote an engine that is creating 2 different layers in 2 canvas elements which are one over another. They contain some generated pictures, which aren`t important here.
I'm trying to create an effect which will display bottom layer when I move mouse over the top layer and click.
Something like this:
This is what I have tried so far:
To use transparency on canvas element and display bottom canvas (fast but not usable)
Re-create a clipping region.
Whenever I press the mouse I store current coordinates and re-render the canvas with updated clipping region
Updating clipping region is slow if I use stroke to create shadows + I`m not sure how to remove lines from it (see picture).
If I remove shadow effect, it works really fast, but I need to have it.
The only thing that comes on my mind how to speed this, is to save coordinates of every click, and then to re-calculate that into 1 shape and drop a shadow on it - I`ll still have lines, but it will be faster because there won`t be thousand of circles to draw...
Any help will be most appreciated!
You can take advantage of the browser's built in interpolation by using it as a pseudo low-pass filter, but first by painting it black:
Copy the top layer to the bottom layer
Set source-in comp. mode
Draw all black
Set source-in comp. mode
Scale down image to 25%
Scale the 25% region back up to 50% of original (or double of current)
Scale the now 50% region back up to 100% of original. It will be blurred.
Depending on how much blur you want you can add additional steps. That being said: blurred shadow is an intensive operation no matter how it is twisted and turned. One can make compromise to only render the shadow on mouse up for example (as in the demo below).
Example
Example using two layers. Top layer let you draw anything, bottom will show shadow version at the bottom later while drawing.
var ctx = document.getElementById("top").getContext("2d"),
bctx = document.getElementById("bottom").getContext("2d"),
bg = new Image(),
isDown = false;
bg.src = "http://i.imgur.com/R2naCpK.png";
ctx.fillStyle = "#27f";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.globalCompositeOperation = "destination-out"; // "eraser"
ctx.canvas.onmousedown = function(e) {isDown = true};
window.onmousemove = function(e) {
if (!isDown) return;
var pos = getPos(ctx.canvas, e);
ctx.beginPath();
ctx.moveTo(pos.x + 10, pos.y);
ctx.arc(pos.x, pos.y, 10, 0, 2*Math.PI); // erase while drawing
ctx.fill();
};
window.onmouseup = function(e) {
if (isDown) {
isDown = false;
makeShadow();
}
};
function makeShadow(){
var w = bctx.canvas.width,
h = bctx.canvas.height,
offset = 7,
alpha = 0.75;
// reset alpha
bctx.globalAlpha = 1;
// normal comp mode to clear as it is faster than using "copy"
bctx.globalCompositeOperation = "source-over";
bctx.clearRect(0, 0, w, h);
// copy top-layer to bottom-layer
bctx.drawImage(ctx.canvas, 0, 0);
// comp. mode will only draw in to non-alpha pixels next
bctx.globalCompositeOperation = "source-in";
// black overlay
bctx.fillRect(0, 0, w, h);
// copy mode so we don't need an extra canvas
bctx.globalCompositeOperation = "copy";
// step 1: reduce to 50% (quality related - create more steps to increase blur/quality)
bctx.drawImage(bctx.canvas, 0, 0, w, h, 0, 0, w * 0.5, h * 0.5);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, 0, 0, w * 0.25, h * 0.25);
bctx.drawImage(bctx.canvas, 0, 0, w * 0.25, h * 0.25, 0, 0, w * 0.5, h * 0.5);
// shadow transparency
bctx.globalAlpha = alpha;
// step 2: draw back up to 100%, draw offset
bctx.drawImage(bctx.canvas, 0, 0, w * 0.5, h * 0.5, offset, offset, w, h);
// comp in background image
bctx.globalCompositeOperation = "destination-over";
bctx.drawImage(bg, 0, 0, w, h);
}
function getPos(canvas, e) {
var r = canvas.getBoundingClientRect();
return {x: e.clientX - r.left, y: e.clientY - r.top};
}
div {position:relative;border:1px solid #000;width:500px;height:500px}
canvas {position:absolute;left:0;top:0}
#bottom {background:#eee}
<div>
<canvas id="bottom" width=500 height=500></canvas>
<canvas id="top" width=500 height=500></canvas>
</div>
In IE, I can use:
<img src="http://example.com/image.png" style="filter:FlipH">
to implement an image flip horizontally.
Is there any way to flip horizontally in HTML5? (maybe by using canvas?)
thanks all :)
canvas = document.createElement('canvas');
canvasContext = canvas.getContext('2d');
canvasContext.translate(width, 0);
canvasContext.scale(-1, 1);
canvasContext.drawImage(image, 0, 0);
Here's a snippet from a sprite object being used for testing and it produces the results you seem to expect.
Here's another site with more details. http://andrew.hedges.name/widgets/dev/
You don't need HTML5, it can be done with CSS same as in IE:
-moz-transform: scale(-1, 1);
-webkit-transform: scale(-1, 1);
-o-transform: scale(-1, 1);
transform: scale(-1, 1);
filter: FlipH;
I like Eschers function above. I have made it a little neater and better. I have added flop (vertically) besides flip. Also a possibility to draw/rotate around the center of the image instead of top left. Finally, the function does not require all arguments. img, x and y are required but the rest are not.
If you were using something like context.drawImage(...), you can now just use drawImage(...) and add the rotate/flip/flop functionality explained here:
function drawImage(img, x, y, width, height, deg, flip, flop, center) {
context.save();
if(typeof width === "undefined") width = img.width;
if(typeof height === "undefined") height = img.height;
if(typeof center === "undefined") center = false;
// Set rotation point to center of image, instead of top/left
if(center) {
x -= width/2;
y -= height/2;
}
// Set the origin to the center of the image
context.translate(x + width/2, y + height/2);
// Rotate the canvas around the origin
var rad = 2 * Math.PI - deg * Math.PI / 180;
context.rotate(rad);
// Flip/flop the canvas
if(flip) flipScale = -1; else flipScale = 1;
if(flop) flopScale = -1; else flopScale = 1;
context.scale(flipScale, flopScale);
// Draw the image
context.drawImage(img, -width/2, -height/2, width, height);
context.restore();
}
Examples:
var myCanvas = document.getElementById("myCanvas");
var context = myCanvas.getContext("2d"); // i use context instead of ctx
var img = document.getElementById("myImage"); // your img reference here!
drawImage(img, 100, 100); // just draw it
drawImage(img, 100, 100, 200, 50); // draw it with width/height specified
drawImage(img, 100, 100, 200, 50, 45); // draw it at 45 degrees
drawImage(img, 100, 100, 200, 50, 0, true); // draw it flipped
drawImage(img, 100, 100, 200, 50, 0, false, true); // draw it flopped
drawImage(img, 100, 100, 200, 50, 0, true, true); // draw it flipflopped
drawImage(img, 100, 100, 200, 50, 45, true, true, true); // draw it flipflopped and 45 degrees rotated around the center of the image :-)
Mirror an image or rendering using the canvas.
Note. This can be done via CSS as well.
Mirroring
Here is a simple utility function that will mirror an image horizontally, vertically or both.
function mirrorImage(ctx, image, x = 0, y = 0, horizontal = false, vertical = false){
ctx.save(); // save the current canvas state
ctx.setTransform(
horizontal ? -1 : 1, 0, // set the direction of x axis
0, vertical ? -1 : 1, // set the direction of y axis
x + (horizontal ? image.width : 0), // set the x origin
y + (vertical ? image.height : 0) // set the y origin
);
ctx.drawImage(image,0,0);
ctx.restore(); // restore the state as it was when this function was called
}
Usage
mirrorImage(ctx, image, 0, 0, true, false); // horizontal mirror
mirrorImage(ctx, image, 0, 0, false, true); // vertical mirror
mirrorImage(ctx, image, 0, 0, true, true); // horizontal and vertical mirror
Drawable image.
Many times you will want to draw on images. I like to call them drawable images. To make an image drawable you convert it to a canvas
To convert an image to canvas.
function makeImageDrawable(image){
if(image.complete){ // ensure the image has loaded
var dImage = document.createElement("canvas"); // create a drawable image
dImage.width = image.naturalWidth; // set the resolution
dImage.height = image.naturalHeight;
dImage.style.width = image.style.width; // set the display size
dImage.style.height = image.style.height;
dImage.ctx = dImage.getContext("2d"); // get drawing API
// and add to image
// for possible later use
dImage.ctx.drawImage(image,0,0);
return dImage;
}
throw new ReferenceError("Image is not complete.");
}
Putting it all together
var dImage = makeImageDrawable(image); // convert DOM img to canvas
mirrorImage(dImage.ctx, dImage, 0, 0, false, true); // vertical flip
image.replaceWith(dImage); // replace the DOM image with the flipped image
More mirrors
If you wish to be able to mirror along an arbitrary line see the answer Mirror along line
One option is to horizontally flip the pixels of images stored in ImageData objects directly, e.g.
function flip_image (canvas) {
var context = canvas.getContext ('2d') ;
var imageData = context.getImageData (0, 0, canvas.width, canvas.height) ;
var imageFlip = new ImageData (canvas.width, canvas.height) ;
var Npel = imageData.data.length / 4 ;
for ( var kPel = 0 ; kPel < Npel ; kPel++ ) {
var kFlip = flip_index (kPel, canvas.width, canvas.height) ;
var offset = 4 * kPel ;
var offsetFlip = 4 * kFlip ;
imageFlip.data[offsetFlip + 0] = imageData.data[offset + 0] ;
imageFlip.data[offsetFlip + 1] = imageData.data[offset + 1] ;
imageFlip.data[offsetFlip + 2] = imageData.data[offset + 2] ;
imageFlip.data[offsetFlip + 3] = imageData.data[offset + 3] ;
}
var canvasFlip = document.createElement('canvas') ;
canvasFlip.setAttribute('width', width) ;
canvasFlip.setAttribute('height', height) ;
canvasFlip.getContext('2d').putImageData(imageFlip, 0, 0) ;
return canvasFlip ;
}
function flip_index (kPel, width, height) {
var i = Math.floor (kPel / width) ;
var j = kPel % width ;
var jFlip = width - j - 1 ;
var kFlip = i * width + jFlip ;
return kFlip ;
}
For anyone stumbling upon this.
If you want to do more complex drawing, the other scale-based answers don't all work. By 'complex' i mean situations where things are more dynamic, like for games.
The problem being that the location is also flipped. So if you want to draw a small image in the top left corner of the canvas and then flip it horizontally, it will relocate to the top right.
The fix is to translate to the center of where you want to draw the image, then scale, then translate back. Like so:
if (flipped) {
ctx.translate(x + width/2, y + width/2);
ctx.scale(-1, 1);
ctx.translate(-(x + width/2), -(y + width/2));
}
ctx.drawImage(img, x, y, width, height);
Here x and y are the location you want to draw the image, and width and height are the width and height you want to draw the image.
I came across this page, and no-one had quite written a function to do what I wanted, so here's mine. It draws scaled, rotated, and flipped images (I used this for rending DOM elements to canvas that have these such transforms applied).
var myCanvas = document.getElementById("myCanvas");
var ctx = myCanvas.getContext("2d");
var img = document.getElementById("myimage.jpg"); //or whatever
var deg = 13; //13 degrees rotation, for example
var flip = "true";
function drawImage(img, x, y, width, height, deg, flip){
//save current context before applying transformations
ctx.save();
//convert degrees to radians
if(flip == "true"){
var rad = deg * Math.PI / 180;
}else{
var rad = 2*Math.PI - 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);
if(flip == "true"){
//flip the canvas
ctx.scale(-1,1);
}
//draw the image
ctx.drawImage(img, -width/2, -height/2, width, height);
//restore the canvas
ctx.restore();
}