html5 canvas - specific - Shift canvas contents to the left



returns method (4)

Is there an easy way to shift canvas contents to the left, dropping the leftmost pixels and moving all others to the left?

https://src-bin.com


Answer #1

Check out this jsFiddle example which uses ctx.translate and ctx.get/putImageData.

source code here

How it was done:

If redrawing what you want to shift is not too slow, the canvas transform methods are worth using.

get/putImageData will also work if you just want to shift the current contents of the canvas without redrawing. This is not without disadvantages; it must make a copy of the pixel region being moved and it cannot be used if you draw any images from an external domain on your canvas:

Whenever the getImageData() method of the 2D context of a canvas element whose origin-clean flag is set to false is called with otherwise correct arguments, the method must throw a SecurityError exception.

In case jsFiddle should ever fail, here's the code:

HTML:

<a href="javascript:doIt()">shift 25 pixels to the left using `translate`</a><br>
<a href="javascript:shiftImage()">shift 25 pixels to the left using `getImageData/putImageData`</a><br>
<canvas id="canvas" width="600" height="200"></canvas>

JS:

var canvas = document.getElementById( "canvas" ),
    ctx = canvas.getContext( "2d" );

var xOff = 0;
var redraw = function() {
        ctx.clearRect(0, 0, 600, 200);
        ctx.save();
        ctx.translate(xOff, 0);

        ctx.font = "100px Arial";
        ctx.fillText( "Google", 20, 130 );

        ctx.restore();
};

window.doIt = function() {
    xOff -= 25;
    redraw();
}

redraw();

var shiftContext = function(ctx, w, h, dx, dy) {
  var clamp = function(high, value) { return Math.max(0, Math.min(high, value)); };
  var imageData = ctx.getImageData(clamp(w, -dx), clamp(h, -dy), clamp(w, w-dx), clamp(h, h-dy));
  ctx.clearRect(0, 0, w, h);
  ctx.putImageData(imageData, 0, 0);
}

window.shiftImage = function() {
  shiftContext(ctx, 600, 200, -25, 0);   
}


var shiftContext = function(ctx, w, h, dx, dy) {
  var clamp = function(high, value) { return Math.max(0, Math.min(high, value)); };
  var imageData = ctx.getImageData(clamp(w, -dx), clamp(h, -dy), clamp(w, w-dx), clamp(h, h-dy));
  ctx.clearRect(0, 0, w, h);
  ctx.putImageData(imageData, 0, 0);
};

window.shiftImage = function() {
  shiftContext(ctx, 600, 200, -25, 0);   
};

Answer #2

I happened to be wondering if there was a convenient way to do this. I ended up coming up with this translate function, which doesn't require any of the (very slow) image data functions:

function translate(x, y) {
    ctxBuffer.clearRect(0,0,canvasBuffer.width,canvasBuffer.height); //clear buffer
    ctxBuffer.drawImage(canvasDisplay,0,0); //store display data in buffer
    ctxDisplay.clearRect(0,0,canvasDisplay.width,canvasDisplay.height); //clear display
    ctxDisplay.drawImage(canvasBuffer,x,y); //copy buffer to display
}

I've made a quick demo of it here.


Answer #3

Perfect guys and thanks. Here's a simplified version of ellisbben's code, works a treat for some scrolling graphs I've building:

function shift_canvas(ctx, w, h, dx, dy) {
  var imageData = ctx.getImageData(0, 0, w, h);
  ctx.clearRect(0, 0, w, h);
  ctx.putImageData(imageData, dx, dy);
}

Answer #4

Using getImageData and putImageData you could easily implement a pixel-by-pixel shift. For instance:

// shift everything to the left:
var imageData = context.getImageData(1, 0, context.canvas.width-1, context.canvas.height);
context.putImageData(imageData, 0, 0);
// now clear the right-most pixels:
context.clearRect(context.canvas.width-1, 0, 1, context.canvas.height);




html5-canvas