Resizing Canvas Image Position Issues

579 views Asked by At

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?

1

There are 1 answers

1
mani On

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%