HTML Canvas - Drag and resize uploaded image - javascript

I am doing a drawing app for a college project and currently im able to upload images into the canvas and i want to make those images resizable/draggable.
I've seen this great example and tried to apply it in my project for hours but with no success.
Is it possible to apply it to an uploaded image instead of preloaded image like in that example?
My javascript code to upload image and a fiddle. Thanks in advance.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function el(id){return document.getElementById(id);}
function readImage() {
if ( this.files && this.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, true, true);
};
img.src = e.target.result;
};
FR.readAsDataURL( this.files[0] );
}
}
el("fileUpload").addEventListener("change", readImage, false);

As you have provided a nice example, I just included those methods and variables in your code and added jquery then declared the var img = new Image(); variable outside of the readImage function.
That's it I did and it worked as you expected.
Here you go,
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 8;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 50;
var imageY = 50;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
function el(id){return document.getElementById(id);}
var img = new Image();
function readImage() {
if ( this.files && this.files[0] ) {
var FR= new FileReader();
FR.onload = function(e) {
img = new Image();
img.onload = function() {
imageWidth = img.width;
imageHeight = img.height;
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight
draw(true, false);
};
img.src = e.target.result;
};
FR.readAsDataURL( this.files[0] );
}
}
el("fileUpload").addEventListener("change", readImage, false);
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
#canvas {
border:1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type='file' id="fileUpload" />
<canvas id="canvas" width="500" height="500"></canvas>

Related

HTML5 Canvas - Rotate by anchor using a mouse

