How do I hand draw on canvas with JavaScript? - javascript

Question
How do I draw free (using my mouse / fingers) on a canvas element like you can do it in paint with a pencil?
About this question
There are a lot of questions that want to achieve free hand drawing on canvas:
draw by mouse with HTML5 Canvas
KineticJS - Draw free with mouse
Free drawing on canvas using fabric.js
Sketching with JS
Paint canvas not working properly
Mouse position on canvas painting
Implementing smooth sketching and drawing on the element
So I thought it would be a good idea to make a reference question, where every answer is community wiki and contains a explanation for exactly one JavaScript library / pure JavaScript how to do paint on canvas.
Structure of answers
The answers should be community wiki and use the following template:
## [Name of library](Link to project page)
### Simple example
A basic, complete example. That means it has to contain HTML
and JavaScript. You can start with this:
<!DOCTYPE html>
<html>
<head>
<title>Simple example</title>
<script type='text/javascript' src='http://cdnjs.com/[your library]'></script>
<style type='text/css'>
#sheet {
border:1px solid black;
}
</style>
<script type='text/javascript'>
window.onload=function(){
// TODO: Adjust
}
</script>
</head>
<body>
<canvas id="sheet" width="400" height="400"></canvas>
</body>
</html>
If possible, this example should work with both, mouse and touch events.
[JSFiddle](Link to code on jsfiddle.net)
This solution works with:
<!-- Please test it the following way: Write "Hello World"
Problems that you test this way are:
* Does it work at all?
* Are lines separated?
* Does it get slow when you write too much?
-->
* Desktop computers:
* [Browser + Version list]
* Touch devices:
* [Browser + Version list] on [Device name]
### Import / Export
Some explanations how to import / export user drawn images.
### Line smoothing
Explanations about how to manipulate the line the user draws.
This can include:
* Bézier curves
* Controlling thickness of lines

Fabric.js
<!DOCTYPE html>
<html>
<head>
<title>Simple example</title>
<script type='text/javascript' src='http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js'></script>
<style type='text/css'>
#sheet {
border:1px solid black;
}
</style>
<script type='text/javascript'>
window.onload=function(){
var canvas = new fabric.Canvas('sheet');
canvas.isDrawingMode = true;
canvas.freeDrawingBrush.width = 5;
canvas.freeDrawingBrush.color = "#ff0000";
}
</script>
</head>
<body>
<canvas id="sheet" width="400" height="400"></canvas>
</body>
</html>
JSFiddle - Demo
The width of the lines can be controlled with canvas.freeDrawingBrush.width.
The color of the lines can be controlled with canvas.freeDrawingBrush.color.
This solution works with:
Desktop computers:
Chrome 33
Firefox 28
Touch devices:
Chrome 34 on Nexus 4
Opera 20 on Nexus 4
Firefox 28 on Nexus 4
Import / Export
Is only possible by serializing the complete canvas, see Tutorial
Line smoothing
Is done automatically and it seems not to be possible to deactivate it.

