Friday, February 17, 2012

HTML5 Canvas Drawing Library

This library will allow you to create as many Canvas elements as you wish on a single page. It does not matter if you have the canvas element inside multiple elements or if the page is too long (scrollable).

There are  a few tutorials online on how to create a canvas drawing app but most assume that you are placing them on a regular HTML page. I tried most of them but since I wanted to use it in my AJAX web application where I load everything inside DIV elements the mouse positioning was always off when the container scrolled up or down.

This is also compatible with mobile browsers. I have tested it on iOS and Android browsers. It will detect a touch event or a mouse event based on the client. This was built to be unobtrusive but the only drawback is that you need jQuery to run this. You do not need to know anything about jQuery jus thow to include it.

The following is the HTML that you need to create 2 canvases. Place this in the body tag of your document.

<fieldset id="palette_canvas1"><legend>Canvas #1</legend>
<canvas id="canvas1" width="600" height="450" style="border:thin solid #000; margin:auto; background-color:white;"></canvas><br />
<script>
canvas1 = new prepare_canvas();
canvas1.create_canvas("canvas1");
</script>
</fieldset>
<fieldset id="palette_canvas2"><legend>Canvas #2</legend>
<canvas id="canvas2" width="600" height="450" style="border:thin solid #000; margin:auto; background-color:white;"></canvas><br />
<script>
canvas2 = new prepare_canvas();
canvas2.create_canvas("canvas2");
</script>
</fieldset>