I am developing in html5's canvas element. I have the follwing code and it is draggable and resizable image. How can I turn it to rotatable by a anchor too? How can I provide live rotating by an anchor. I saw other codes samples, but do not know how to implement it.
Sampler Working:
http://jsfiddle.net/LAS8L/588/
<canvas id="canvas" width=350 height=350></canvas>
Javascript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 8;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 50;
var imageY = 50;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
var cx = canvas.width / 2;
var cy = canvas.height / 2;
var w;
var h;
var r = 0;
var img = new Image();
img.onload = function () {
imageWidth = img.width;
imageHeight = img.height;
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight
draw(true, false);
}
img.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/facesSmall.png";
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function desenhe() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawRotationHandle(true);
drawRect();
}
function drawRect() {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.drawImage(img, 0, 0, img.width, img.height, -imageWidth, -imageheight, w, h);
// ctx.fillStyle="yellow";
// ctx.fillRect(-w/2,-h/2,w,h);
ctx.restore();
}
function drawRotationHandle(withFill) {
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(r);
ctx.beginPath();
ctx.moveTo(0, -1);
ctx.lineTo(imageWidth + 20, -1);
ctx.lineTo(imageWidth + 20, -7);
ctx.lineTo(imageWidth + 30, -7);
ctx.lineTo(imageWidth + 30, 7);
ctx.lineTo(imageWidth + 20, 7);
ctx.lineTo(imageWidth + 20, 1);
ctx.lineTo(0, 1);
ctx.closePath();
if (withFill) {
ctx.fillStyle = "blue";
ctx.fill();
}
ctx.restore();
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
I would like to work this way: http://jsfiddle.net/m1erickson/QqwKR/ but I don't know how merge the code. Can somebody help me?
Here is a function the will set the transform to scale rotate and translate an rectangle or anything.
function setTransform(ctx,x,y,scale,rotate){
var xdx = Math.cos(rotate) * scale; // create the x axis
var xdy = Math.sin(rotate) * scale;
ctx.setTransform(xdx, xdy, - xdy, xdx, x, y);
}
The canvas transform is set after that. Now just draw the object in its local space coords.
Eg draw at center of canvas double scale and 45deg rotation
setTransform(ctx,canvas.width/2,canvas.height/2,2,Math.PI /4);
ctx.strokeRect(-100,-100,200,200);
You will notice that the coordinates are negative. This is because I want the center of the box to be at the center of the canvas. If I wanted the top left of the box to be at the center
ctx.strokeRect(0,0,200,200);
or the bottom right
ctx.strokeRect(-200,-200,200,200);
Back to the centered box I can move it anywhere
setTransform(
ctx,
Math.random() * canvas.width, // random x pos
Math.random() * canvas.height, // random y pos
Math.random() * 10 + 0.1, // random scale
Math.random() * Math.PI * 2 // random rotation
);
The transform is random but I do not need to care I can still draw the box in local coordinates.
ctx.strokeRect(-100,-100,200,200);
And it will be draw where ever the transform has set it to.
Using ctx.setTransform saves the hassle of using save and restore.
If at any stage you need to return to the default transform
ctx.setTransform(1,0,0,1,0,0);
The problem you will next face is that the mouse coordinates are in canvas coordinates while the object is in its local space. You need to convert the mouse coordinates into the local object coordinates.
This is done by multiplying the mouse coordinates by the inverse of the matrix. A bit of maths here.
function getMouseLocal(mousex,mouseY,x,y,scale,rot){
var xdx = Math.cos(rotate) * scale; // create the x axis
var xdy = Math.sin(rotate) * scale;
// get the cross product of the two axies
var cross = xdx * xdx - xdy * -xdy;
// or
var cross = Math.pow(xdx,2) + Math.pow(xdy,2);
// then create the inverted axies
var ixdx = xdx / cross; // create inverted x axis
var ixdy = -xdy / cross;
var iydx = xdy / cross; // create inverted y axis
var iydy = xdx / cross;
// now remove the origin from the mouse coords
mouseX -= x;
mouseY -= y;
// multiply by the invers matrix
var localMouseX = mouseX * ixdx + mouseY * iydx;
var localMouseY = mouseX * ixdy + mouseY * iydy;
// and return the result
return {x : localMouseX, y : localMouseY};
}
Now you have the mouse coordinates in the local space. If you need to find out if the mouse is inside the box you
setTransform(ctx,100,100,2,Math.PI/4);
ctx.strokeRect(-100,-100,200,200);
var localMouse= getMouseLocal(mouseX,mouseY,100,100,2,Math.PI/4);
if(localMouse.x > -100 && localMouse.x < -100 + 200 && localMouse.y > -100 && localMouse.y < -100 + 200){
// mouse is inside the box
}
That should give you what you need.
UPDATE
I forgot you want to scale both x and y.. So below are the modified functions for scaling both X and Y axies
// sx and sy are scale x and y
function setTransform(ctx,x,y,sx,sy,rotate){
var xdx = Math.cos(rotate); // create the x axis
var xdy = Math.sin(rotate);
ctx.setTransform(xdx * sx, xdy * sx, - xdy * sy, xdx * sy, x, y);
}
And getting the mouse to local
function getMouseLocal(mousex,mouseY,x,y,sx,sy,rot){
var xdx = Math.cos(rotate); // create the x axis
var xdy = Math.sin(rotate);
// get the cross product of the two axies
var cross = xdx * sx * xdx * sy - xdy *sx * -xdy * sy;
// or
// this shortcut does not work now.
// var cross = Math.pow(xdx,2) + Math.pow(xdy,2);
// then create the inverted axies
var ixdx = (xdx * sy) / cross; // create inverted x axis
var ixdy = (-xdy * sx) / cross;
var iydx = (xdy * sy) / cross; // create inverted y axis
var iydy = (xdx * sx) / cross;
// now remove the origin from the mouse coords
mouseX -= x;
mouseY -= y;
// multiply by the invers matrix
var localMouseX = mouseX * ixdx + mouseY * iydx;
var localMouseY = mouseX * ixdy + mouseY * iydy;
// and return the result
return {x : localMouseX, y : localMouseY};
}

Draw multiple draggable circle HTML5 Canvas

I have to draw mutiple draggable circles on an HTML5 canvas, and also I should move the circles after creating it. But while dragging to draw there are multiple frames created. How can I remove it without reloading the page?
Here is a demo of my code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
function handleMouseDown(e) {
e.preventDefault();
// e.stopPropagation();
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
isDown = true;
}
function handleMouseUp(e) {
if (!isDown) {
return;
}
e.preventDefault();
// e.stopPropagation();
isDown = false;
}
function handleMouseOut(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
isDown = false;
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
if (isDown) {
var dx = Math.abs(startX - mouseX);
var dy = Math.abs(startY - mouseY);
var midX = (startX + mouseX) / 2;
var midY = (startY + mouseY) / 2;
var r = Math.sqrt(dx * dx + dy * dy) / 2;
alert(midX, midY);
draw(midX, midY, r);
}
}
function draw(midX, midY, r) {
// ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(midX, midY, r, 0, 2 * Math.PI, false);
//ctx.restore();
//ctx.stroke();
ctx.fillStyle = getRandomColor();
ctx.fill();
}
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function(e) {
handleMouseOut(e);
});
#canvas {
border: 1px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Drag to draw circles</h4>
<canvas id="canvas" width=600 height=400></canvas>
<button onclick="location.reload()">Reset</button>
You can clear the canvas without reloading the page by using ctx.clearRect() like so:
ctx.clearRect(0, 0, canvas.width, canvas.height);
Working Live Demo:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
function handleMouseDown(e) {
e.preventDefault();
// e.stopPropagation();
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
isDown = true;
}
function handleMouseUp(e) {
if (!isDown) {
return;
}
e.preventDefault();
// e.stopPropagation();
isDown = false;
}
function handleMouseOut(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
isDown = false;
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
e.preventDefault();
//e.stopPropagation();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
if(isDown)
{
var dx = Math.abs(startX - mouseX);
var dy = Math.abs(startY - mouseY);
var midX = (startX + mouseX) / 2;
var midY = (startY + mouseY) / 2;
var r = Math.sqrt(dx * dx + dy * dy) / 2;
//alert(midX,midY);
draw(midX,midY,r);
}
}
function draw(midX,midY,r)
{
// ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(midX, midY, r, 0, 2 * Math.PI, false);
//ctx.restore();
//ctx.stroke();
ctx.fillStyle = getRandomColor();
ctx.fill();
}
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
$("#canvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
handleMouseOut(e);
});
document.getElementById("clear").onclick = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
#canvas {
border:1px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Drag to draw circles</h4>
<canvas id="canvas" width=600 height=400></canvas>
<button id="clear">Reset</button>
JSFiddle Version: https://jsfiddle.net/j9y7fqyx/

