How i can create realistic simple pencil tool, not like in a ms windows paint program. I need result like this:
if i try solid without transparent i get like in a ms windows paint programs not realistic pencil, if i try add opacity i see circles this is too not realistic:
How i can get pencil tool like in first picture? my trying example:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var previousMouseX = null;
var previousMouse = null;
var isDrawing = false;
var lineWidth = 10;
var brush = 1;
var myColor = "#FF0000";
function getMousePosition(canvas, evt) {
var rect = canvas.getBoundingClientRect();
if (evt.clientX !== undefined && evt.clientY !== undefined) {
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
}
/* BUTTONS */
$("#btn1").on("click", function() {
ctx.globalAlpha = "0.2";
});
$("#btn2").on("click", function() {
ctx.globalAlpha = "1";
});
$("#change-color").on("click", function() {
ctx.strokeStyle = "#009933";
});
$("#canvas").on("mousedown", function(e) {
isDrawing = true;
var pos = getMousePosition(canvas, e);
move(pos.x, pos.y);
});
$("#canvas").on("mousemove", function(e) {
if(isDrawing) {
var pos = getMousePosition(canvas, e);
stroke(pos.x, pos.y);
}
});
$("#canvas").on("mouseup", function() {
isDrawing = false;
});
function stroke(mouseX, mouseY) {
ctx.globalCompositeOperation = "source-over";
ctx.lineJoin = ctx.lineCap = "round";
ctx.lineWidth = 10;
ctx.beginPath();
ctx.moveTo(previousMouseX, previousMouseY);
ctx.lineTo(mouseX, mouseY);
ctx.closePath();
ctx.stroke();
move(mouseX, mouseY);
}
function move(mouseX, mouseY) {
previousMouseX = mouseX;
previousMouseY = mouseY;
}
canvas {
border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="button" id="btn1" value="Transparent">
<input type="button" id="btn2" value="Solid">
<input type="button" id="change-color" value="Green color"><br />
<canvas id="canvas" width="500" height="500">
Does this go anywhere near doing what you want?
Draw at pencil using transparent, line width 10 and then draw over the line solid using smaller line width (8). Perhaps you could get more variation by randomly varying the second line width between 7, 8 and 9?
EDIT could also randomly set opacity of second line between say 1 and 0.8!
Permanently set opacity on first line and added this code to the function stroke()
ctx.globalAlpha = "1";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(previousMouseX, previousMouseY);
ctx.lineTo(mouseX, mouseY);
ctx.closePath();
ctx.stroke();
Changed code snippet
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var previousMouseX = null;
var previousMouse = null;
var isDrawing = false;
var lineWidth = 10;
var brush = 1;
var myColor = "#FF0000";
function getMousePosition(canvas, evt) {
var rect = canvas.getBoundingClientRect();
if (evt.clientX !== undefined && evt.clientY !== undefined) {
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
}
/* BUTTONS */
$("#btn1").on("click", function() {
ctx.globalAlpha = "0.2";
});
$("#btn2").on("click", function() {
ctx.globalAlpha = "1";
});
$("#change-color").on("click", function() {
ctx.strokeStyle = "#009933";
});
$("#canvas").on("mousedown", function(e) {
isDrawing = true;
var pos = getMousePosition(canvas, e);
move(pos.x, pos.y);
});
$("#canvas").on("mousemove", function(e) {
if(isDrawing) {
var pos = getMousePosition(canvas, e);
stroke(pos.x, pos.y);
}
});
$("#canvas").on("mouseup", function() {
isDrawing = false;
});
function stroke(mouseX, mouseY) {
ctx.globalCompositeOperation = "source-over";
ctx.lineJoin = ctx.lineCap = "round";
ctx.lineWidth = 10;
ctx.globalAlpha = "0.2"; //NOTE ALWAYS SET TO 'TRANSPARENT' needs variable if you want to switch to solid.
ctx.beginPath();
ctx.moveTo(previousMouseX, previousMouseY);
ctx.lineTo(mouseX, mouseY);
ctx.closePath();
ctx.stroke();
ctx.globalAlpha = "1";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(previousMouseX, previousMouseY);
ctx.lineTo(mouseX, mouseY);
ctx.closePath();
ctx.stroke();
move(mouseX, mouseY);
}
function move(mouseX, mouseY) {
previousMouseX = mouseX;
previousMouseY = mouseY;
}
canvas {
border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input type="button" id="btn1" value="Transparent">
<input type="button" id="btn2" value="Solid">
<input type="button" id="change-color" value="Green color"><br />
<canvas id="canvas" width="500" height="500">
Here's a pencil effect.
It's adapted from this nice chalk effect done by Mohamed Moustafa: http://codepen.io/mmoustafa/pen/gmEdk
Example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw,ch;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var isDown=false;
var startX,startY,mouseX,mouseY;
var xLast = 0;
var yLast = 0;
var brushDiameter=2;
var fill1='rgba(255,255,255,0.5)';
var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/pad.jpg";
function start(){
cw=canvas.width=img.width;
ch=canvas.height=img.height;
ctx.fillStyle = fill1;
ctx.strokeStyle = fill1;
ctx.lineWidth = brushDiameter;
ctx.lineCap = 'round';
ctx.drawImage(img,0,0);
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
getOffset();
xLast=mouseX=parseInt(e.clientX-offsetX);
yLast=mouseY=parseInt(e.clientY-offsetY);
isDown=true;
draw(mouseX+1, mouseY+1);
}
function handleMouseUp(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
isDown=false;
}
function handleMouseOut(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
getOffset();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
draw(mouseX,mouseY);
}
//252,254,171
function draw(x,y){
ctx.strokeStyle = 'rgba(0,0,0,'+(0.4+Math.random()*0.2)+')';
ctx.beginPath();
ctx.moveTo(xLast, yLast);
ctx.lineTo(x, y);
ctx.stroke();
// Chalk Effect
var length = Math.round(Math.sqrt(Math.pow(x-xLast,2)+Math.pow(y-yLast,2))/(5/brushDiameter));
var xUnit = (x-xLast)/length;
var yUnit = (y-yLast)/length;
for(var i=0; i<length; i++ ){
var xCurrent = xLast+(i*xUnit);
var yCurrent = yLast+(i*yUnit);
var xRandom = xCurrent+(Math.random()-0.5)*brushDiameter*1.2;
var yRandom = yCurrent+(Math.random()-0.5)*brushDiameter*1.2;
ctx.clearRect( xRandom, yRandom, Math.random()*2+2, Math.random()+1);
}
xLast = x;
yLast = y;
}
function getOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
body{ background-color:ivory; }
#canvas{border:1px solid red; background:white;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Drag to draw pencil line on the pad</h4>
<canvas id="canvas" width=300 height=300></canvas>
Related
Hello i make like a paint with undo function, i write all coordinates in array and then try undo just redrawing without last coordinates but problem while i redrawing my canvas parameters incorrect. i use lineJoin = "roind" but after redrawing i see without round..
this result with round line begin and line end while i drawing:
this result without round begin and line end after undo function:
I don't have idea where disappear my round lines while i redrawing all drawings coordinate by coordinate..
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var points = [];
var size = 10;
var prevX = 0;
var prevY = 0;
var isCanDraw = false;
$("#canvas").on("mousedown", function(e) {
isCanDraw = true;
prevX = e.clientX;
prevY = e.clientY;
points.push({x: prevX, y: prevY, size: size, mode: "begin"});
});
$("#canvas").on("mousemove", function(e) {
if(isCanDraw) {
stroke(e.clientX, e.clientY);
points.push({x: prevX, y: prevY, size: size, mode: "draw"});
}
});
$("#canvas").on("mouseup", function(e) {
isCanDraw = false;
points.push({x: prevX, y: prevY, size: size, mode: "end"});
});
$("#canvas").on("mouseleave", function(e) {
isCanDraw = false;
});
$("#undo").on("click", function(e) {
deleteLast();
redraw();
});
function deleteLast() {
if(points.length != 0) {
var i = points.length - 1;
while(points[i].mode != "begin") {
i--;
points.pop();
}
points.pop();
}
}
function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if(points.length != 0) {
for(var i=0; i < points.length; i++) {
var pt = points[i];
var begin=false;
if(size != pt.size) {
size = pt.size;
begin=true;
}
if(pt.mode == "begin" || begin) {
ctx.moveTo(pt.x, pt.y)
}
ctx.lineTo(pt.x, pt.y)
if( pt.mode == "end" || (i == points.length-1) ) {
ctx.lineJoin = "round";
ctx.stroke()
}
}
}
}
function stroke(x,y) {
ctx.lineWidth = size;
ctx.lineJoin = "round";
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
prevX = x;
prevY = y;
}
#canvas {
border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="300"></canvas>
<input type="button" id="undo" value="undo">
I think that you're looking for ctx.lineCap property.
+ I modified your redraw function to use a switchinstead of your confusing if statements :
function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.lineCap = "round";
ctx.beginPath();
for(var i=0; i < points.length; i++) {
var pt = points[i];
switch(pt.mode){
case "begin" : ctx.moveTo(pt.x, pt.y);
case "draw" : ctx.lineTo(pt.x, pt.y);
case "end" : ctx.stroke();
}
}
}
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var points = [];
var size = 10;
var prevX = 0;
var prevY = 0;
var isCanDraw = false;
var rect = canvas.getBoundingClientRect();
$("#canvas").on("mousedown", function(e) {
isCanDraw = true;
prevX = e.clientX;
prevY = e.clientY;
points.push({
x: prevX,
y: prevY,
size: size,
mode: "begin"
});
ctx.beginPath();
ctx.arc(prevX, prevY, size/2, 0, Math.PI*2);
ctx.fill();
});
$("#canvas").on("mousemove", function(e) {
if (isCanDraw) {
stroke(e.clientX - rect.left, e.clientY - rect.top);
points.push({
x: prevX,
y: prevY,
size: size,
mode: "draw"
});
}
});
$("#canvas").on("mouseup", function(e) {
isCanDraw = false;
points.push({
x: prevX,
y: prevY,
size: size,
mode: "end"
});
});
$("#canvas").on("mouseleave", function(e) {
isCanDraw = false;
});
$("#undo").on("click", function(e) {
deleteLast();
redraw();
});
function deleteLast() {
if (points.length != 0) {
var i = points.length - 1;
while (points[i].mode != "begin") {
i--;
points.pop();
}
points.pop();
}
}
function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.lineCap = "round";
ctx.beginPath();
for (var i = 0; i < points.length; i++) {
var pt = points[i];
switch (pt.mode) {
case "begin":
ctx.moveTo(pt.x, pt.y);
case "draw":
ctx.lineTo(pt.x, pt.y);
case "end":
ctx.stroke();
}
}
}
function stroke(x, y) {
ctx.lineWidth = size;
ctx.lineJoin = "round";
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
prevX = x;
prevY = y;
}
// debounce our rect update func
var scrolling = false;
function scrollHandler(){
rect = canvas.getBoundingClientRect();
scrolling = false;
}
$(window).on('scroll resize', function(e){
if(!scrolling){
requestAnimationFrame(scrollHandler);
}
});
#canvas {
border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="300"></canvas>
<input type="button" id="undo" value="undo">
#Kaiido answers correctly that applying lineCap='round' will round the ends of your redrawn line.
Two further thoughts:
You should account for your canvas's offset position from the top-left corner of the document. Otherwise your prevX & prevY positions will be slightly off if the canvas is not on the top-left of the document.
You will have a more crisp line (less "bulgy") if you allow only the beginning and ending linecaps to be rounded and all the interim linecaps to be butted. Leave the linejoins as the default of mitered.
Here's example code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var points = [];
var size = 10;
var prevX = 0;
var prevY = 0;
var isCanDraw = false;
$("#canvas").on("mousedown", function(e) {
isCanDraw = true;
prevX = e.clientX-offsetX;
prevY = e.clientY-offsetY;
points.push({x: prevX, y: prevY, size: size, mode: "begin"});
});
$("#canvas").on("mousemove", function(e) {
if(isCanDraw) {
stroke(e.clientX-offsetX, e.clientY-offsetY);
points.push({x: prevX, y: prevY, size: size, mode: "draw"});
}
});
$("#canvas").on("mouseup", function(e) {
isCanDraw = false;
points.push({x: prevX, y: prevY, size: size, mode: "end"});
});
$("#canvas").on("mouseleave", function(e) {
isCanDraw = false;
});
$("#undo").on("click", function(e) {
deleteLast();
redraw();
});
function deleteLast() {
if(points.length != 0) {
var i = points.length - 1;
while(points[i].mode !== "begin") {
i--;
points.pop();
}
points.pop();
}
}
function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var savedFillStyle=ctx.fillStyle;
ctx.fillStyle=ctx.strokeStyle;
var i=0;
while(i<points.length){
var p=points[i];
// draw "begin" as circle instead of line
ctx.beginPath();
ctx.arc(p.x,p.y,p.size/2,0,Math.PI*2);
ctx.closePath();
ctx.fill();
// draw "draw"
ctx.lineWidth=p.size;
ctx.beginPath();
ctx.moveTo(p.x,p.y);
i++;
while(i<points.length && points[i].mode!='end'){
var p=points[i];
ctx.lineTo(p.x,p.y);
i++;
}
ctx.stroke();
// draw "end" as circle instead of line
var p=points[i];
ctx.beginPath();
ctx.arc(p.x,p.y,p.size/2,0,Math.PI*2);
ctx.closePath();
ctx.fill();
i++;
}
ctx.fillStyle=savedFillStyle;
}
function stroke(x,y) {
ctx.lineWidth = size;
ctx.lineJoin = "round";
ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
prevX = x;
prevY = y;
}
body{ background-color: ivory; padding:10px; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="300"></canvas>
<input type="button" id="undo" value="undo"> </body>
My problem then i painting longer than 20seconds begin lagging. i think because it's have a lot of points into array. How i can optimize it? Drawing lines must be smooth like in example, but i have lags :/
var el = document.getElementById('c');
var ctx = el.getContext('2d');
ctx.lineWidth = 10;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.globalAlpha = "0.2";
ctx.strokeStyle = "red";
var isDrawing, points = [ ];
el.onmousedown = function(e) {
isDrawing = true;
points.push({ x: e.clientX, y: e.clientY });
};
el.onmousemove = function(e) {
if (!isDrawing) return;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
points.push({ x: e.clientX, y: e.clientY });
ctx.beginPath();
ctx.moveTo(points[0].x, points[0].y);
for (var i = 1; i < points.length; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
ctx.stroke();
ctx.clearPath();
};
el.onmouseup = function() {
isDrawing = false;
points.length = 0;
};
canvas { border: 1px solid #ccc }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="c" width="500" height="300"></canvas>
I'm trying to create a drawing board with two different colour brushes. You can select the brush you want by clicking on the appropriate button.
Note: This only needs to work on iOS Safari.
The two brushes are:
A Yellow Highlighter
A solid brush colour
The issue I am facing is that selecting a different brush, alters the colour of the existing brush strokes on the canvas.
How can I have each brush not affect the other?
Code:
var el = document.getElementById('c');
var ctx = el.getContext('2d');
var isDrawing;
var _highlight = false;
function marker(){
ctx.lineWidth = 10;
ctx.strokeStyle = 'rgba(0,0,0,1)';
}
function highlight(){
ctx.lineWidth = 15;
ctx.strokeStyle = 'rgba(255,255,0,0.4)';
ctx.globalCompositeOperation = 'destination-atop';
}
document.getElementById("marker").addEventListener("click", function(){
_highlight = false;
});
document.getElementById("clear").addEventListener("click", function(){
ctx.clearRect(0, 0, el.width, el.height);
ctx.restore();
ctx.beginPath();
});
document.getElementById("highlight").addEventListener("click", function(){
_highlight = true;
});
el.onmousedown = function(e) {
isDrawing = true;
if(_highlight){
highlight();
ctx.lineJoin = ctx.lineCap = 'round';
ctx.moveTo(e.clientX, e.clientY);
}else{
marker();
ctx.lineJoin = ctx.lineCap = 'round';
ctx.moveTo(e.clientX, e.clientY);
}
};
el.onmousemove = function(e) {
if (isDrawing) {
if(_highlight){
highlight();
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
}else{
marker();
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
}
}
};
el.onmouseup = function() {
isDrawing = false;
};
canvas#c {
border: 1px solid #ccc;
background:url(http://i.imgur.com/yf6d9SX.jpg);
position: relative;
left: 0;
top: 0;
z-index: 2;
}
<canvas id="c" width="930" height="500"></canvas>
<br>
<button id="marker">Marker</button>
<button id="highlight">Highlight</button>
<button id="clear">Clear</button>
You are accumulating all lines to the same path, so every time you stroke the current stroke color will be used for all of them, including the previous lines.
Try adding beginPath() at your mouse down event as well as in your pen change.
There are several other issues though in this code not addressed here, including:
Composite mode when pen changes
Mouse positions must be corrected to relative position of canvas
(For marker effect you can also use the new blending mode "multiply" instead of "destination-atop", does not work in IE though).
var el = document.getElementById('c');
var ctx = el.getContext('2d');
var isDrawing;
var _highlight = false;
function marker() {
ctx.lineWidth = 10;
ctx.strokeStyle = 'rgba(0,0,0,1)';
ctx.globalCompositeOperation = 'source-over';
}
function highlight() {
ctx.lineWidth = 15;
ctx.strokeStyle = 'rgba(255,255,0,0.4)';
ctx.globalCompositeOperation = "multiply";
if (ctx.globalCompositeOperation !== "multiply") // use multiply if available
ctx.globalCompositeOperation = 'destination-over'; // fallback mode
}
document.getElementById("marker").addEventListener("click", function() {
_highlight = false;
});
document.getElementById("clear").addEventListener("click", function() {
ctx.clearRect(0, 0, el.width, el.height);
ctx.beginPath();
});
document.getElementById("highlight").addEventListener("click", function() {
_highlight = true;
});
el.onmousedown = function(e) {
var pos = getMouse(e);
isDrawing = true;
ctx.beginPath();
_highlight ? highlight() : marker();
ctx.lineJoin = ctx.lineCap = 'round';
ctx.moveTo(pos.x, pos.y);
};
el.onmousemove = function(e) {
if (isDrawing) {
var pos = getMouse(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
}
};
el.onmouseup = function() {
isDrawing = false;
};
function getMouse(e) {
var rect = el.getBoundingClientRect();
return {x: e.clientX - rect.left, y: e.clientY - rect.top}
}
canvas#c {
border: 1px solid #ccc;
background: url(http://i.imgur.com/yf6d9SX.jpg);
position: relative;
left: 0;
top: 0;
z-index: 2;
}
<canvas id="c" width="930" height="500"></canvas>
<br>
<button id="marker">Marker</button>
<button id="highlight">Highlight</button>
<button id="clear">Clear</button>
I need to create a opacity brush clean and smooth.
This is one drawing line example what i need:
Second picture what i get:
While i move cursor faster, i get little less circles in the drawing line
var el = document.getElementById('c');
var ctx = el.getContext('2d');
ctx.lineJoin = "round"
ctx.strokeStyle = "#000000";
ctx.globalAlpha = "0.2";
ctx.lineWidth = 30;
ctx.globalCompositeOperation = "source-over";
var isDrawing, lastPoint;
el.onmousedown = function(e) {
isDrawing = true;
lastPoint = { x: e.clientX, y: e.clientY };
};
el.onmousemove = function(e) {
if (!isDrawing) return;
var currentPoint = { x: e.clientX, y: e.clientY };
ctx.beginPath();
ctx.moveTo(lastPoint.x, lastPoint.y);
ctx.lineTo(currentPoint.x, currentPoint.y);
ctx.closePath();
ctx.stroke();
lastPoint = currentPoint;
};
el.onmouseup = function() {
isDrawing = false;
};
function clearit() {
ctx.clearRect(0,0, 1000, 1000);
}
canvas { border: 1px solid #ccc }
<canvas id="c" width="500" height="300"></canvas>
<input type="button" id="clear-btn" value="Clear it" onclick="clearit()">
Your problem is that in mousemove you are starting and closing lots of paths, so the opacity of the line is overloading.
If you add:
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(250,250);
ctx.lineTo(200,100);
ctx.stroke();
you can see that the effect is removed.
A partial solution (you can't see what you are drawing) is this:
el.onmousedown = function(e) {
isDrawing = true;
lastPoint = { x: e.clientX, y: e.clientY };
ctx.beginPath();
ctx.moveTo(lastPoint.x, lastPoint.y);
};
el.onmousemove = function(e) {
if (!isDrawing) return;
var currentPoint = { x: e.clientX, y: e.clientY };
ctx.lineTo(currentPoint.x, currentPoint.y);
lastPoint = currentPoint;
};
el.onmouseup = function() {
isDrawing = false;
ctx.closePath();
ctx.stroke();
};
Now we begin the path with mousedown, 'draw' the path in mousemove, and stroke the path with mouseup. I'm not sure about the 'closePath()' effect, but the inner circles disappear.
There is also a neat work around using two canvases:
<!DOCTYPE html>
<html>
<head>
<style>
canvas {
border:1px solid #c3c3c3;
}
</style>
</head>
<body>
<canvas id="cv1" width="400" height="300">
</canvas>
<canvas id="cv2" width="400" height="300">
</canvas>
<hr>
<button onclick='merge();'>Merge</button>
<script>
var el1 = document.getElementById('cv1');
var el2 = document.getElementById('cv2');
var ctx1 = el1.getContext('2d');
var ctx2 = el2.getContext('2d');
ctx1.lineJoin = "round"
ctx1.strokeStyle = "#00FF00";
ctx1.globalAlpha = "0.2";
ctx1.lineWidth = 30;
ctx1.globalCompositeOperation = "source-over";
ctx2.globalCompositeOperation = "source-over";
var isDrawing, lastPoint;
el1.onmousedown = function(e) {
isDrawing = true;
lastPoint = { x: e.clientX, y: e.clientY };
};
el1.onmousemove = function(e) {
if (!isDrawing) return;
var currentPoint = { x: e.clientX, y: e.clientY };
ctx1.beginPath();
ctx1.moveTo(lastPoint.x, lastPoint.y);
ctx1.lineTo(currentPoint.x, currentPoint.y);
ctx1.closePath();
ctx1.stroke();
lastPoint = currentPoint;
};
el1.onmouseup = function() {
isDrawing = false;
};
function merge() {
ctx2.putImageData(ctx1.getImageData(0,0,400,300),0,0);
}
</script>
</body>
</html>
This allows you to draw on one canvas, but if you don't like what you have done, you can reverse it.
I am writing on whiteboard using HTML5 drawing.
The problem is when I am trying to draw ellipse, so press down and drag, many ellipse are drawn.
ctx.moveTo(startX, startY + (y-startY)/2);
ctx.bezierCurveTo(startX, startY, x, startY, x, startY + (y-startY)/2);
ctx.bezierCurveTo(x, y, startX, y, startX, startY + (y-startY)/2);
ctx.stroke();
I want to show only one ellipse every time.
Any help?
This might help - this is my version of drawing an ellipse using only arc and scaling.
https://jsfiddle.net/richardcwc/wdf9cocz/
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var scribble_canvasx = $(canvas).offset().left;
var scribble_canvasy = $(canvas).offset().top;
var scribble_last_mousex = scribble_last_mousey = 0;
var scribble_mousex = scribble_mousey = 0;
var scribble_mousedown = false;
//Mousedown
$(canvas).on('mousedown', function(e) {
scribble_last_mousex = parseInt(e.clientX-scribble_canvasx);
scribble_last_mousey = parseInt(e.clientY-scribble_canvasy);
scribble_mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
scribble_mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
scribble_mousex = parseInt(e.clientX-scribble_canvasx);
scribble_mousey = parseInt(e.clientY-scribble_canvasy);
if(scribble_mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
//Save
ctx.save();
ctx.beginPath();
//Dynamic scaling
var scalex = 1*((scribble_mousex-scribble_last_mousex)/2);
var scaley = 1*((scribble_mousey-scribble_last_mousey)/2);
ctx.scale(scalex,scaley);
//Create ellipse
var centerx = (scribble_last_mousex/scalex)+1;
var centery = (scribble_last_mousey/scaley)+1;
ctx.arc(centerx, centery, 1, 0, 2*Math.PI);
//Restore and draw
ctx.restore();
ctx.strokeStyle = 'black';
ctx.lineWidth = 5;
ctx.stroke();
}
//Output
$('#output').html('current: '+scribble_mousex+', '+scribble_mousey+'<br/>last: '+scribble_last_mousex+', '+scribble_last_mousey+'<br/>mousedown: '+scribble_mousedown);
});
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>