To achieve pan-functionality with peep-hole, it's just a matter of two drawing operations, one full and one cropped.
To get this result , you can do the following ( see full code here ):
Settings:
var ctx = canvas.getContext('2d'), ix = 0, iy = 0, /// image position offsetX = 0, offsetY = 0, /// current offsets deltaX, deltaY, /// deltas from mouse down mouseDown = false, /// in mouse drag img = null, /// background rect, /// rect position rectW = 200, rectH = 150; /// size of highlight area
Configure the basic functions that you use to set the size according to the size of the window (including when resizing):
/// calc canvas w/h in relation to window as well as /// setting rectangle in center with the pre-defined /// width and height function setSize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; rect = [canvas.width * 0.5 - rectW * 0.5, canvas.height * 0.5 - rectH * 0.5, rectW, rectH] update(); } /// window resize so recalc canvas and rect window.onresize = setSize;
The main function in this is the draw function. Here we draw the image at the position calculated by the mouse movement (see the next section).
- The first step to get this blurry look is to set the alpha to about 0.2 (you can also draw a transparent rectangle on top, but it's more efficient).
- Then draw the full image.
- Reset alpha
- Draw a pip hole using clipping with corrected offsets for the source.
-
/// main draw function update() { if (img === null) return; /// limit x/y as drawImage cannot draw with negative /// offsets for clipping if (ix + offsetX > rect[0]) ix = rect[0] - offsetX; if (iy + offsetY > rect[1]) iy = rect[1] - offsetY; /// clear background to clear off garbage ctx.clearRect(0, 0, canvas.width, canvas.height); /// make everything transparent ctx.globalAlpha = 0.2; /// draw complete background ctx.drawImage(img, ix + offsetX, iy + offsetY); /// reset alpha as we need opacity for next draw ctx.globalAlpha = 1; /// draw a clipped version of the background and /// adjust for offset and image position ctx.drawImage(img, -ix - offsetX + rect[0], /// sx -iy - offsetY + rect[1], /// sy rect[2], rect[3], /// sw/h /// destination rect[0], rect[1], rect[2], rect[3]); /// make a nice sharp border by offsetting it half pixel ctx.strokeRect(rect[0] + 0.5, rect[1] + 0.5, rect[2], rect[3]); }
Now it's a matter of processing the mouse, moving and zooming in, and calculating the offsets -
At the bottom of the mouse, we save the current position of the mouse, which we will use to calculate the deltas on the mouse movement:
canvas.onmousedown = function(e) { /// don't do anything until we have an image if (img === null) return; /// correct mouse pos var coords = getPos(e), x = coords[0], y = coords[1]; /// store current position to calc deltas deltaX = x; deltaY = y; /// here we go.. mouseDown = true; }
Here we use the delta to avoid jumping the image by setting the angle to the position of the mouse. Deltas are transferred as offsets to the update function:
canvas.onmousemove = function(e) { /// in a drag? if (mouseDown === true) { var coords = getPos(e), x = coords[0], y = coords[1]; /// offset = current - original position offsetX = x - deltaX; offsetY = y - deltaY; /// redraw what we have so far update(); } }
And finally, with the mouse, we make the displacements a constant part of the image position:
document.onmouseup = function(e) { /// was in a drag? if (mouseDown === true) { /// not any more!!! mouseDown = false; /// make image pos. permanent ix += offsetX; iy += offsetY; /// so we need to reset offsets as well offsetX = offsetY = 0; } }
To scale the canvas, I believe that this question has already been answered: you should merge this with the answer given here:
Zoom Canvas to Mouse Cursor