Canvas rotate image which depicts an angled ellipse - javascript

I have an image in my canvas and am trying to rotate it in an unusual way. I have my image rotating but on the wrong origin point.
I want to rotate the image in such a way that the ellipse is shown to be rotating from it's origin point rather than the image itself rotating. There for ultimately the ellipse would be stationary in the canvas and simply rotating.
This is my current code:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
var angle;
var toRads = Math.PI/180;
var start = new Date().getTime();
var rotation = 15;
function draw(){
var x = canvas.width/2 - img.width/2;
var y = canvas.height/2 - img.height/2;
var deltaTime = new Date().getTime() - start;
start = new Date().getTime();
angle = (angle || 0) + (deltaTime/1000 * rotation);
if(angle > 360){angle = 0;}
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(x,y);
ctx.rotate(angle * toRads);
ctx.drawImage(img,20,20);
ctx.restore();
setTimeout(draw,1);
}
I was wondering if this can be done in 2D or is it only possible via 3D such as webGL stuff?
I created a jsfiddle of what I have got so far:
http://jsfiddle.net/hc0p5e06/

The order of the transformations are important. You are missing a translation to place the origin of the circle at the right point (assuming you want the center)
var w = img.width; // get the image width and height
var h = img.height;
ctx.translate(x,y);
ctx.rotate(angle * toRads);
ctx.drawImage(img,0,0,w,h,-w/2,-h/2,w,h); // draw the image translated half
// its size up and left in the new
// coordinate space

Related

html5 canvas draw lines in a circle

I am having some trouble drawing lines in circle with html5 canvas.
I am trying to make the bars look something like this
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var bars = 50;
var radius = 100;
for(var i = 0; i < bars; i++){
var x = radius*Math.cos(i);
var y = radius*Math.sin(i);
draw_rectangle(x+200,y+200,1,13,i, ctx );
}
function draw_rectangle(x,y,w,h,deg, ctx){
ctx.save();
ctx.translate(x, y);
ctx.rotate(degrees_to_radians(deg));
ctx.fillStyle = "yellow";
ctx.fillRect(-1*(w/2), -1*(h/2), w, h);
ctx.restore();
}
function degrees_to_radians(degrees){
return degrees * Math.PI / 180;
}
function radians_to_degrees(radians){
return radians * 180 / Math.PI;
};
for some reason my lines are all crooked and unaligned. I really need help on this one. https://codepen.io/anon/pen/PRBdYV
The easiest way to deal with such a visualization is to play with the transformation matrix of your context.
You need to understand it as if you were holding a sheet of paper in your hands.
Instead of trying to draw the lines at the correct angle, rotate the sheet of paper, and always draw your lines in the same direction.
This way all you need in your drawing method is the angle, and the height of each bar.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
// the position of the whole thing
var circleX = canvas.width / 2;
var circleY = canvas.height / 2;
//
var bars = 50;
var barWidth = 5;
// inner radius
var radius = 50;
ctx.fillStyle = "yellow";
// no need to use degrees, a full circle is just 2π
for(var i = 0; i < Math.PI*2; i+= (Math.PI*2 / bars)){
draw_rectangle(i, (Math.random()*30) + 10);
}
function draw_rectangle(rad, barHeight){
// reset and move to the center of our circle
ctx.setTransform(1,0,0,1, circleX, circleY);
// rotate the context so we face the correct angle
ctx.rotate(rad);
// move along y axis to reach the inner radius
ctx.translate(0, radius);
// draw the bar
ctx.fillRect(
-barWidth/2, // centered on x
0, // from the inner radius
barWidth,
barHeight // until its own height
);
}
canvas#canvas{
background:black;
}
<html>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
</body>
</html>
https://codepen.io/anon/pen/YajONR
Problems fixed: Math.cos wants radians, not degrees
We need to go from 0 to 360, so I adjusted the number of bars to make that a bit easier, and multiplied i by 6 (so the max value is 60*6==360)
If we don't add +90 when drawing the bars, we just get a circle
Check your codepen and figured out the problem lies in the degrees_to_radians
Here is the update link of you code.Link
PS I only looked at the shape of the circle not alignments of the bar :D

Image rotation using canvas