Plain JavaScript
Simple example
<!DOCTYPE html>
<html>
<head>
<title>Simple example</title>
<style type='text/css'>
#sheet {
border:1px solid black;
}
</style>
</head>
<body>
<canvas id="sheet" width="400" height="400"></canvas>
<script type='text/javascript'>
/*jslint browser:true */
"use strict";
var context = document.getElementById('sheet').getContext("2d");
var canvas = document.getElementById('sheet');
context = canvas.getContext("2d");
context.strokeStyle = "#ff0000";
context.lineJoin = "round";
context.lineWidth = 5;
var clickX = [];
var clickY = [];
var clickDrag = [];
var paint;
/**
* Add information where the user clicked at.
* #param {number} x
* #param {number} y
* #return {boolean} dragging
*/
function addClick(x, y, dragging) {
clickX.push(x);
clickY.push(y);
clickDrag.push(dragging);
}
/**
* Redraw the complete canvas.
*/
function redraw() {
// Clears the canvas
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
for (var i = 0; i < clickX.length; i += 1) {
if (!clickDrag[i] && i == 0) {
context.beginPath();
context.moveTo(clickX[i], clickY[i]);
context.stroke();
} else if (!clickDrag[i] && i > 0) {
context.closePath();
context.beginPath();
context.moveTo(clickX[i], clickY[i]);
context.stroke();
} else {
context.lineTo(clickX[i], clickY[i]);
context.stroke();
}
}
}
/**
* Draw the newly added point.
* #return {void}
*/
function drawNew() {
var i = clickX.length - 1
if (!clickDrag[i]) {
if (clickX.length == 0) {
context.beginPath();
context.moveTo(clickX[i], clickY[i]);
context.stroke();
} else {
context.closePath();
context.beginPath();
context.moveTo(clickX[i], clickY[i]);
context.stroke();
}
} else {
context.lineTo(clickX[i], clickY[i]);
context.stroke();
}
}
function mouseDownEventHandler(e) {
paint = true;
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
if (paint) {
addClick(x, y, false);
drawNew();
}
}
function touchstartEventHandler(e) {
paint = true;
if (paint) {
addClick(e.touches[0].pageX - canvas.offsetLeft, e.touches[0].pageY - canvas.offsetTop, false);
drawNew();
}
}
function mouseUpEventHandler(e) {
context.closePath();
paint = false;
}
function mouseMoveEventHandler(e) {
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
if (paint) {
addClick(x, y, true);
drawNew();
}
}
function touchMoveEventHandler(e) {
if (paint) {
addClick(e.touches[0].pageX - canvas.offsetLeft, e.touches[0].pageY - canvas.offsetTop, true);
drawNew();
}
}
function setUpHandler(isMouseandNotTouch, detectEvent) {
removeRaceHandlers();
if (isMouseandNotTouch) {
canvas.addEventListener('mouseup', mouseUpEventHandler);
canvas.addEventListener('mousemove', mouseMoveEventHandler);
canvas.addEventListener('mousedown', mouseDownEventHandler);
mouseDownEventHandler(detectEvent);
} else {
canvas.addEventListener('touchstart', touchstartEventHandler);
canvas.addEventListener('touchmove', touchMoveEventHandler);
canvas.addEventListener('touchend', mouseUpEventHandler);
touchstartEventHandler(detectEvent);
}
}
function mouseWins(e) {
setUpHandler(true, e);
}
function touchWins(e) {
setUpHandler(false, e);
}
function removeRaceHandlers() {
canvas.removeEventListener('mousedown', mouseWins);
canvas.removeEventListener('touchstart', touchWins);
}
canvas.addEventListener('mousedown', mouseWins);
canvas.addEventListener('touchstart', touchWins);
</script>
</body>
</html>
JSFiddle
The width of the lines can be controlled with context.lineWidth.
The color of the lines can be controlled with strokeStyle.
This solution works with:
Desktop computers:
Chrome 33
Firefox 28
Touch devices:
Firefox 28 on Nexus 4
It does not work with
Touch devices:
Chrome 34 / Opera 20 on Nexus 4 (see issue)
Import / Export
Importing and exporting the image can be done by importing / exporting clickX, clickY and clickDrag.
Line smoothing
Can eventually be done by replacing lineTo() with bezierCurveTo()

