Get full ImageData after Panning the image inside Cavnas

168 views Asked by At

I have a situation where I need to get the full ImageData inside the canvas even after panning the image.

Thanks in Advance

Example in the fiddle: https://jsfiddle.net/z46cvm9h/

<canvas id="canvas"></canvas>
<button onclick="showImage()">
Show panned Image
</button>
<img id="image" src='' />
var context     = canvas.getContext("2d");
canvas.width    = 400;
canvas.height   = 300;

var global = {
scale : 1,
offset    : {
 x : 0,
 y : 0,
},
};
var pan = {
start : {
 x : null,
 y : null,
},
offset : {
 x : 0,
 y : 0,
},
};

function draw() {
context.setTransform(1, 0, 0, 1, 0, 0);
context.clearRect(0, 0, canvas.width, canvas.height);

context.translate(pan.offset.x, pan.offset.y);

context.beginPath();
context.rect(50, 50, 100, 100);
context.fillStyle = 'skyblue';
context.fill();

context.beginPath();
context.arc(350, 250, 50, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();

}

draw();

canvas.addEventListener("mousedown", startPan);
canvas.addEventListener("mouseleave", endPan);
canvas.addEventListener("mouseup", endPan);

function startPan(e) {
canvas.addEventListener("mousemove", trackMouse);
canvas.addEventListener("mousemove", draw);
pan.start.x = e.clientX;
pan.start.y = e.clientY;
}

function endPan(e) {
canvas.removeEventListener("mousemove", trackMouse);
pan.start.x = null;
pan.start.y = null;
global.offset.x = pan.offset.x;
global.offset.y = pan.offset.y;
}

function trackMouse(e) {
var offsetX    = e.clientX - pan.start.x;
var offsetY    = e.clientY - pan.start.y;
pan.offset.x = global.offset.x + offsetX;
pan.offset.y = global.offset.y + offsetY;
}

function showImage(){
document.getElementById('image').src = canvas.toDataURL();
}

PS: JSFiddle is for demonstration, I can't put the exact scenario into JSFiddle. In the application, I pan the image and then use the mouse to draw something on the canvas using the mousedown and mousemove events. On the mouseup event, I need to have the ImageData with the full image I drew, but when using getImageData, I am only getting the image appearing on the canvas. The panned image is cropped to the canvas size.

1

There are 1 answers

0
Daniel On

As @Blindman67 suggested, you can make a second canvas.

Create an object to store the furthest away points in your image.

const imagePadding = {
  top: 0,
  right: 0,
  bottom: 0,
  left: 0
}

top shall be the highest point of the drawing, right shall be the point furthest to the right, and so on. For demonstration purposes, the padding is set equal to how far you have panned in each direction. You will want to set it equal to the shapes/points of the drawing that are furthest in each direction (up, right, down, and left--those are the directions I am talking about).

function panImage(e) {
  pan.x += e.movementX
  pan.y += e.movementY
  drawPreview()
  
  imagePadding.top = Math.max(imagePadding.top, pan.y)
  imagePadding.left = Math.max(imagePadding.left, pan.x)
  imagePadding.bottom = Math.max(imagePadding.bottom, -pan.y)
  imagePadding.right = Math.max(imagePadding.right, -pan.x)
}

To draw the full image, you can make a function like this:

function drawFinalImage() {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  const pannedImage = document.getElementById('image')

  canvas.width = previewCanvas.width + imagePadding.left + imagePadding.right
  canvas.height = previewCanvas.height + imagePadding.top + imagePadding.bottom

  ctx.translate(imagePadding.left, imagePadding.top)
  drawShapes(ctx)

  pannedImage.src = canvas.toDataURL()
}

See the JSFiddle for a demo as well as how you can implement the code. Let me know if there is anything I should explain better.

You can use JSFiddle Console to adjust the padding. Type imagePadding.top = 200, press enter, and click the canvas to update the final image.

imagePadding.top = 200