I need to rotate an image through canvas and through the cropper.js library I can do the rotation of the image but save the image and condition it with canvas does not save me with the format of the rotation.
In my code what I have is an event that makes me rotating towards 90 or -90 degrees. Then when saving the image I need to be saved with that format.
I need to rotate on the axis of the image so that when the image is saved with rotate canvas it is saved with the correct position. I have seen some ways to do it but it has not worked for me, I do not know that I am losing.
//Events to rotate using cropper Js library
'click #rotateL': function(e, instance){
$('#target').cropper('rotate', -90);
angleInDegrees = angleInDegrees - 90 ;
drawRotated(angleInDegrees);
},
'click #rotateR': function(events, instance){
$('#target').cropper('rotate', 90);
angleInDegrees += 90;
drawRotated(angleInDegrees);
},
function drawRotated(degrees){
var canvas = $("#canvas")[0];
var context = canvas.getContext('2d');
var image = document.createElement("img");
image.src = $('#target').attr("src");
image.onload = function () {
context.drawImage(image,(canvas.width - x1) / 2,
(canvas.height - y1) / 2,x1, y1);
//ctx.drawImage(img, x, y, width, height)
}
context.clearRect(0,0,canvas.width,canvas.height);
context.save();
context.translate(canvas.width/2,canvas.height/2);
context.rotate(degrees*Math.PI/180);
context.drawImage(image, -x1/2,-y1/2);
context.restore();
var dataURL = canvas.toDataURL("image/jpeg");
Session.set("url", dataURL);
}
// event that saves the changes made when you cut the image or rotate.
'click #Save' : function(e) {
$(".loader").fadeIn("slow");
e.preventDefault();
var photoid = $('#photoid').val();
var dataURL = Session.get("url");
var photo = {
srcData : dataURL,
userid : Meteor.userId(),
photo_id : photoid
}
Meteor.call('updatePhoto',photo,function(err) {
if (!err) {
$('#photos').show();
$('#crops').hide();
canvas.height = 0;
canvas.width = 0;
//page relod is better than
//document.getElementById('target').src="";
FlowRouter.go('/search');
FlowRouter.go('/addphoto');
}
});
},
If you are using cropper.js. You can use build-in method getCroppedCanvas to get edited and cropped new canvas back. There is no bother to write on your own.
var canvas = $ ('# target').cropper ('getCroppedCanvas');
console.log (canvas)
var dataURL = canvas.toDataURL ("image / jpeg");
To rotate 90 deg clockwise on a new canvas.
// assuming that image is a loaded image.
const canvas = document.createElement("canvas");
canvas.width = image.height;
canvas.height = image.width;
const ctx = canvas.getContext("2d");
ctx.setTransform(
0,1, // x axis down the screen
-1,0, // y axis across the screen from right to left
image.height, // x origin is on the right side of the canvas
0 // y origin is at the top
);
ctx.drawImage(image,0,0);
To rotate -90Deg onto a new canvas
const canvas = document.createElement("canvas");
canvas.width = image.height;
canvas.height = image.width;
const ctx = canvas.getContext("2d");
ctx.setTransform(
0,-1, // x axis up the screen
1,0, // y axis across the screen from left to right
0, // x origin is on the left side of the canvas
image.width // y origin is at the bottom
);
ctx.drawImage(image,0,0);
The origins are where the top left corner of the image ends up being after the rotation.

How to rotate image in Canvas

I have built a canvas project with https://github.com/petalvlad/angular-canvas-ext
<canvas width="640" height="480" ng-show="activeateCanvas" ap-canvas src="src" image="image" zoomable="true" frame="frame" scale="scale" offset="offset"></canvas>
I am successfully able to zoom and pan the image using following code
scope.zoomIn = function() {
scope.scale *= 1.2;
}
scope.zoomOut = function() {
scope.scale /= 1.2;
}
Additionally I want to rotate the image. any help i can get with which library i can use and how can i do it inside angularjs.
You can rotate an image using context.rotate function in JavaScript.
Here is an example of how to do this:
var canvas = null;
var ctx = null;
var angleInDegrees = 0;
var image;
var timerid;
function imageLoaded() {
image = document.createElement("img");
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
image.onload = function() {
ctx.drawImage(image, canvas.width / 2 - image.width / 2, canvas.height / 2 - image.height / 2);
};
image.src = "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcT7vR66BWT_HdVJpwxGJoGBJl5HYfiSKDrsYrzw7kqf2yP6sNyJtHdaAQ";
}
function drawRotated(degrees) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(degrees * Math.PI / 180);
ctx.drawImage(image, -image.width / 2, -image.height / 2);
ctx.restore();
}
<button onclick="imageLoaded();">Load Image</button>
<div>
<canvas id="canvas" width=360 height=360></canvas><br>
<button onclick="javascript:clearInterval(timerid);
timerid = setInterval(function() {
angleInDegrees += 2;
drawRotated(angleInDegrees);
}, 100);">
Rotate Left
</button>
<button onclick="javascript:clearInterval(timerid);
timerid = setInterval(function() {
angleInDegrees -= 2;
drawRotated(angleInDegrees);
}, 100);">
Rotate Right
</button>
</div>
With curtesy to this page!
Once you can get your hands on the canvas context:
// save the context's co-ordinate system before
// we screw with it
context.save();
// move the origin to 50, 35 (for example)
context.translate(50, 35);
// now move across and down half the
// width and height of the image (which is 128 x 128)
context.translate(64, 64);
// rotate around this point
context.rotate(0.5);
// then draw the image back and up
context.drawImage(logoImage, -64, -64);
// and restore the co-ordinate system to its default
// top left origin with no rotation
context.restore();
To do it in a single state change. The ctx transformation matrix has 6 parts. ctx.setTransform(a,b,c,d,e,f); (a,b) represent the x,y direction and scale the top of the image will be drawn along. (c,d) represent the x,y direction and scale the side of the image will be drawn along. (e,f) represent the x,y location the image will be draw.
The default matrix (identity matrix) is ctx.setTransform(1,0,0,1,0,0) draw the top in the direction (1,0) draw the side in the direction (0,1) and draw everything at x = 0, y = 0.
Reducing state changes improves the rendering speed. When its just a few images that are draw then it does not matter that much, but if you want to draw 1000+ images at 60 frames a second for a game you need to minimise state changes. You should also avoid using save and restore if you can.
The function draws an image rotated and scaled around its center point that will be at x,y. Scale less than 1 makes the images smaller, greater than one makes it bigger. ang is in radians with 0 having no rotation, Math.PI is 180deg and Math.PI*0.5 Math.PI*1.5 are 90 and 270deg respectively.
function drawImage(ctx, img, x, y, scale, ang){
var vx = Math.cos(ang) * scale; // create the vector along the image top
var vy = Math.sin(ang) * scale; //
// this provides us with a,b,c,d parts of the transform
// a = vx, b = vy, c = -vy, and d = vx.
// The vector (c,d) is perpendicular (90deg) to (a,b)
// now work out e and f
var imH = -(img.Height / 2); // get half the image height and width
var imW = -(img.Width / 2);
x += imW * vx + imH * -vy; // add the rotated offset by mutliplying
y += imW * vy + imH * vx; // width by the top vector (vx,vy) and height by
// the side vector (-vy,vx)
// set the transform
ctx.setTransform(vx, vy, -vy, vx, x, y);
// draw the image.
ctx.drawImage(img, 0, 0);
// if needed to restore the ctx state to default but should only
// do this if you don't repeatably call this function.
ctx.setTransform(1, 0, 0, 1, 0, 0); // restores the ctx state back to default
}

