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%