Plain JS - ES6
Simple example
Plain Javascript example above has some serious issues: it does not reflect the comments objections, the paint state is redundant, events are not unhooked properly, the redraw() function is not used, it can be simplified a lot and it doesn't work with modern syntax. The fix is here:
var canvas = document.getElementById('sheet'), g = canvas.getContext("2d");
g.strokeStyle = "hsl(208, 100%, 43%)";
g.lineJoin = "round";
g.lineWidth = 1;
g.filter = "blur(1px)";
const
relPos = pt => [pt.pageX - canvas.offsetLeft, pt.pageY - canvas.offsetTop],
drawStart = pt => { with(g) { beginPath(); moveTo.apply(g, pt); stroke(); }},
drawMove = pt => { with(g) { lineTo.apply(g, pt); stroke(); }},
pointerDown = e => drawStart(relPos(e.touches ? e.touches[0] : e)),
pointerMove = e => drawMove(relPos(e.touches ? e.touches[0] : e)),
draw = (method, move, stop) => e => {
if(method=="add") pointerDown(e);
canvas[method+"EventListener"](move, pointerMove);
canvas[method+"EventListener"](stop, g.closePath);
};
canvas.addEventListener("mousedown", draw("add","mousemove","mouseup"));
canvas.addEventListener("touchstart", draw("add","touchmove","touchend"));
canvas.addEventListener("mouseup", draw("remove","mousemove","mouseup"));
canvas.addEventListener("touchend", draw("remove","touchmove","touchend"));
<canvas id="sheet" width="400" height="400" style="border: 1px solid black"></canvas>
Support
It should work everywhere today. I could be further simplified by pointer events, but Safari lacks support for it as of 2021.
Import / Export
For import, use g.drawImage()
g.drawImage(img, 0, 0);
For export, see canvas.toBlob()
function save(blob) {
var fd = new FormData();
fd.append("myFile", blob);
// handle formData to your desire here
}
canvas.toBlob(save,'image/jpeg');
Line smoothing
For antialiasing, See blur() from SVG filters; if you import, don't forget to apply it AFTER the image is imported
context.filter = "blur(1px)";

Paper.js
Simple example
<!DOCTYPE html>
<html>
<head>
<title>Paper.js example</title>
<script type='text/javascript' src='http://paperjs.org/assets/js/paper.js'></script>
<style type='text/css'>
#sheet {
border:1px solid black;
}
</style>
</head>
<body>
<script type="text/paperscript" canvas="sheet">
var path;
function onMouseDown(event) {
// If we produced a path before, deselect it:
if (path) {
path.selected = false;
}
// Create a new path and set its stroke color to black:
path = new Path({
segments: [event.point],
strokeColor: 'black',
strokeWidth: 3
});
}
// While the user drags the mouse, points are added to the path
// at the position of the mouse:
function onMouseDrag(event) {
path.add(event.point);
}
// When the mouse is released, we simplify the path:
function onMouseUp(event) {
path.simplify();
}
</script>
<canvas id="sheet" width="400" height="400"></canvas>
</body>
</html>
JSFiddle
The width of the lines can be controlled with strokeWidth.
The color of the lines can be controlled with strokeColor.
This solution works with:
Desktop computers:
Chrome 33
Import / Export
?
Line smoothing
Line smoothing can be done by adjusting path.simplify();.

EaselJs
Simple example
A basic, complete example. That means it has to contain HTML
and JavaScript. You can start with this:
<!DOCTYPE html>
<html>
<head>
<title>EaselJS example</title>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/EaselJS/0.7.1/easeljs.min.js"></script>
<script>
var canvas, stage;
var drawingCanvas;
var oldPt;
var oldMidPt;
var color;
var stroke;
var index;
function init() {
if (window.top != window) {
document.getElementById("header").style.display = "none";
}
canvas = document.getElementById("sheet");
index = 0;
//check to see if we are running in a browser with touch support
stage = new createjs.Stage(canvas);
stage.autoClear = false;
stage.enableDOMEvents(true);
createjs.Touch.enable(stage);
createjs.Ticker.setFPS(24);
drawingCanvas = new createjs.Shape();
stage.addEventListener("stagemousedown", handleMouseDown);
stage.addEventListener("stagemouseup", handleMouseUp);
stage.addChild(drawingCanvas);
stage.update();
}
function stop() {}
function handleMouseDown(event) {
color = "#ff0000";
stroke = 5;
oldPt = new createjs.Point(stage.mouseX, stage.mouseY);
oldMidPt = oldPt;
stage.addEventListener("stagemousemove" , handleMouseMove);
}
function handleMouseMove(event) {
var midPt = new createjs.Point(oldPt.x + stage.mouseX>>1, oldPt.y+stage.mouseY>>1);
drawingCanvas.graphics.clear().setStrokeStyle(stroke, 'round', 'round').beginStroke(color).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y, oldMidPt.x, oldMidPt.y);
oldPt.x = stage.mouseX;
oldPt.y = stage.mouseY;
oldMidPt.x = midPt.x;
oldMidPt.y = midPt.y;
stage.update();
}
function handleMouseUp(event) {
stage.removeEventListener("stagemousemove" , handleMouseMove);
}
</script>
</head>
<body onload="init();">
<canvas id="sheet" width="400" height="400"></canvas>
</body>
</html>
Demo
The interesting parts in the documentation are:
EaselJS: A starting point for getting into EaselJS.
Stage Class:
This solution works with:
Desktop computers:
Chrome 33
Firefox 28
Touch devices:
Chrome 34 / Firefox 28 / Opera 20 on Nexus 4
Import / Export
?
Line smoothing
?