What you need to make sure is that the ID of the container is pallete_"CANVASID", the ID of the canvas element itself should be the CANVASID and when the object is created it needs to be with CANVASID.
Now for the Javascript:
function prepare_canvas()
{
var prepare_canvas_obj = new Object();
var canvas;
var canvas_ctx;
var canvas_color;
var numeric_color;
var cb_lastPointsQuiz = Array();
//create the palette
function create_palette(canvasID)
{
if(!document.getElementById('palette_'+canvasID))
{
return false;
}
var palette_container = document.createElement('div');
palette_container.id = 'paletter_container_'+canvasID;
palette_container.innerHTML = '<span id="selected_color_'+canvasID+'"></span>';
palette_container.innerHTML += '<div><img id="green_image_'+canvasID+'" title="Change to Green" onclick="'+canvasID+'.changeColor(2);" style="cursor:pointer" src="images/pngs/bullet_green.png">&nbsp;<img id="blue_image_'+canvasID+'" title="Change to Blue" onclick="'+canvasID+'.changeColor(3);" style="cursor:pointer" src="images/pngs/bullet_blue.png">&nbsp;<img id="red_image_'+canvasID+'" title="Change to Red" onclick="'+canvasID+'.changeColor(1);" style="cursor:pointer" src="images/pngs/bullet_red.png">&nbsp;<img id="black_image_'+canvasID+'" title="Change to Black" onclick="'+canvasID+'.changeColor(4);" style="cursor:pointer" src="images/pngs/bullet_black.png">&nbsp;<img id="eraser_image_'+canvasID+'" title="Eraser" onclick="'+canvasID+'.changeColor(5);" height="16px" style="cursor:pointer" src="images/pngs/eraser.png">&nbsp;<img id="size_increase_'+canvasID+'" title="Increase Size" onclick="'+canvasID+'.changeSize(1);" height="16px" style="cursor:pointer" src="images/pngs/16-arrow-down.png">&nbsp;<img id="size_decrease_'+canvasID+'" title="Decrease Size" onclick="'+canvasID+'.changeSize(2);" height="16px" style="cursor:pointer" src="images/pngs/16-arrow-up.png">&nbsp;';
document.getElementById('palette_'+canvasID).appendChild(palette_container);
return true;
}
function create_canvas(canvasID) {
canvas = document.getElementById(canvasID);
var palette_created = create_palette(canvasID);
if(!palette_created)
{
alert('Palette could not be created. Please enclose the canvas element inside a DIV with ID palette_'+canvasID);
}
canvas_color = canvas_select_color(1);
if (canvas.getContext) {
canvas_ctx = canvas.getContext('2d');
canvas_ctx.lineWidth = 2;
canvas_ctx.strokeStyle = canvas_color;
showSelectedColor(canvas_color);
canvas_ctx.beginPath();
canvas.onmousedown = startDraw;
canvas.onmouseup = stopDraw;
canvas.ontouchstart = startDraw;
canvas.ontouchstop = stopDraw;
canvas.ontouchmove = drawMouse;
}else{
alert('Could not get context');
}
}//end create canvas
//select color
function canvas_select_color(colorNumber)
{
var color_return;
switch (colorNumber)
{
case 1:
//red
color_return = "rgb(255,0,0)";
break;
case 2:
//green
color_return = "rgb(0,255,0)";
break;
case 3:
//blue
color_return = "rgb(0,0,255)";
break;
case 4:
//black
color_return = "rgb(0,0,0)";
break;
case 5:
//eraser
color_return = "rgb(255,255,255)";
break;
default:
color_return = "rgb(255,0,0)";
}
return color_return;
}//end select color
//show selected color
function showSelectedColor(selectedColor)
{
document.getElementById('red_image_'+canvas.id).style.border = '';
document.getElementById('blue_image_'+canvas.id).style.border = '';
document.getElementById('green_image_'+canvas.id).style.border = '';
document.getElementById('black_image_'+canvas.id).style.border = '';
document.getElementById('eraser_image_'+canvas.id).style.border = '';
canvas_ctx.lineWidth=2;
if(selectedColor=="rgb(255,0,0)")
{
document.getElementById('selected_color_'+canvas.id).innerHTML = '<strong style="color:red">RED</strong>';
document.getElementById('red_image_'+canvas.id).style.border = '1px black solid';
}else if(selectedColor=="rgb(0,255,0)"){
document.getElementById('selected_color_'+canvas.id).innerHTML = '<strong style="color:green">GREEN</strong>';
document.getElementById('green_image_'+canvas.id).style.border = '1px black solid';
}else if(selectedColor=="rgb(0,0,255)"){
document.getElementById('selected_color_'+canvas.id).innerHTML = '<strong style="color:blue">BLUE</strong>';
document.getElementById('blue_image_'+canvas.id).style.border = '1px black solid';
}else if(selectedColor=="rgb(0,0,0)"){
document.getElementById('selected_color_'+canvas.id).innerHTML = '<strong style="color:black">BLACK</strong>';
document.getElementById('black_image_'+canvas.id).style.border = '1px black solid';
}else if(selectedColor=="rgb(255,255,255)"){
document.getElementById('selected_color_'+canvas.id).innerHTML = '<strong style="color:black">Eraser</strong>';
document.getElementById('eraser_image_'+canvas.id).style.border = '1px black solid';
canvas_ctx.lineWidth=20;
}
}//end show selected color
//start draw
function startDraw(e) {
if (e.touches) {
// Touch event
for (var i = 1; i <= e.touches.length; i++) {
cb_lastPointsQuiz[i] = getCoords(e.touches[i - 1]); // Get info for finger #1
}
}else {
// Mouse event
cb_lastPointsQuiz[0] = getCoords(e);
canvas.onmousemove = drawMouse;
}
return false;
}
// Called whenever cursor position changes after drawing has started
function stopDraw(e) {
e.preventDefault();
canvas.onmousemove = null;
}
function drawMouse(e) {
if (e.touches) {
// Touch Enabled
for (var i = 1; i <= e.touches.length; i++) {
var p = getCoords(e.touches[i - 1]); // Get info for finger i
cb_lastPointsQuiz[i] = drawLine(cb_lastPointsQuiz[i].x, cb_lastPointsQuiz[i].y, p.x, p.y);
}
}
else {
// Not touch enabled
var p = getCoords(e);
cb_lastPointsQuiz[0] = drawLine(cb_lastPointsQuiz[0].x, cb_lastPointsQuiz[0].y, p.x, p.y);
}
canvas_ctx.stroke();
canvas_ctx.closePath();
canvas_ctx.beginPath();
return false;
}
function drawLine(sX, sY, eX, eY) {
canvas_ctx.moveTo(sX, sY);
canvas_ctx.lineTo(eX, eY);
return { x: eX, y: eY };
}
function getCoords(e) {
var x = e.pageX - $(document).scrollLeft() - $(canvas).offset().left;
var y = e.pageY - $(document).scrollTop() - $(canvas).offset().top;
return { x: x, y: y };
}
function changeColor(the_color)
{
var color_changed = canvas_select_color(the_color);
canvas_ctx.strokeStyle = color_changed;
showSelectedColor(color_changed);
numeric_color = the_color;
//new_color = the_color;
}
//increase or decrease size
function changeSize(op)
{
//changing size clears the canvas so save and restore
var orig_height = canvas.height;
var bitmap = canvas_ctx.getImageData(0, 0, canvas.width, canvas.height);
if(op==1)
{
//increase
canvas.height = orig_height + 100;
canvas_ctx.putImageData(bitmap, 0, 0);
changeColor(numeric_color);
}else{
//decrease
if(orig_height>200)
{
canvas.height = orig_height - 100;
canvas_ctx.putImageData(bitmap, 0, 0);
changeColor(numeric_color);
}else{
alert('Cannot decrease size more than this.');
}
}
}
prepare_canvas_obj.create_canvas = create_canvas;
prepare_canvas_obj.canvas_select_color = canvas_select_color;
prepare_canvas_obj.showSelectedColor = showSelectedColor;
prepare_canvas_obj.startDraw = startDraw;
prepare_canvas_obj.changeColor = changeColor;
prepare_canvas_obj.changeSize = changeSize;
return prepare_canvas_obj;
}
view raw canvas_draw.js hosted with ❤ by GitHub

jQuery is only used to get the position of the cursor in this function getCoords(e)
I had previously used this function but it does not work if the container is scrollable.

Canvas is a very powerful element with a huge potential and I cannot wait for the day that we will reminisce and say "Remember that really buggy application that drove everyone crazy? It did not work on Linux, Mac and had so many security issues in Windows....What was it called? Ah, yes Flash."

No comments:

My Blog List