Resizing Canvas Image Position Issues

I'm using a HTML canvas to allow a user to edit (move, resize and rotate) an image on bottle to create their own custom one - similar to how a t-shirt designer would work.
It all works (there's a slight issue with the rotate though) up until you resize the screen. Because the canvas is horizontally centred on my page, when you reduce the size (or increase) from the initial load of the page - the canvas thinks the image on is still in its original place. Meaning that you cannot click the image to move it around, you have to click to the right or left (depending on how the screen is resized).
I think there's an issue with the maths, perhaps to do with the window or canvas offset not being updated when you resize the screen, but I cannot work out what the problem is.
Example: https://jsfiddle.net/mpsx1xnj/
The code is as follows:
<div id="design-canvas">
<canvas id="bottleCanvas" width="400" height="600"></canvas>
<center><canvas id="printableCanvas" width="71" height="245"></canvas></center>
<center><canvas id="editorCanvas" width="400" height="600"></canvas></center>
<p class="tooltip">Guidelines show the printable area on the bottle.</p>
</div>
var canvas = document.getElementById("editorCanvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#editorCanvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 4;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 0;
var imageY;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
var ratio;
var img = new Image();
img.crossOrigin='anonymous';
img.onload = function () {
ratio = img.width / img.height;
imageWidth = 71;
imageHeight = imageWidth / ratio;
imageY = (245-imageHeight)/2;
if (imageHeight > 245) {
imageHeight = 245;
imageWidth = imageHeight * ratio;
imageY = 0;
}
imageX = ((canvas.width-imageWidth)/2);
imageY = ((canvas.height-imageHeight)/2);
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
draw(true, false);
}
//img.src='https://dl.dropboxusercontent.com/u/139992952/multple/leftarrow.png';
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
offsetX = offsetX + window.pageXOffset;
offsetY = offsetY + window.pageYOffset;
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageWidth/ratio; //imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#editorCanvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#editorCanvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#editorCanvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#editorCanvas").mouseout(function (e) {
handleMouseOut(e);
});
function rotate(rotationPointX,rotationPointY,degreeRotation){
// Create an second in-memory canvas:
var mCanvas=document.createElement('canvas');
mCanvas.width=canvas.width;
mCanvas.height=canvas.height;
var mctx=mCanvas.getContext('2d');
// Draw your canvas onto the second canvas
mctx.drawImage(canvas,0,0);
// Clear your main canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// Rotate the main canvas
// set the rotation point as center of the canvas
// (but you can set any rotation point you desire)
ctx.translate(rotationPointX,rotationPointY);
// rotate by 90 degrees (==PI/2)
var radians=degreeRotation/180*Math.PI;
ctx.rotate(radians);
// Draw the second canvas back to the (now rotated) main canvas:
ctx.drawImage(mCanvas,-canvas.width/2,-canvas.height/2);
// clean up -- unrotate and untranslate
ctx.rotate(-radians);
ctx.translate(-canvas.width/2,-canvas.height/2);
}
$(window).on("resize scroll",function(e) {
offsetX = win.left;
offsetY = canvasOffset.top;
imageWidth = 71;
imageHeight = imageWidth / ratio;
imageY = (245-imageHeight)/2;
if (imageHeight > 245) {
imageHeight = 245;
imageWidth = imageHeight * ratio;
imageY = 0;
}
imageX = ((canvas.width-imageWidth)/2);
imageY = ((canvas.height-imageHeight)/2);
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
draw(true, false);
});
$('#rotate').click(function(){
rotate((imageX + (canvas.width/2)),(imageY + (canvas.height/2,90)));
});
So my question is how would I fix this issue, so that resizing the window causes no issue?
If i understand you correctly...
Here's a solution: jsFiddle
the width and height attributes of the canvas determine the width or height of the canvas's coordinate system - the page resizing only updates css properties (to make it responsive) which means your fixed width/height attrs always stay the same, even after a resize.
so on page resize
$('canvas#editorCanvas').attr('width', $('#design-canvas').width() );
$('canvas#editorCanvas').attr('height', $('#design-canvas').height() );
make the container responsive using max-height, max-width and setting height/width to 100%