Here, try my canvas free drawing and erase.
https://jsfiddle.net/richardcwc/d2gxjdva/
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
var tooltype = 'draw';
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = mousex = parseInt(e.clientX-canvasx);
last_mousey = mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.beginPath();
if(tooltype=='draw') {
ctx.globalCompositeOperation = 'source-over';
ctx.strokeStyle = 'black';
ctx.lineWidth = 3;
} else {
ctx.globalCompositeOperation = 'destination-out';
ctx.lineWidth = 10;
}
ctx.moveTo(last_mousex,last_mousey);
ctx.lineTo(mousex,mousey);
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
}
last_mousex = mousex;
last_mousey = mousey;
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
//Use draw|erase
use_tool = function(tool) {
tooltype = tool; //update
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<canvas id="canvas" width="800" height="500"></canvas>
<input type="button" value="draw" onclick="use_tool('draw');" />
<input type="button" value="erase" onclick="use_tool('erase');" />
<div id="output"></div>

(Disclaimer: I wrote this library)
Scrawl.js
Simple example
<!DOCTYPE html>
<html>
<head>
<title>Simple example</title>
<style type='text/css'>
#sheet {border:1px solid black;}
</style>
</head>
<body>
<canvas id="sheet" width="400" height="400"></canvas>
<script src="http://scrawl.rikweb.org.uk/js/scrawlCore-min.js"></script>
<script>
var mycode = function(){
//define variables
var myPad = scrawl.pad.sheet,
myCanvas = scrawl.canvas.sheet,
sX, sY, here,
drawing = false,
currentSprite = false,
startDrawing,
endDrawing;
//event listeners
startDrawing = function(e){
drawing = true;
currentSprite = scrawl.newShape({
start: here,
lineCap: 'round',
lineJoin: 'round',
method: 'draw',
lineWidth: 4,
strokeStyle: 'red',
data: 'l0,0 ',
});
sX = here.x;
sY = here.y;
if(e){
e.stopPropagation();
e.preventDefault();
}
};
myCanvas.addEventListener('mousedown', startDrawing, false);
endDrawing = function(e){
if(currentSprite){
currentSprite = false;
}
drawing = false;
if(e){
e.stopPropagation();
e.preventDefault();
}
};
myCanvas.addEventListener('mouseup', endDrawing, false);
//animation object
scrawl.newAnimation({
fn: function(){
//get current mouse position
here = myPad.getMouse();
if(here.active){
if(drawing){
if(here.x !== sX || here.y !== sY){
//extend the line
currentSprite.set({
data: currentSprite.data+' '+(here.x - sX)+','+(here.y - sY),
});
sX = here.x;
sY = here.y;
}
}
}
else{
//stop drawing if mouse leaves canvas area
if(currentSprite){
endDrawing();
}
}
//update display
scrawl.render();
},
});
};
//Scrawl is modular - load additional modules
scrawl.loadModules({
path: 'js/',
modules: ['animation', 'shape'],
callback: function(){
window.addEventListener('load', function(){
scrawl.init(); //start Scrawl
mycode(); //run code
}, false);
},
});
</script>
</body>
</html>
JSFiddle
This solution works with:
recent versions of IE, Chrome, Firefox, Opera (desktop)
(not tested on mobile/touch devices)
Adding touch support
(try adding a dedicated touch library like Hammer.js?)
Import / Export
Scrawl has experimental support for saving and loading JSON strings
tutorial page: load and save
Line smoothing and other sprite manipulations
line data is saved internally as an SVGTiny Path.d value - any algorithm that can take line data in that format and smooth it should work
line attributes - thickness, color, positioning, rotation, etc - can be set, and animated.

Related

Canvas disappearing on event listener

I am trying to create a rect that moves on keypress for a pong game and when I press the key the left rect disappears..
Any ideas how to fix the problem? It is really important..
The code is written in vanilla javascript so please don't write jQuery..
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pong</title>
<script type="text/javascript">
var x = 100;
var y = 100;
var xmoveFirst = 720;
var ymoveFirst = 0;
var xmoveSecond = 30 ;
var ymoveSecond = 0;
function canvas() {
var can = document.getElementById('theCanvas');
can.style.backgroundColor = "black";
var ctx = can.getContext('2d');
//first player
ctx.fillStyle="white";
ctx.fillRect(xmoveFirst,ymoveFirst,5,75);
//second player
ctx.fillStyle = 'white';
ctx.fillRect(xmoveSecond,ymoveSecond,5,75);
//first player move
function moveFirst(eFirst) {
ctx.clearRect(0,0,750,750); //clear rects
if (eFirst.keyCode == 40) {
ymoveFirst+=25;
console.log("first,"+ymoveFirst);
}
else if (eFirst.keyCode == 38) {
ymoveFirst-=25;
console.log("first,"+ymoveFirst);
}
ctx.fillStyle="white";
ctx.fillRect(xmoveFirst,ymoveFirst,5,75);
ctx.fillRect(xmoveSecond,ymoveSecond,5,75);
}
var first = document.onkeydown = moveFirst;
//second player move
function moveSecond(eSecond) {
ctx.clearRect(0,0,750,750);
if (eSecond.keyCode == 83) {
ymoveSecond+=25;
console.log("second,"+ymoveSecond);
}
else if (eSecond.keyCode == 87) {
ymoveSecond-=25;
}
ctx.fillStyle="white";
ctx.fillRect(xmoveFirst,ymoveFirst,5,75);
ctx.fillRect(xmoveSecond,ymoveSecond,5,75);
console.log("second,"+ymoveSecond)
}
var second = document.onkeydown = moveSecond;
}
83,87
</script>
</head>
<body onload="canvas()">
<canvas id="theCanvas" width="750" height="750"></canvas>
</body>
</html>
This line: can.width=can.width; resets the canvas width.
When you change the canvas size (width or height), you clear the canvas (making everything black). After this line, you are only redrawing the rightmost paddle, so the left one remains missing.
You'll need to redraw the leftmost paddle as well if you want it to come back. Here is the modified moveRight() function:
function moveRight(eFirst) {
if (eFirst.keyCode==40) {
ymoveFirst+=25;
console.log(ymoveFirst);
}
else if (eFirst.keyCode==38) {
ymoveFirst-=25;
console.log(ymoveFirst);
}
can.width=can.width;
ctx.fillStyle="white";
// Redraw BOTH paddles
ctx.fillRect(xmoveFirst,ymoveFirst,5,75);
ctx.fillRect(xmoveSecond,ymoveSecond,5,75);
}
Also, replace
document.onkeydown = moveFirst; and document.onkeydown = moveSecond;
with
document.addEventListener("keydown", moveFirst);, and document.addEventListener("keydown", moveSecond);
Currently, you are overwritting the first listener with document.onkeydown = moveSecond;. By using addEventListener, you don't overwrite the ones that already exist.

Moving image in a circular path purely using JavaScript

How can I make the imageObject to move in a circular path? Or more specific, what are the mathematical formulas needed to make it do so?
I am required to use setInterval with a function that caluclates the new coordinates of the picture. setInterval is supposed to call the function at least 20 times a second.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Graphics and animation using HTML5 Canvas</title>
<style>
#the-canvas { border: 1px dashed gray }
</style>
<script>
addEventListener('load', function() {
var x = document.getElementById("the-canvas");
var y = x.getContext("2d");
var imageObject = new Image();
imageObject.onload = function() {
y.drawImage(imageObject, 100, 200);
};
imageObject.src = "image.jpg";
});
</script>
</head>
<body>
<canvas id="the-canvas" width="500" height="400">
Your browser does not support the <canvas> element.
</canvas>
</body>
</html>
Mathematical formulas needed would be cosine in one dimension and sine in the other.
Something like this:
addEventListener('load', function() {
var x = document.getElementById("the-canvas");
var y = x.getContext("2d");
var imageObject = new Image();
var step = 0, radius = 50, speed = 0.05;
function spin() {
y.clearRect(0, 0, x.width, x.height);
y.drawImage(imageObject, 100 + radius * Math.cos(speed * step), 200 + radius * Math.sin(speed * step));
++step;
}
imageObject.onload = function() {
y.drawImage(imageObject, 100, 200);
setInterval(spin, 50); // 20 fps
};
imageObject.src = "image.jpg";
});

Drawing and saving an image as JPEG in HTML Canvas

I am creating an app which allows user to draw a digit(using mouse) in Canvas. When they click on submit, the image should be saved as a JPEG and Clear should Erase the digit drawn in canvas. I am new to HTML5 Canvas. I saw some tutorials which created a canvas, but I am unable to save and clear canvas. Any help would really be appreciated. Thanks.
Here is my HTML:
<div style="padding-bottom: 20px;padding-left: 210px;">
<div class="btn-group" role="group" aria-label="...">
<button type="button" id="save" class="btn btn-default">Submit</button>
<button type="button" id="clear" class="btn btn-default">Clear</button>
</div></div>
</div>
Javascript within Script tag:
var clear = document.getElementById('clear');
clear.addEventListener('click', clearCanvas);
var clearCanvas = function(e) {
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 500, 400);
ctx.clearRect(20, 20, 100, 50);
}
The tutorial you're using fails to mention a few key things:
The canvasInAPerfectWorldline isn't used: you can delete it.
You need jQuery: just add <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script/> in your <head> section.
You should wrap your javascript in the jQuery boilerplate, to ensure it gets executed after the rest to the document has loaded: $( document ).ready(function() { <your javascript here> });
The canvasWidth and canvasHeight variables are never set: add this line before the variables are used:var canvasWidth = 600; var cavasHeight = 400;
The variables mouseX and mouseY are never used: you can delete them (but take a look at the onClick() function two lines later to see what they would have been used for).
The finished result should look like this:
<!DOCTYPE html>
<html>
<head>
<title>HTML5 Create HTML5 Canvas JavaScript Drawing App Example</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script>
<style>canvas { border: 1px solid #ccc; }</style>
<script type="text/javascript">
$( document ).ready(function() {
var canvasWidth = 600; var cavasHeight = 400;
var canvasDiv = document.getElementById('canvasDiv');
canvas = document.createElement('canvas');
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', cavasHeight);
canvas.setAttribute('id', 'canvas');
canvasDiv.appendChild(canvas);
if(typeof G_vmlCanvasManager != 'undefined') {
canvas = G_vmlCanvasManager.initElement(canvas);
}
context = canvas.getContext("2d");
$('#canvas').mousedown(function(e){
paint = true;
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
redraw();
});
$('#canvas').mousemove(function(e){
if(paint){
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
redraw();
}
});
$('#canvas').mouseup(function(e){
paint = false;
});
$('#canvas').mouseleave(function(e){
paint = false;
});
$('#clear').click(function(){
clickX.length = 0;
clickY.length = 0;
clickDrag.length = 0;
redraw();
});
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
function addClick(x, y, dragging)
{
clickX.push(x);
clickY.push(y);
clickDrag.push(dragging);
}
function redraw(){
context.clearRect(0, 0, context.canvas.width, context.canvas.height); // Clears the canvas
context.strokeStyle = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
for(var i=0; i < clickX.length; i++) {
context.beginPath();
if(clickDrag[i] && i){
context.moveTo(clickX[i-1], clickY[i-1]);
}else{
context.moveTo(clickX[i]-1, clickY[i]);
}
context.lineTo(clickX[i], clickY[i]);
context.closePath();
context.stroke();
}
}
});
</script>
</head>
<body>
<div id="canvasDiv"></div>
</body>
</html>
As for saving your canvas as a JPEG, that's more complicated. As markE has pointed out, there's a related question here which shows one way to do it.
EDIT: Adding a 'Clear' button:
Your 'drawing' is really just a series of pen movements stored in the clickX, clickY and clickDrag arrays. Each time redraw() is called, the drawing gets recreated from the arrays. So just drawing a white rectangle will only clear the screen until the next redraw(). Instead, you can clear the arrays by adding this to your javascript:
$('#clear').click(function(){
clickX.length = 0;
clickY.length = 0;
clickDrag.length = 0;
redraw();
});
(BTW by deleting the details of your original question, you make it hard for the next person to understand the context of the answers. You should either (a) add to your original question, or (b) ask a new question. Also you can upvote and/or accept any answers you find helpful. Thanks)
I think that's a duplicated question. See here
Can I get image from canvas element and use it in img src tag?
var image = new Image();
image.id = "pic"
image.src = canvas.toDataURL();
document.getElementById('image_for_crop').appendChild(image);

Javascript canvas animating

I want to make a loading bar for my web application and I want to use a html canvas for this. This is the script that I use to fill up the canvas:
<script>
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
var xPos = 0;
draw = function() {
if(xPos < 300){
c.rect(0, 0, xPos, 30);
c.fill(255,0,0);
xPos += 0.5;
}
};
</script>
I tested this code on a online code converter (khan academy) and it worked (of course without the first 2 lines and c. in front of most things), and that is also my trouble I don't know where I have to put c. in front of?
I simplified the page a little bit:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css">
</head>
<body>
<canvas id="bar"></canvas>
<script>
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
c.fillStyle = "#ff0000"
draw = function(){
if(xPos < 300){
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
}
};
</script>
</body>
</html>
Whatever you are trying to draw... this:
draw = function(){
if(xPos < 300) {
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
}
};
... it is a definition of variable in global context (context of window object), then assigning a function to it. That's all - it only defines the behavior.
What you need also needs to execute that (a sidenote: to execute it after the canvas is actually created - when you put code in a script tag after canvas tag - it's sufficient and you did it already).
To execute the function use:
draw();
Or don't wrap code in function at all (unless it's to be called multiple times).
Or use a syntax construct to execute the function created in place like this:
(draw = function(){
if(xPos < 300) {
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
setTimeout(draw,15); // use this to achieve animation effect
}
})();
var xPos = 0;
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
c.fillStyle = "#FF0000";
var draw;
(draw = function(){
if(xPos < 300) {
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
setTimeout(draw,15);
}
})();
#bar {
width: 300px;
height: 50px;
}
<canvas id="bar"></canvas>
Edit: I've been thinking of what you might need, as it's not entirely abvious what you want. I have created this jsfiddle. Maybe it'll be of any help.
Hmmm...
You got some things mixed up. Try this:
<html>
<canvas id = "cvs1" width = "300" height = "30"></canvas>
</html>
And for the script:
var c = document.getElementById("cvs1").getContext("2d");
c.fillStyle = "#ff0000" //Set Fill Color(Set to red)
if(xPos < 300){
c.fillRect(xPos, 0, 30, 30);
xPos += 0.5;
}
If not:
What you did was use fill and rect seperately. You need to set the color, and then use the fillRect() function to draw the rectangle.
EDIT: You got the x,y,width,height as width,height,x,y. Fixed answer.
Good luck!
You need to call draw for every animation step. You could do this using setTimeout, setInterval or requestAnimationFrame :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="test.css">
</head>
<body>
<canvas id="bar"></canvas>
<script>
var canvas = document.getElementById("bar");
var c = canvas.getContext("2d");
c.fillStyle = "#ff0000";
xPos=0;
draw = function(){
if(xPos < 300){
c.fillRect(0, 0, xPos, 30);
xPos += 0.5;
requestAnimationFrame(draw);
}
};
requestAnimationFrame(draw);
</script>
</body>
</html>

