Wednesday, February 27, 2013

html5 canvas for image with touch/click interactions

I successfully used html5 canvas to implement a parking lot image with an ability to show occupancy status in addition to selecting an individual parking spot for reserving. In the implementation, I used one canvas object on which the parking lot image is drawn using;

   ctx = canvas.getContext('2d');
   ctx.drawImage(...);

I created a utility functions to clips partly

       function clipCanvas(x,y,w,h) {
return ctx.getImageData(x,y,w,h);
}

or buffer completely a canvas state;


       function bufferCurrentCanvas(x,y,w,h) {
if (!bufferCanvas) bufferCanvas = document.createElement('canvas');
bufferCanvas.width  = w;
bufferCanvas.height = h;
bufferCanvas.getContext('2d').clearRect(x,y,w,h);
bufferCanvas.getContext('2d').drawImage(canvas, x, y, w, h, x, y, w, h );
return bufferCanvas;
}

To support spot selection functionality I had to create a metadata for the image. The metadata consists of the coordinates x,y, width, height and parking spots for all parking blocks. To determine if a specific block is clicked/touched (on a touch device) I first determine if a the mouse click coordinate is within a block and if true determine which parking spot within that block is selected by using a offset calculation logic based on the parking spot height and width information, which is constant for a given image.

As part of parking occupancy status, I implemented an animation of flipping a colored rectangle on parking spot, to show a recently parked car. This animation is completely implemented using canvas functionality;


              function animateStatus(spotInfo, img) {
var xoffset = 0,
step = 1,
horzOrient = ('angle' in spotInfo && spotInfo.angle === 90);
flipW = horzOrient ? parkStatus.blockInfo.carHeight/2 : parkStatus.blockInfo.carWidth/2,
flipped = false,
flipSpeed = 50;
var saveBg = horzOrient ? clipCanvas(spotInfo.x, spotInfo.y, parkStatus.blockInfo.carHeight, parkStatus.blockInfo.carWidth): clipCanvas(spotInfo.x, spotInfo.y, parkStatus.blockInfo.carWidth, parkStatus.blockInfo.carHeight);
function drawImg(){
if(flipped)
xoffset -= step;
else
xoffset += step;

function drawAndWait() {
setTimeout(drawImg, flipSpeed);
//clear old image
ctx.putImageData(saveBg, spotInfo.x, spotInfo.y);
//draw new image
if(horzOrient)
ctx.drawImage(img, spotInfo.x+xoffset, spotInfo.y, parkStatus.blockInfo.carHeight-(xoffset*2), parkStatus.blockInfo.carWidth);
else
ctx.drawImage(img, spotInfo.x+xoffset, spotInfo.y, parkStatus.blockInfo.carWidth-(xoffset*2), parkStatus.blockInfo.carHeight);
}

if(!flipped && spotInfo.x + xoffset <= spotInfo.x + flipW) {
drawAndWait();
}else {
flipped = true;
if(flipped && xoffset > 0){
drawAndWait();
}
}
}

drawImg();
}


This implementation will work without any code change once the metadata for the new image is provided.

If you are interested in additional code snippets I can provide it.






No comments:

Post a Comment