Building a Drawing Board

Today, We will build a plugin to add a drawing board to your website. Now the drawing board we will be building today is a simple one but adding more functionalities is just as easy. Before we begin, let me point out the prerequisite to this tutorial. You must have a little experience in JavaScript as well as Canvas API.

Let’s get started!

HTML

Everything we would be doing is in a single canvas element. Also for the sake of this tutorial, I would be making the canvas fill up the entire screen.

<canvas id='board'>Canvas is not supported!</canvas>

Give the canvas element an ID of board so we could access it in JavaScript. Also make sure to use a newer browser that supports Canvas API.

JAVASCRIPT

We would need to access the Canvas element using the ID we had given before and make it fill the entire screen.

var board = document.getElementById("board"),
	        context = board.getContext('2d');
board.width = window.innerWidth;
board.height = window.innerHeight;

Now the way we will make people give the illusion of drawing is by making small circles (dots) at every mouse position when they click and drag the mouse. Let’s define some variables to configure the dragging event.

var radius = 10,
    dragging = false;

context.lineWidth = 2 * radius;

Next we define a method to convert degree to radian for simplicity. It is optional.

// Convert Degree to Radian
var deg2rad = function (deg) {
	return (Math.PI / 180) * deg;
}

Handling dragging is easy. We will just need to keep track the distance traveled by mouse in between the mouse down and mouse up events.

// Handling Dragging end event
var dragOut = function () {
	dragging = false;
	context.beginPath();
}

// Handling Dragging start event
var dragIn = function (e) {
	dragging = true;
	putPoint(e);
}

Finally, At each step of dragging, we output a small circle on the screen at the mouse coordinates.

// Putting a small circle at coordinates
var putPoint = function(e) {
	if(dragging) {
		context.lineTo(e.clientX, e.clientY);
		context.stroke();
		context.beginPath();
		context.arc(e.clientX, e.clientY, radius, deg2rad(0), deg2rad(360));
		context.fill();

		context.beginPath();
		context.moveTo(e.clientX, e.clientY);
	}
}

// Attaching Handlers to events
board.addEventListener("mousedown", dragIn);
board.addEventListener("mousemove", putPoint);
board.addEventListener("mouseup", dragOut);

At this point, we have a drawing board that would show a trail of your mouse if you click and drag. But it’s not very pretty and not a whole lot of options. Let’s add some features.

Adding Radius Control

What we are aiming for is two buttons that allow us to increase or decrease the circle radius of putPoint method. Let’s add two buttons in the HTML. We will also add a span to show the current selected radius.

 


<div id='toolbar'>
    <div id="rad">
        Radius: <span id="radval"></span>
        <div id="decrad" class="radControl">-</div>
        <div id="incrad" class="radControl">+</div>
    </div>
</div>

Let’s add some variables in JavaScript for radius control. We will define minimum and maximum value for the radius and also the rate at which the radius will increase or decrease on clicking the buttons.

var minRadius = 0.5,
	maxRadius = 100,
	defaultRadius = 10,
	interval = 5,
	radSpan = document.getElementById('radval'),
	decrad = document.getElementById('decrad'),
	incrad = document.getElementById('incrad');

Now for the method to change the radius of out circle. We will change the lineWidth property of the context object.

var setRadius = function(rad) {
	if(rad < minRadius) { rad = minRadius; } if(rad > maxRadius) {
		rad = maxRadius;
	}

	radius = rad;
	context.lineWidth = 2*radius; 
	radSpan.innerHTML = radius;
}

Finally add the event handlers for the buttons.

var decrementRadius = function() {
	setRadius(radius - interval);
}

var incrementRadius = function() {
	setRadius(radius + interval);
}

decrad.addEventListener("click", decrementRadius);
incrad.addEventListener("click", incrementRadius);
setRadius(defaultRadius);

And we are done. Wait! Not yet! The color is still black which is ugly. So we would add another functionality to change the color.

Changing The Color

We will add some color palettes in the board for the user to select. You can change this functionality to allow user to select from a varied range of colors. Add the container to hold the color palettes inside the toolbar div.


<div id='colors'></div>

Again, Starting with the variables and method to set the color. The method change the strokeStyle and fillStyle properties of the context object.

var colors = ["black", "red", "green", "blue", "grey", "white"];
var colorPalete = document.getElementById("colors");

var setColor = function(color) {
	alert(color);
	context.strokeStyle = color;
	context.fillStyle = color;
}

Now to build the swatches to show to the user. We will attach an event listener to the click event to each swatch.

// Build swatches based on the colors list
for(var i = 0, n = colors.length; i < n ; i++) {
	var swatch = document.createElement('div');
	swatch.classList.add("swatch");
	swatch.classList.add(colors[i]);
	swatch.addEventListener("click", setSwatch);

	colorPalete.appendChild(swatch);
}

// Event Handler to change color based on the swatch clicked
var setSwatch = function(e) {
	var swatch = e.target;

	if(swatch) {
		if (swatch.currentStyle) {
		    var color = swatch.currentStyle.backgroundColor;
		    setColor(color);
		} else if (window.getComputedStyle) {
		    var color = window.getComputedStyle(swatch).backgroundColor;
		    setColor(color);
		} else {
			var color = "#069";
			setColor(color);
		}
		
		var active = document.getElementsByClassName('active')[0];
		if(active) active.classList.remove ('active');

		swatch.classList.add('active');
	}
}

// Setting the first swatch color as default
setSwatch(document.getElementsByClassName('swatch')[0]);

 

Saving the magic

Final functionality we will add to the board application is the ability to save the drawing. Up until now, all the functionalities would have worked without hosting but for this to work, we would require a server. Try localhost server such as wamp for windows and lamp for linux. Alternatively, you can also create the file in JavaScript and make it download to user without using server or PHP. Once again, add the control button in toolbor div.


<div id='save'>
    <span>Save</span>
</div>

To save the file, We will make an ajax call to the PHP file called save.php and send it the data received from the toDataURL method of the canvas object.

var saveButton = document.getElementById("save"),
	destination = 'save.php';

function saveImage() {
	var data = board.toDataURL();

	var request = new XMLHttpRequest();

	request.onReadyStateChange = function() {
		if(request.readyState == 4 && request.status == 200) {
			var file = request.responseText;
			
		}
	}
	
	request.open('POST', destination, true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

	request.send('img=' + data);
}

saveButton.addEventListener("click", saveImage);

The save.php file simply creates an image object with the given base64 data string.

<?php 
        $data = $_POST['img']; 
        $data = str_replace('data:image/png;base64,', '', $data); 
        $data = str_replace(' ', '+', $data); 
        $image = base64_decode($data); 
        $path = 'Images/' . uniqid() . '.png'; 

        if(file_put_contents($path, $image)) { 
            print $path; 
        } else { 
            header("HTTP/1.1 500 Internal Server Error"); 
        } 
?>

The source code for the application is available on GitHub. Wanna check out a quick demo of the final product.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s