getting mouse position with javascript within canvas

I'm studying jquery and html5 canvas. All I want to do is a simple html5 drawing example. When the mouse move, I draw red squares under my mouse.
My code is simple, but I have a problem getting the mouse cursor position within the canvas.
Right now, I am using x=event.offsetX; to get the mouse position. This works very well in chrome, however when it comes to firefox, it doesn't work. I changed the code to x=event.layerX. but it seems that layerX is the position of my mouse relative to the web page, not the position of the canvas. because I always see an offset.
I have two questions, first, what is the right thing to do to get the correct mouse position under firefox. second, how can i write a code that works for ie, firefox, chrome, safari and opera?
here is my code:
<!doctype html />
<html><head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(
function(){
var flip = document.getElementById('flip');
var context = flip.getContext('2d');
context.fillStyle = "rgb(255,255,255)";
context.fillRect(0, 0, 500, 500);
$("a").click(function(event){alert("Thanks for visiting!");});
$("#flip").mousemove(function(event){
var x, y;
x = event.layerX;
y = event.layerY;
//alert("mouse pos"+event.layerX );
var flip = document.getElementById('flip');
var context = flip.getContext('2d');
context.fillStyle = "rgb(255,0,0)";
context.fillRect(x, y, 5, 5);
}
);
}
);
</script>
</head> <body bgcolor="#000000"> jQuery<canvas id="flip" width="500" height="500">
This text is displayed if your browser does not support HTML5 Canvas.</canvas> </body></html>
I see plenty of question on this subject and all propose to browse DOM or use offsetX and offsetY, which are not always set right.
You should use the function: canvas.getBoundingClientRect() from the canvas API.
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
console.log('Mouse position: ' + mousePos.x + ',' + mousePos.y);
}, false);
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<script>
Element.prototype.leftTopScreen = function () {
var x = this.offsetLeft;
var y = this.offsetTop;
var element = this.offsetParent;
while (element !== null) {
x = parseInt (x) + parseInt (element.offsetLeft);
y = parseInt (y) + parseInt (element.offsetTop);
element = element.offsetParent;
}
return new Array (x, y);
}
document.addEventListener ("DOMContentLoaded", function () {
var flip = document.getElementById ("flip");
var xy = flip.leftTopScreen ();
var context = flip.getContext ("2d");
context.fillStyle = "rgb(255,255,255)";
context.fillRect (0, 0, 500, 500);
flip.addEventListener ("mousemove", function (event) {
var x = event.clientX;
var y = event.clientY;
context.fillStyle = "rgb(255, 0, 0)";
context.fillRect (x - xy[0], y - xy[1], 5, 5);
});
});
</script>
<style>
#flip {
border: 1px solid black;
display: inline-block;
}
body {
text-align: center;
}
</style>
</head>
<body>
<canvas id = "flip" width = "500" height = "500">This text is displayed if your browser does not support HTML5 Canvas.</canvas>
</body>
</html>
You don't have to worry about compatibility, only IE (prior 9) does not support canvas natively.
You will need a custom function to work out where the element is and then work out where the mouse is within that element. Here is an example. It uses this function from quirks mode and my JavaScript library which should not be difficult to translate into jQuery.
function findPos(obj) {
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return [curleft, curtop];
}
}
EDIT
This will not work in IE due to it not supporting pageX. You will have to pass the event object through a function like this to correct that. But as 2x2p1p said, canvas is not supported by any Internet Explorer below version 9.

Categories

Resources