1

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.

Danny
  • 669
  • 9
  • 20
Niranth Reddy
  • 493
  • 1
  • 11
  • 27
  • 1
    Use a second canvas that is large enough for all of the pixels you want to get and draw the content on that then use getImageData from the second canvas. – Blindman67 Jul 09 '20 at 14:58
  • @Blindman67 Am not so clear of it, can you please explain a bit more, with kind of an example – Niranth Reddy Jul 09 '20 at 15:22
  • Sorry, the reported problem is about `getImageData`, but I can't find in your code how and when you are calling it. It's hard to answer. – Daniele Ricci Jul 09 '20 at 16:02
  • More than this you say that you are using mouseDown and mouseMove to draw something but in your code these events are used to move the image.... it's really too hard to try to answer to this question – Daniele Ricci Jul 09 '20 at 16:16

1 Answers1

1

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

Dharman
  • 30,962
  • 25
  • 85
  • 135
Danny
  • 669
  • 9
  • 20