I'm iplementing zoom out effect of an image. But after it's scaled and zoom out, the image isn't on center of canvas.
This is my code:
var canvas = document.getElementById('canvas');
var image = document.getElementById('image');
var ctx = canvas.getContext("2d");
var zoomDelta = 0.025; // 10 steps in 10s, scale from 5 to 1
var currentScale = 5;
var img = new Image();
img.src = image.src;
img.onload = function() {
ctx.canvas.width = img.width;
ctx.canvas.height = img.height;
}
$("#start").on("click", function () {
ctx.translate(canvas.width / 2, canvas.height / 2);
drawImage();
var zoom1 = window.setInterval(
function() {
if(currentScale < 1)
window.clearInterval(zoom1);
else
reDraw();
}, 50
);
});
function reDraw() {
currentScale -= zoomDelta;
drawImage();
}
function drawImage() {
clear();
ctx.save();
ctx.scale(currentScale, currentScale);
ctx.drawImage(img, -img.width / 2, -img.width / 2);
ctx.restore();
}
function clear() {
ctx.clearRect(-img.width / 2 - 2, -img.width / 2 - 2, img.width + 4, img.height + 4);
}
Thanks in advance.
Btw, this is its fiddle: http://jsfiddle.net/huynq/RK2D7/
Translate to the point on which you want to center the image.
A Demo: http://jsfiddle.net/m1erickson/QEuw4/
var cx=canvas.width/2;
var cy=canvas.height/2;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(cx,cy);
ctx.scale(scale,scale);
ctx.drawImage(img,-img.width/2,-img.height/2);
ctx.restore();
Related
I tried to load the image by url on the canvas. And I change the canvas size to image size. andf I tried to rotate the image but if I executed it, some part of the image is cropped. Please find the errors in my code.
if (submitBtn) {
submitBtn.addEventListener('click', handleSubmitBtnClick);
}
function handleSubmitBtnClick() {
let imgURLValue = inputImageURL.value;
backgroundImage.src = `${imgURLValue}`;
backgroundImage.crossOrigin = 'Anonymous';
backgroundImage.onload = function () {
canvas.width = backgroundImage.width;
canvas.height = backgroundImage.height;
ctx.drawImage(
backgroundImage,
0,
0,
backgroundImage.width,
backgroundImage.height
);
};
}
if (rotateBtn) {
rotateBtn.addEventListener('click', handleRotateBtn);
}
function handleRotateBtn() {
degree += 90;
if (degree >= 360) {
degree = 0;
}
if (degree === 0 || degree === 180) {
canvas.width = backgroundImage.width;
canvas.height = backgroundImage.height;
} else {
canvas.width = backgroundImage.height;
canvas.height = backgroundImage.width;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(backgroundImage.width / 2, backgroundImage.height / 2);
ctx.rotate((degree * Math.PI) / 180);
ctx.drawImage(
backgroundImage,
0,
0,
backgroundImage.width,
backgroundImage.height,
-backgroundImage.width / 2,
-backgroundImage.height / 2,
backgroundImage.width,
backgroundImage.height
);
ctx.restore();
}
[enter image description here][1]
If I rotate the image, the image is loaded like this..
[1]: https://i.stack.imgur.com/drNaG.png
The origin of your rotation should be the center of the canvas, so that it uses the updated width and height values.
By using the original center of the image your drawing will be offset.
const rotateBtn = document.querySelector("button");
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
const backgroundImage = new Image();
backgroundImage.src = "https://picsum.photos/150/300";
backgroundImage.decode().then(() => {
rotateBtn.disabled = false;
handleRotateBtn();
});
let degree = -90;
if (rotateBtn) {
rotateBtn.addEventListener('click', handleRotateBtn);
}
function handleRotateBtn() {
degree += 90;
if (degree >= 360) {
degree = 0;
}
if (degree === 0 || degree === 180) {
canvas.width = backgroundImage.width;
canvas.height = backgroundImage.height;
} else {
canvas.width = backgroundImage.height;
canvas.height = backgroundImage.width;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
// use the updated center as origin
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate((degree * Math.PI) / 180);
// I simplified this call but it does the same as yours
ctx.drawImage(
backgroundImage,
-backgroundImage.width / 2,
-backgroundImage.height / 2
);
ctx.restore();
}
canvas { background: ivory }
<button disabled>rotate</button><br>
<canvas></canvas>
I am trying to crop an image with Javascript. I have croppr.js and it is sending the data and I was trying to crop the image so I can save it to a storage server with Base 64. I have read online about .drawimage(). I have tried:
function process(data) {
console.log("DATA:" + data)
var canvas = document.getElementById("canvas")
var context = canvas.getContext('2d');
var imageObj = new Image();
var zoom
imageObj.onload = function() {
context.width = data.width
context.height = data.height
// draw cropped image
var sourceX = data.x;
var sourceY = data.y;
var sourceWidth = data.width / 2;
var sourceHeight = data.height / 2;
var destWidth = sourceWidth;
var destHeight = sourceHeight;
var destX = 0;
var destY = 0;
context.drawImage(imageObj, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
var dataurl = canvas.toDataURL('image/jpeg', 1.0)
console.log(dataurl)
};
imageObj.src = document.getElementsByTagName("img")[0].src;
console.log(imageObj.src)
}
data Contains X Y Height Width As an JSON array.
First I see is the:
context.width = data.width
context.height = data.height
Did you meant to do canvas instead?
Here is an example:
function process(data) {
var canvas = document.getElementById("canvas")
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
canvas.width = data.width
canvas.height = data.height
// draw cropped image
var w = data.width / 2;
var h = data.height / 2;
context.drawImage(img, data.x, data.y, w, h, 0, 0, w, h);
};
img.src = data.src;
}
process({x:0, y:0, width:600, height: 600, src: "http://i.stack.imgur.com/UFBxY.png"})
<canvas id="canvas"></canvas>
That is the only issue I could see on your code.
What is not clear is the data you use to call the process function
I have problem with drawing this (1766 * 2880) PNG file on canvas.
But I don't have any problem with JPG format of that size or (1533 * 2500) size of PNG file.
I consider devicePixelRatio for scaling canvas, and ignoring the ratio makes no changes.
var loadImage = function (url) {
var ratio = Math.max(window.devicePixelRatio || 1, 1),
image = new Image();
image.onload = function () {
var paper = '#paper-0',
canvas = $(paper)[0],
ctx = canvas.getContext("2d"),
img = this;
var w = Math.ceil(img.width / ratio), h = Math.ceil(img.height / ratio);
$(paper).css({ width: w + 'px', height: h + 'px' });
canvas.width = w * ratio;
canvas.height = h * ratio;
ctx.scale(ratio, ratio);
ctx.drawImage(img, 0, 0, w, h);
}
image.src = url;
}
I'm taking image input from user, then resizing and showing it on a canvas. Here is the code-
HTML-
<form class="cmxform">
<input type='file' id="Photo" />
<canvas id="canvas" width="300" height="200"></canvas>
</form>
JavaScript-
$("#Photo").change(function (e) {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.src = URL.createObjectURL(e.target.files[0]);
img.onload = function () {
ctx.drawImage(img, 0, 0, img.width, img.height, // source rectangle
0, 0, canvas.width, canvas.height); // destination rectangle
}
});
But here I'm loosing the aspect ratio. Is there any way to do it?
UPDATE-
I've got the answer from this sa question -
Here is a snippet to help you for that
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
var fill = true;
if (fill)
{
$('#fill').attr("disabled", true);
}
$("#Photo").change(function (e) {
img.src = URL.createObjectURL(e.target.files[0]);
img.onload = function () {
if (fill)
{
drowImageFill(img);
}
else
{
drowImageCenter(img);
}
}
});
$("#fill").click(function(){
//console.log("fill");
var input = document.getElementById('Photo');
if (input.files[0] !== undefined)
{
img.src = URL.createObjectURL(input.files[0]);
img.onload = function () {
drowImageFill(img);
}
}
$('#fill').attr("disabled", true);
$('#center').attr("disabled", false);
fill = true;
});
$("#center").click(function(){
//console.log("center");
var input = document.getElementById('Photo');
if (input.files[0] !== undefined)
{
img.src = URL.createObjectURL(input.files[0]);
img.onload = function () {
drowImageCenter(img);
}
}
$('#center').attr("disabled", true);
$('#fill').attr("disabled", false);
fill = false;
});
//ratio formula
//http://andrew.hedges.name/experiments/aspect_ratio/
function drowImageFill(img){
ctx.clearRect(0, 0, canvas.width, canvas.height);
//detect closet value to canvas edges
if( img.height / img.width * canvas.width > canvas.height)
{
// fill based on less image section loss if width matched
var width = canvas.width;
var height = img.height / img.width * width;
offset = (height - canvas.height) / 2;
ctx.drawImage(img, 0, -offset, width, height);
}
else
{
// fill based on less image section loss if height matched
var height = canvas.height;
var width = img.width / img.height * height;
offset = (width - canvas.width) / 2;
ctx.drawImage(img, -offset , 0, width, height);
}
}
function drowImageCenter(img)
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
if( img.height / img.width * canvas.width < canvas.height)
{
// center based on width
var width = canvas.width;
var height = img.height / img.width * width;
offset = (canvas.height - height) / 2;
ctx.drawImage(img, 0, offset, width, height);
}
else
{
// center based on height
var height = canvas.height;
var width = img.width / img.height * height;
offset = (canvas.width - width) / 2;
ctx.drawImage(img, offset , 0, width, height);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="300" height="200" style="border:2px solid #000000;"></canvas>
<form class="cmxform">
<input type='file' id="Photo" />
</form>
<button id="fill">Fill</button>
<button id="center">Center</button>
I'm developing a game using HTML5 canvas element and native javascript. I have different sprites for game objects. Is it possible to rotate sprites using native javascript?
For example, I have a sprite image like this:
I use Image for this sprite:
var image = new Image(...);
image.src = "...";
After loading I want to rotate this image and save different projections in local variables:
var sprite_left = rotate(image, 0),
sprite_top = rotate(image, 90),
sprite_right = rotate(image, 180),
sprite_right = rotate(image, 270);
The rotate function should look like this:
function rotate(sourceImage, angle){
...
}
Could anybody help me to write the rotate function?
EDIT:
I have decided to share my code, which I used to test my sprites:
var wait = function (image, completed, count) {
if (count == null) count = 0;
if (!image.complete && count < 1000) {
count++;
window.setTimeout(function () {
wait(image, completed, count);
console.log('waiting...');
}, 10);
}
else {
completed();
}
},
rotateW = function (image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var p = document.createElement("p");
p.innerText = "W: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(Math.PI);
context.translate(-canvas.width / 2, -canvas.height / 2);
context.drawImage(image, 0, 0);
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
},
rotateE = function (image) {
var canvas = document.createElement("canvas");
canvas.width = image.width;
canvas.height = image.height;
var p = document.createElement("p");
p.innerText = "E: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.drawImage(image, 0, 0);
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
},
rotateS = function (image, frameCount) {
var canvas = document.createElement("canvas");
canvas.width = image.height * frameCount;
canvas.height = image.width / frameCount;
var p = document.createElement("p");
p.innerText = "S: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.translate(image.height / 2, image.width / (2 * frameCount));
context.rotate(Math.PI / 2);
var i = frameCount;
while (i--> 0) {
context.drawImage(image, - image.width / 2 , - ( 0.5 + i ) * image.height);
}
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
},
rotateN = function (image, frameCount) {
var canvas = document.createElement("canvas");
canvas.width = image.height * frameCount;
canvas.height = image.width / frameCount;
var p = document.createElement("p");
p.innerText = "N: ";
p.appendChild(canvas);
document.body.appendChild(p);
var context = canvas.getContext("2d");
context.translate(image.height / 2, image.width / (2 * frameCount));
context.rotate( 3 * Math.PI / 2);
var i = frameCount;
while (i-- > 0) {
context.drawImage(image, -image.width / 2, (frameCount - i - 1.5) * image.height);
}
var newImage = new Image();
newImage.src = canvas.toDataURL("image/png");
return newImage;
};
/*
N
|
W----O----E
|
S
*/
getSprites = function (image, frameCount) {
var sprite = {
N: rotateN(image, frameCount),
S: rotateS(image, frameCount),
W: rotateW(image, frameCount),
E: rotateE(image, frameCount)
};
return [
sprite.W, // left
sprite.N, // up
sprite.E, // right
sprite.S] // down
};
$.sprite = {
register: function (options) {
var image = new Image();
image.src = options.src;
wait(image, function () {
var sprites = getSprites(image, options.frameCount);
});
}
};
The final result is:
the following function will create a new Canvas out
of img (which might be an image or a canvas).
Give it an angle in radian, or 'N', 'S', 'W' for
the corresponding rotation.
function createRotatedImage(img, angle) {
angle = (angle == 'N') ? -Math.PI/2 :
(angle == 'S') ? Math.PI/2 :
(angle == 'W') ? Math.PI :
angle ;
var newCanvas = document.createElement('canvas');
newCanvas.width = img.width ;
newCanvas.height = img.height ;
var newCtx = newCanvas.getContext('2d') ;
newCtx.save () ;
newCtx.translate ( img.width / 2, img.height / 2) ;
newCtx.rotate (angle);
newCtx.drawImage ( img, - img.width / 2, - img.height / 2) ;
newCtx.restore () ;
}
Use a <canvas> to pre-render the different rotations
Store these in memory using via toBlob, optionally converting these blobs to URLs with window.URL.createObjectURL
Swap URLs as desired.
See this MDN page for canvas options
Absolutely! It's not as simple as rotating the image, though. You need to rotate the context from the canvas, and draw that image on the rotated context, and then restore it.
context.save();
context.rotate(angle);
//DRAW IT!
context.restore();
How about having a function like :
Image.prototype.rotate = function(angle) {
var c = document.createElement("canvas");
c.width = this.width;
c.height = this.height;
var ctx = c.getContext("2d");
ctx.rotate(angle);
var imgData = ctx.createImageData(this.width, this.height);
ctx.putImageData(imgData);
return new Image(imgData);
}
var img1 = new Image();
var img2 = img1.rotate(90);
Ofcourse it's just a quick sample to give you an idea.