Scale Canvas Image Proportionately

I'm using the following code to create a canvas to which the user uploads an image and can the drag, resize and rotate the image onto a product. Sort of like a tshirt design tool.
My problem is, I need to scale the image proportionately, so that when the user resizes the image it doesn't look distorted or stretched.
var canvas = document.getElementById("editorCanvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#editorCanvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var isDown = false;
var pi2 = Math.PI * 2;
var resizerRadius = 4;
var rr = resizerRadius * resizerRadius;
var draggingResizer = {
x: 0,
y: 0
};
var imageX = 0;
var imageY;
var imageWidth, imageHeight, imageRight, imageBottom;
var draggingImage = false;
var startX;
var startY;
var img = new Image();
img.crossOrigin='anonymous';
img.onload = function () {
var ratio = img.width / img.height;
imageWidth = 71;
imageHeight = imageWidth / ratio;
imageY = (245-imageHeight)/2;
if (imageHeight > 245) {
imageHeight = 245;
imageWidth = imageHeight * ratio;
imageY = 0;
}
imageX = ((canvas.width-imageWidth)/2);
imageY = ((canvas.height-imageHeight)/2);
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
draw(true, false);
}
//img.src='https://dl.dropboxusercontent.com/u/139992952/multple/leftarrow.png';
function draw(withAnchors, withBorders) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw the image
ctx.drawImage(img, 0, 0, img.width, img.height, imageX, imageY, imageWidth, imageHeight);
// optionally draw the draggable anchors
if (withAnchors) {
drawDragAnchor(imageX, imageY);
drawDragAnchor(imageRight, imageY);
drawDragAnchor(imageRight, imageBottom);
drawDragAnchor(imageX, imageBottom);
}
// optionally draw the connecting anchor lines
if (withBorders) {
ctx.beginPath();
ctx.moveTo(imageX, imageY);
ctx.lineTo(imageRight, imageY);
ctx.lineTo(imageRight, imageBottom);
ctx.lineTo(imageX, imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x, y) {
ctx.beginPath();
ctx.arc(x, y, resizerRadius, 0, pi2, false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x, y) {
var dx, dy;
// top-left
dx = x - imageX;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (0);
}
// top-right
dx = x - imageRight;
dy = y - imageY;
if (dx * dx + dy * dy <= rr) {
return (1);
}
// bottom-right
dx = x - imageRight;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (2);
}
// bottom-left
dx = x - imageX;
dy = y - imageBottom;
if (dx * dx + dy * dy <= rr) {
return (3);
}
return (-1);
}
function hitImage(x, y) {
return (x > imageX && x < imageX + imageWidth && y > imageY && y < imageY + imageHeight);
}
function handleMouseDown(e) {
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
draggingResizer = anchorHitTest(startX, startY);
draggingImage = draggingResizer < 0 && hitImage(startX, startY);
}
function handleMouseUp(e) {
draggingResizer = -1;
draggingImage = false;
draw(true, false);
}
function handleMouseOut(e) {
handleMouseUp(e);
}
function handleMouseMove(e) {
if (draggingResizer > -1) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight = imageX + imageWidth;
imageBottom = imageY + imageHeight;
// redraw the image with resizing anchors
draw(true, true);
} else if (draggingImage) {
imageClick = false;
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move the image by the amount of the latest drag
var dx = mouseX - startX;
var dy = mouseY - startY;
imageX += dx;
imageY += dy;
imageRight += dx;
imageBottom += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
// redraw the image with border
draw(false, true);
}
}
$("#editorCanvas").mousedown(function (e) {
handleMouseDown(e);
});
$("#editorCanvas").mousemove(function (e) {
handleMouseMove(e);
});
$("#editorCanvas").mouseup(function (e) {
handleMouseUp(e);
});
$("#editorCanvas").mouseout(function (e) {
handleMouseOut(e);
});
function rotate(rotationPointX,rotationPointY,degreeRotation){
// Create an second in-memory canvas:
var mCanvas=document.createElement('canvas');
mCanvas.width=canvas.width;
mCanvas.height=canvas.height;
var mctx=mCanvas.getContext('2d');
// Draw your canvas onto the second canvas
mctx.drawImage(canvas,0,0);
// Clear your main canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// Rotate the main canvas
// set the rotation point as center of the canvas
// (but you can set any rotation point you desire)
ctx.translate(rotationPointX,rotationPointY);
// rotate by 90 degrees (==PI/2)
var radians=degreeRotation/180*Math.PI;
ctx.rotate(radians);
// Draw the second canvas back to the (now rotated) main canvas:
ctx.drawImage(mCanvas,-canvas.width/2,-canvas.height/2);
// clean up -- unrotate and untranslate
ctx.rotate(-radians);
ctx.translate(-canvas.width/2,-canvas.height/2);
}
$('#rotate').click(function(){
rotate(canvas.width/2,canvas.height/2,90);
});
I presume there's a way of doing it, i'm just not entirely sure what would need changing or what's wrong in the code for it.
So my question is how do I change my code to allow for proportional scaling?
I actually managed to fix this by editing the maths in the handleMouseMove(e) function like so:
// resize the image
switch (draggingResizer) {
case 0:
//top-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageY = mouseY;
imageHeight = imageBottom - mouseY;
break;
case 1:
//top-right
imageY = mouseY;
imageWidth = mouseX - imageX;
imageHeight = imageWidth/ratio; //imageBottom - mouseY;
break;
case 2:
//bottom-right
imageWidth = mouseX - imageX;
imageHeight = mouseY - imageY;
break;
case 3:
//bottom-left
imageX = mouseX;
imageWidth = imageRight - mouseX;
imageHeight = mouseY - imageY;
break;
}
The place before I commented the code is the fix - this ensures the imageHeight is proportional to the imageWidth by using the initially calculated ratio.

