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.
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.