Rotate Rectangular Canvas Image to Fit

I am attempting to rotate an image that fills a rectangular canvas element. Using the code below, I can rotate it satisfactorily (90 degree increments). However, when the big side is translated to the small side, I cannot figure out how to fill the entire canvas. Instead, I have a compacted image. Any help would be appreciated in solving this. Thanks!
What I have so far:
var degrees = 90;
function drawRotated(degrees){
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
var translateX = (canvas.width)/2;
var translateY = (canvas.height)/2;
ctx.translate(translateX,translateY);
ctx.rotate(degrees*Math.PI/180);
ctx.translate(-translateX,-translateY);
ctx.drawImage(theImage, 0,0, canvas.width, canvas.height);
}
to rotate the image without distorting it, it is important to use the image dimensions to translate the image to 0, 0. this will get the center of the image to the origin. you rotate the matrix around the origin (0, 0). you were rotating around the center of the canvas.
additionally you have to perform some math for one translation so that the image is always in the upper left corner.
function drawRotated(degrees){
var theImage = document.getElementById('image');
var imageWidth = theImage.naturalWidth;
var imageHeight = theImage.naturalHeight;
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var angle = degrees*Math.PI/180;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// this will align your image in the upper left corner when rotating in 90deg increments
ctx.translate(Math.abs(imageWidth/2 * Math.cos(angle) + imageHeight/2 * Math.sin(angle)), Math.abs(imageHeight/2 * Math.cos(angle) + imageWidth/2 * Math.sin(angle)));
ctx.rotate(angle);
ctx.translate(-imageWidth/2, -imageHeight/2);
ctx.drawImage(theImage, 0, 0);
}
see FIDDLE

canvas hole in html5 with image not working

I am trying to create a hole in canvas; and loading image in canvas after.
I want this canvas to contain a hole at a top layer.
I just read about counter-clockwise canvas rules and then created hole with counter clockwise position as below-
var c = document.getElementById("canvas-front");
var ctx = c.getContext("2d");
var centerX = c.width / 2;
var centerY = c.offsetTop;
var radius = 30;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI,true);//boolean true to counter-clockwise
ctx.fillStyle = 'black';
ctx.fill();
I have canvas before image in it-
After applying image in this canvas-
Canvas-
<canvas id="canvas-front" width="261" height="506"></canvas>
As you can see from both the images, I can't get this hole in canvas work.
How do I create this arc so that image doesn't overlap this.
I get this issue solved-
What I had to do-
On change of file I did empty to canvas and redrew image and then while image is being loaded
the arc is being created to counter-clockwise position-
Drawing the canvas again on image change-
var canvas = document.getElementById("canvas-front");
canvas.width = canvas.width;//blanks the canvas
var c = canvas.getContext("2d");
Creating image and giving it required src from changed input-
var img = new Image();
img.src = e.target.result;
Loading image and creating arc parallely-
img.onload = function () {
c.drawImage(img, 0, 0);
var centerX = canvas.width / 2;
var centerY = canvas.offsetTop;
var radius = 30;
c.beginPath();
c.arc(centerX, centerY, radius, 0, 2 * Math.PI, true);
c.fillStyle = 'black';
c.fill();
}

Categories

Resources