HTML5 canvas, make image rotate around click to select and drag circle

I have completed code that has a user click a button (to the right of the canvas), then the image is added to the canvas and is constrained to only move around the circumference of a circle. In order to move the image the user just needs to click the image and then move the mouse. To release the image the user simply needs to click where the image goes on the canvas.
Here is a fiddle showing what the current code does.
http://jsfiddle.net/smacnabb/68awv7sq/9/
Question: I am looking to be able to have the images that move around the circumference of the circle rotate while moving around the circumference of the circle.
This is what I mean:
Here is a fiddle for the code I added to try and make this happen
http://jsfiddle.net/smacnabb/68awv7sq/11/
in the handlemousemove method, it calls state.draw() every time the mouse move i'm passing mouseX, mouseY to state.draw.
state.draw() is in addstate method and this was the code I added to make the image rotate
var dx = mouseX - centerX;
var dy = mouseY - centerY;
var radianAngle = Math.atan2(dy, dx);
context.save();
context.translate(centerX, centerY);
context.rotate(radianAngle);
if (this.dragging) {
context.strokeStyle = 'black';
context.strokeRect(this.x, this.y, this.width + 2, this.height + 2)
}
context.drawImage(this.image, this.x, this.y);
context.restore();
What am I doing wrong?
You are close...Take a look at this example:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var canvasOffset = $canvas.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var radianAngle = 0;
var cx = 225;
var cy = 125;
var radius = 50;
// image loader
var imageURLs = [];
var imagesOK = 0;
var imgs = [];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/cars.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/plane.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/cars1.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/multple/plane1.png");
loadAllImages(start);
function loadAllImages(callback) {
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function() {
imagesOK++;
if (imagesOK >= imageURLs.length) {
callback();
}
};
img.onerror = function() {
alert("image load failed");
}
img.crossOrigin = "anonymous";
img.src = imageURLs[i];
}
}
var imagesY = 20;
var targets = [];
var selectedTarget = -1;
function start() {
var n = imgs.length / 2;
for (var i = 0; i < n; i++) {
var target = imgs[i + n];
ctx.drawImage(target, 15, imagesY);
targets.push({
x: 15,
y: imagesY,
width: target.width,
height: target.height,
image: imgs[i]
});
imagesY += target.height + 10;
}
}
function handleMouseDown(e) {
e.preventDefault();
x = parseInt(e.clientX - offsetX);
y = parseInt(e.clientY - offsetY);
for (var i = 0; i < targets.length; i++) {
var t = targets[i];
if (x >= t.x && x <= t.x + t.width && y >= t.y && y <= t.y + t.height) {
selectedTarget = i;
draw(x, y);
}
}
}
function handleMouseMove(e) {
if (selectedTarget < 0) {
return;
}
e.preventDefault();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
draw(mouseX, mouseY);
}
function draw(mouseX, mouseY) {
var dx = mouseX - cx;
var dy = mouseY - cy;
var radianAngle = Math.atan2(dy, dx);
// Drawing code goes here
var img = targets[selectedTarget].image;
ctx.clearRect(100, 0, canvas.width, canvas.height);
// draw the circle
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
// draw the image rotated around the circumference
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(radianAngle);
ctx.drawImage(img, radius - img.width / 2, -img.height / 2);
ctx.restore();
}
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Select an icon on left by clicking<br>
Then move mouse to have icon rotate around circle</h4>
<canvas id="canvas" width=350 height=350></canvas>

Categories

Resources