How can I vertically rotate an image using only Canvas (without WebGL etc.)?
I'm looking at something like -webkit-transform: rotateY(); in CSS3.
[Edit: Oops! I think I misunderstood your question. You want to flip with 3D effect, just without webGL.]
Yes, you can do 3D rotations in canvas without webGL.
Several canvas libraries offer 3D canvas rotation...
Take a look and K3D (NICE effects!): http://www.kevs3d.co.uk/dev/canvask3d/k3d_test.html
Take a look at GreenSock: http://www.greensock.com/css3/
If you don't want any libraries at all, check out K3D. It's license is liberal enough to allow you to pull out the rotating code you need.
.
.
[My original answer below is probably off-track of what you want--but I'll leave it here anyway]
Here's how to vertically flip a canvas image
When you want to flip vertically, you ironically are flipping on the horizontal axis.
To flip on the horizontal axis you use context.scale like this:
context.scale(1,-1); // flip vertically--using the HORIZONTAL axis !
Here's code and a Fiddle: http://jsfiddle.net/m1erickson/JBCGC/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvasH=document.getElementById("canvasH");
var ctxH=canvasH.getContext("2d");
var img=new Image();
img.onload=function(){
// flip on the horizontal axis
// (causes upside down)
canvasH.width=img.width;
canvasH.height=img.height;
ctxH.save();
ctxH.scale(1,-1);
ctxH.translate(0,-img.height);
ctxH.drawImage(img,0,0);
ctxH.restore();
}
img.src="http://dl.dropbox.com/u/139992952/houseIcon.png";
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvasH" width=300 height=300></canvas>
</body>
</html>
You can try this -
// translate context to center of canvas
context.translate(canvas.width / 2, canvas.height / 2);
// rotate 45 degrees clockwise
context.rotate(Math.PI / 4);
The rotate transformation requires an angle in radians.
Reference
I like #markE answer, just figured I would post this one as well. It allows you to rotate the image to whatever angle you need.
function rotate(angle) {
ctxH.clearRect(0, 0, width, height);
ctxH.save();
ctxH.translate(width / 2, height / 2);
ctxH.rotate(angle * Math.PI / 180);
ctxH.drawImage(img, -width / 2, -height / 2);
ctxH.restore();
}
markE's Modified Demo (with animation)
Related
I'm aware that this has been asked a few times, but they are all using other libraries and I need it to work using just P5.js and JavaScript.
I have a basic game setup where players join a room using Express and Socket.io and spawn in as a ship. I want there to be a playable map area, and for what the client sees to be a section of that map with the client's ship in the middle
How can I achieve this with the HTML canvas through p5.js?
One way I've tried is to map the ship's coordinates on the whole playable area to just the width of the client's browser. This works well, but doesn't have the client's ship in the centre so they just drift off the screen if the move around enough.
Here's a diagram to explain what I'm trying to achieve:
The black box represents the whole playable area (the map).
Each green circle is a ship and each red box represents the client who is controlling that ship and the section of the map that they can see
What you're looking for is the translate function:
specifies an amount to displace objects within the display window. The x parameter specifies left/right translation, the y parameter specifies up/down translation.
You want the player to be the centre of their screen, thus you should translate such that the player is at the centre.
translate(width/2 - player.x, height/2 - player.y);
I've put together a really simple example that should point you in the right direction. It's basically just a circle that you can move around a game world, I've added a couple rectangles in so it's obvious you're moving the player with the arrow keys:
let player;
function setup() {
createCanvas(400, 400);
player = {
x: width/2,
y: height/2
}
}
function draw() {
background(220);
translate(width/2 - player.x, height/2 - player.y);
rect(-100, 100, 50, 50);
rect(100, 50, 50, 50);
if (keyIsDown(LEFT_ARROW)) {
player.x--;
} else if (keyIsDown(RIGHT_ARROW)) {
player.x++;
} else if (keyIsDown(UP_ARROW)) {
player.y--;
} else if (keyIsDown(DOWN_ARROW)) {
player.y++;
}
ellipse(player.x, player.y, 10, 10);
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
Also, here's a link to the p5.js sketch
I am playing with HTML5 canvas , my book says that
latest browser supports arcTo method and it has capabilities to remove
arc() function .
My question is how?
Also I am confused with this example of arcTo , why its getting formed in this way can someone explain
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<canvas id="canvas" width="500" height="500" ></canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext('2d');
var drawScreen = function(){
context.moveTo(0,0);
context.lineTo(100,200);
context.arcTo(350,350,100,100,20);
context.stroke();
}
drawScreen();
</script>
</body>
</html>
Here is some pseudocode explaining how the JavaScript code you posted works:
1) Get the canvas, and store it to variable 'canvas'
2) Get the 2d context of 'canvas', and store it to variable 'context'
3) Initialize a function, 'drawScreen', that takes no arguments, but runs the following instructions:
a) Move the pen to (0,0) on the canvas.
b) Draw a line from the pen's current position to (100, 100)
c) Draw an arc with a tangent line that passes through (350, 350) and the current pen position, and another tangent line that passes through (350, 350) and (100, 100), around a circle with radius 20.
d) Push the updated canvas to the screen.
4) Run the function 'drawScreen'
Believe it or not, you can use arcTo or a combination of other commands to do exactly the same thing arc does, albeit with more work, and there are numerous examples of this online.
I need to rotate an image in a canvas and simultaneously resize it to make sure that the corners of the canvas does not remain empty. The solution should be something similar to what do aviary in the "Crop, Resize & Rotate" example.
I think the solution is to combine the functions of rotation and resize of canvas, but I can not find any concrete solution to the problem and I didn't find any exaustive example on the web.
Any advice would be helpful
Thanks
I have not had a look at the example you have given but I gave a detailed answer on the problem of fitting a rotated image onto a canvas so that there is no blank spaces.
There is some math involved (go figure) but it is just basic trigonometry and I provided an explanation of how its all done. There are two solutions, one that finds the min scale that will fit the canvas for any rotation and the other the will find the min scale to fit the canvas for a particular rotation.
It is assumed that the image is centered, if not there is an easy way to adapt the code provided by supplying an abstract canvas size so that the rotated image is centered on that abstract canvas.
So if your center of image is at x = 100, y = 100 and the canvas is canvasWidth = 300, canvasHeight = 300 then just use an abstract size of absCanvasWidth = (canvasWidth - x) * 2; and then the image at x = absCanvasWidth/2 do the same for height. That will fit the rotated, translated image to fill the canvas.
The answer with the code can be found for the question After rotate, draw Image at correct position
Here's some code that might help you. This shows how to rotate an image 90 degrees clockwise, then scale it to fit in the original canvas space.
window.onload = function() {
var img = document.getElementById("myImage");
var rotatedCanvas = document.getElementById("myRotatedCanvas");
var width = rotatedCanvas.offsetWidth;
var height = rotatedCanvas.offsetHeight;
// draw the original image
var ctx = document.getElementById("myCanvas").getContext("2d");
ctx.drawImage(img, 0, 0);
// draw the rotated image
ctx = rotatedCanvas.getContext("2d");
ctx.rotate(90 * Math.PI / 180);
// the last two parameters scale the image
ctx.drawImage(img, 0, -width, height, width);
};
img {
display: none;
}
canvas {
border: 1px black solid;
}
<img src="http://imgur.com/UeMOrix.gif" id="myImage"/>
<canvas id="myCanvas" width="400" height="150"></canvas>
<br>
<canvas id="myRotatedCanvas" width="400" height="150"></canvas>
Using getImageData, I'm trying to create a radial fade effect on an image where point(0,0) has an alpha of 0 and point(img.width, img.height) has an alpha of 0.5 sort of like this:
(The last point has an alpha of 1.0, but imagine it's 0.5.)
I've been able to create a linear alpha increase in my for loop using
imgData.data[i+3]=i/imgData.length;
but the left edge (obviously) becomes more defined as the loop iterates.
I've tried using two loops, one to create row "breaks" in the array, and the other to handle the alpha manipulation like so:
for(var j=0;j<imgData.height;j++){
for(var i=0;i<imgData.data.length;i+=4){
imgData.data[i+3] = 0 + 125 * i/imgData.data.length;
}
}
but the performance of this is really slow and it doesn't achieve the fade that I'm looking for. I'm also not sure I'm doing that properly. I also tried Faster Canvas Pixel Manipulation with Typed Arrays as outlined on the Mozilla Hacks site, but the image wasn't even drawn to the canvas using that method. (I'm using Chrome - not sure if that's the issue or if it's my code.)
Any ideas?
EDIT: Thanks to markE for the great solution - it's beautifully quick. I mentioned this in my comment to him, but here's the full code for creating a greyscale image (part of my requirements) that has the fade pictured in mark's demo.
img_width = window.innerWidth/2.5;
img_height = img_width * (9/16);
//hidden_ctx is hidden behind a background layer
var g1=hidden_ctx.createRadialGradient(500,500,550,500,500,650);
g1.addColorStop(0.00,"rgba(0,0,0,0.7)");
g1.addColorStop(0.30,"rgba(0,0,0,0.35)");
g1.addColorStop(1.00,"rgba(0,0,0,0.00)");
hidden_ctx.fillStyle=g1;
hidden_ctx.fillRect(0, 0, img_width, img_height);
hidden_ctx.globalCompositeOperation="source-in";
//custom drawImage method where selected[num] contains
//contains images & metadata
drawIt(hidden_ctx, selected[num].image[0], 0, 0, img_width, img_height);
imgData=hidden_ctx.getImageData(0, 0, img_width, img_height);
// invert colors
for (var i=0;i<imgData.data.length;i+=4)
{
grayscaled = 0.34 * imgData.data[i] + 0.5 * imgData.data[i + 1] + 0.16 * imgData.data[i + 2];
imgData.data[i]=grayscaled;
imgData.data[i+1]=grayscaled;
imgData.data[i+2]=grayscaled;
}
//places the converted image in the lower right corner where
//WIDTH/HEIGHT is window.innerWidth/window.innerHeight
ctx.putImageData(imgData, WIDTH-img_width, HEIGHT-img_height);
You can use compositing to achieve a fade effect more efficiently.
draw a radial gradient that fades to transparent in the top-left corner.
Adjust the radial gradient to meet your design needs.
set compositing to source-in which causes any subsequent draws to only appear over existing non-transparent pixels.
draw your image (the image will fade the same way your radial gradient did)
Using compositing is especially efficient if the device has a GPU because compositing will use it.
Example code and a Demo: http://jsfiddle.net/m1erickson/thqamsLk/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
canvas{ background-color: lightgray; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/reef.jpg";
function start(){
canvas.width=img.width;
canvas.height=img.height;
var g1=ctx.createRadialGradient(500,500,550,500,500,650);
g1.addColorStop(0.00,"rgba(0,0,0,1.00)");
g1.addColorStop(0.30,"rgba(0,0,0,0.75)");
g1.addColorStop(1.00,"rgba(0,0,0,0.00)");
ctx.fillStyle=g1;
ctx.fillRect(0,0,cw,ch);
ctx.globalCompositeOperation="source-in";
ctx.drawImage(img,0,0);
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Fading an image using compositing</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
I'm dynamically drawing a polygon inside a canvas using this code I found. (the coordinates are provided by the user)
https://stackoverflow.com/a/4841057/1667856
Is it possible to move this polygon into the center of a canvas after/before it has been created?
I found out that you can use the canvas translate() method to move shapes around but I can't seem to figure out how to recalculate the coordinates so that the polygon will automatically appear in the middle of the canvas and not on its original coordinates.
As you've probably discovered, html canvas is just a pixel drawing.
The shapes you draw on the canvas are just like dried paint. They can't be moved or remolded into another shape.
The typical way of "moving" a shape is to clear the canvas and redraw the same shape with different coordinates.
You can create those coordinates by adding an offsetX and offsetY to all the polygon coordinates.
Alternatively (more simply) you can translate the coordinates.
Important note: context.translate does not just move the coordinates of your polygon. It changes every coordinate for all NEW drawings.
ctx.translate(50,50) "moves" the canvas's origin to 50,50. That means if you start drawing your polygon at 5,5 you will visually start drawing at 50+5,50+5.
Here is example code and a Demo: http://jsfiddle.net/m1erickson/2Gm73/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// calculate the middle of the canvas
var centerX=canvas.width/2;
var centerY=canvas.height/2;
// just for testing: draw crosshairs on center canvas
ctx.beginPath();
ctx.moveTo(centerX,0);
ctx.lineTo(centerX,canvas.height);
ctx.moveTo(0,centerY);
ctx.lineTo(canvas.width,centerY);
ctx.stroke();
// define some points for your polygon
var poly=[ 5,5, 100,50, 50,100, 10,90 ];
// save the canvas context in its untranslated state
ctx.save();
// translate the canvas
// the context now uses centerX,centerY as its 0,0 origin
ctx.translate(centerX,centerY);
// draw the polygon
ctx.beginPath();
ctx.moveTo(poly[0], poly[1]);
for(var i=2;i<poly.length;i+=2){
ctx.lineTo( poly[i] , poly[i+1] )
}
ctx.closePath();
ctx.fillStyle = '#f00';
ctx.fill();
// restore the context to its untranslated state
// (otherwise all further drawings will be "moved"
// just like this polygon
ctx.restore();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
If you want your polygon to be visually centered in the canvas, you must also calculate the offset of the center of your polygon itself:
// calc the max values of x,y in the polygon and divide by 2
var centerPolyX = 100/2; // max x comes from coordinate 100,50
var centerPolyY = 100/2; // max y comes from coordinate 50,100
Then translate to center canvas minus the polygon center:
// move to center canvas
// but then move left and up by half the polygon's size
ctx.translate(centerX-centerPolyX,centerY-centerPolyY);