Create a realistic pencil tool for a painting app with HTML5 Canvas
You could try something like the following demo
Your most likely using moveTo
and lineTo
to create the paths, if you do it that way the properties will be shared for the path until you close the path. So everytime you change the thickness youd need to call closePath
and then beginPath
again.
In my example I use Bresenham's line algorithm to plot the points. Basically onmousedown it starts painting. Then onmousemove it compares the current coordinates with the last coordinates and plots all of the points between. Its also using fillRect
to paint. Based on how fast your moving the line will be thicker or thinner.
Heres the code for the drawing function
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d"),
painting = false,
lastX = 0,
lastY = 0,
lineThickness = 1;
canvas.width = canvas.height = 600;
ctx.fillRect(0, 0, 600, 600);
canvas.onmousedown = function(e) {
painting = true;
ctx.fillStyle = "#ffffff";
lastX = e.pageX - this.offsetLeft;
lastY = e.pageY - this.offsetTop;
};
canvas.onmouseup = function(e){
painting = false;
}
canvas.onmousemove = function(e) {
if (painting) {
mouseX = e.pageX - this.offsetLeft;
mouseY = e.pageY - this.offsetTop;
// find all points between
var x1 = mouseX,
x2 = lastX,
y1 = mouseY,
y2 = lastY;
var steep = (Math.abs(y2 - y1) > Math.abs(x2 - x1));
if (steep){
var x = x1;
x1 = y1;
y1 = x;
var y = y2;
y2 = x2;
x2 = y;
}
if (x1 > x2) {
var x = x1;
x1 = x2;
x2 = x;
var y = y1;
y1 = y2;
y2 = y;
}
var dx = x2 - x1,
dy = Math.abs(y2 - y1),
error = 0,
de = dy / dx,
yStep = -1,
y = y1;
if (y1 < y2) {
yStep = 1;
}
lineThickness = 5 - Math.sqrt((x2 - x1) *(x2-x1) + (y2 - y1) * (y2-y1))/10;
if(lineThickness < 1){
lineThickness = 1;
}
for (var x = x1; x < x2; x++) {
if (steep) {
ctx.fillRect(y, x, lineThickness , lineThickness );
} else {
ctx.fillRect(x, y, lineThickness , lineThickness );
}
error += de;
if (error >= 0.5) {
y += yStep;
error -= 1.0;
}
}
lastX = mouseX;
lastY = mouseY;
}
}
jazzytomato
Programmers know the benefits of everything and the tradeoffs of nothing
Updated on June 21, 2022Comments
-
jazzytomato almost 2 years
First I want to say that I made a lot of research and tries myself without any success.
I am working on a MSPaint-like application using Canvas, and I would like to create a pencil tool which looks realistic like handmade drawings... Here is an example in the link below with the default tool : http://www.onemotion.com/flash/sketch-paint/
I tried to play with mousespeed and linewidth properties but it is not working well (the entire line enlarge and shrink as I move the mouse). I have no idea of an algorithm acting on pixel raw data.
Do you know something existing or a suitable algorithm to apply ? Thank you very much for your help
EDIT
I decided to add the solution I've chosen because it seems to interest lot of people. So, the best thing I found so far is to draw an image onto the canvas, using the technique explained here : http://css.dzone.com/articles/sketching-html5-canvas-and. It works like a charm, the result is really convincing and this is quite easy to implement. Try it out here : http://tricedesigns.com/portfolio/sketch/brush.html#
-
Beginner over 10 years@Loktar i have tried to implement same thing using jquery mobile. I am able to obtain touchevents, but unable to draw the line. can u please help in it? thanks:)
-
Melvin Roest over 4 yearsI had a hard time figuring out how this works. I realized that it's quite easy to see. Selectively toggle out:
if (steep){
,if (x1 > x2) {
and also doelse if (x1 > x2) {
(for experimentation) and also toggleif (y1 < y2) { yStep = 1; }
and you'll see visually what the algorithm is doing. -
Tom Parke over 3 yearsI'd like to let you know that you've created one of the best feeling pencil tools on the internet (much better than a lot of sites that have drawing tools).
-
Loktar over 3 yearsWow @TomParke I really appreciate that! Maybe I'll wrap it into a component or something and throw it on Github.