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>
Related
I just in problem when draw multiple circle in canvas. When I draw single circle just sucessfully, but for next circle first circle is gone. Actually only one circle is exist. So, please give me something in my code for multiple circle,
this my code
html
<canvas id="canvas" width="800" height="500"></canvas>
JS
//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;
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_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.clearRect(0,0,canvas.width,canvas.height);
//Save
ctx.save();
ctx.beginPath();
//Dynamic scaling
var scalex = 1*((mousex-last_mousex)/2);
var scaley = 1*((mousey-last_mousey)/2);
ctx.scale(scalex,scaley);
//Create ellipse
var centerx = (last_mousex/scalex)+1;
var centery = (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();
}
});`
The ctx.clearRect function is clearing the canvas every time you click and move your mouse, therefore the previous circle is cleared and new circle is drew onto it. But if you remove that function, it will create a new circle every time you move the mouse and is not what you want.
My solution will be adding a array variable circles to store the coordinates of the circles every time you mouseup, and then loop through the circles array to draw circle after clearing the canvas.
Also, I have move out the logics to draw a circle into a function. Here is how:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = 0, last_mousey = 0;
var mousex =0, mousey = 0;
var mousedown = false;
const circles = [];
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
circles.push({
x1: mousex,
y1: mousey,
x2: last_mousex,
y2: last_mousey
})
});
function drawCircle(ctx, circle) {
const { x1,y1,x2,y2 } = circle
ctx.beginPath();
//Dynamic scaling
var scalex = 1*((x1-x2)/2);
var scaley = 1*((y1-y2)/2);
ctx.scale(scalex,scaley);
//Create ellipse
var centerx = (x2/scalex)+1;
var centery = (y2/scaley)+1;
ctx.arc(centerx, centery, 1, 0, 2*Math.PI);
//Restore and draw
ctx.restore();
ctx.strokeStyle = 'black';
ctx.lineWidth = 5;
ctx.stroke();
ctx.save();
}
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height);
//Save
ctx.save();
circles.forEach(circle => {
drawCircle(ctx, circle)
})
drawCircle(ctx, {
x1: mousex,
y1: mousey,
x2: last_mousex,
y2: last_mousey
})
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500" style="border: 1px solid black"></canvas>
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>
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 am making a canvas, where there is a large image and behind it there is another image. then by using mouse coordinate I made a circle around the cursor. This circle will work as a hole to reveal the hidden image under the background. I made it kinda but I cannot set the front image.
Have a look at my code please: JSFiddle
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 578;
var height = 400;
var imageObj = new Image();
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
function writeMessage(canvas, message, x, y) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var pattern = context.createPattern(imageObj, 'no-repeat');
context.fillStyle = pattern;
context.fill();
context.font = '28pt Calibri';
context.fillStyle = 'black';
//context.fillText(message, x, y);
context.beginPath();
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
}
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);
//var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message, mousePos.x, mousePos.y);
}, false);
context.fillStyle = 'black';
context.fill();
Can someone tell me please how to have an image as big as the canvas to cover it?
Thanks
It looks like you are on the right track. The easiest way to have an image where the circle is not in your setup, would be to set a background image on the canvas element, and use background-size: cover to make it fill the canvas area.
Working Example (see CSS in second block):
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 578;
var height = 400;
var imageObj = new Image();
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
function writeMessage(canvas, message, x, y) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var pattern = context.createPattern(imageObj, 'no-repeat');
context.fillStyle = pattern;
context.fill();
context.font = '28pt Calibri';
context.fillStyle = 'black';
//context.fillText(message, x, y);
context.beginPath();
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
}
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);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message, mousePos.x, mousePos.y);
}, false);
canvas, img {
display:block;
margin:1em auto;
border:1px solid black;
}
canvas {
background:url('http://img2.wikia.nocookie.net/__cb20090917002539/starwars/images/7/70/Vader_yelloweyes.jpg');
background-size: cover;
}
<canvas id="myCanvas" width="578" height="400"></canvas>
<p></p>
To get the foreground image to fill the canvas, and take care of the edge, you need to resize the image in another canvas.
Working Example:
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 0;
var y = 0;
var width = 578;
var height = 400;
var imageObj = new Image();
//Create another canvas to darw a resized image to.
var imageResized = document.createElement('canvas');
imageResized.width = width;
imageResized.height = height;
//Wait for the original image to low to draw the resize.
imageObj.onload = function() {
//Find hoe mauch to scale the image up to cover.
var scaleX = width / imageObj.width;
var scaleY = height / imageObj.height;
var scaleMax = Math.max(scaleX, scaleY);
var ctx = imageResized.getContext('2d');
ctx.scale(scaleMax, scaleMax);
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
function writeMessage(canvas, message, x, y) {
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
var pattern = context.createPattern(imageResized, 'no-repeat');//Use imageResized, not imageObj.
context.fillStyle = pattern;
context.fill();
context.font = '28pt Calibri';
context.fillStyle = 'black';
//context.fillText(message, x, y);
context.beginPath();
context.arc(x, y, 50, 0, 2 * Math.PI);
context.stroke();
}
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);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message, mousePos.x, mousePos.y);
}, false);
canvas, img {
display:block;
margin:1em auto;
border:1px solid black;
}
canvas {
background:url('http://img2.wikia.nocookie.net/__cb20090917002539/starwars/images/7/70/Vader_yelloweyes.jpg');
background-size: cover;
}
<canvas id="myCanvas" width="578" height="400"></canvas>
<p></p>
I want something like ellipse option in paint for drawing on my canvas. I have achieved this partially. The problem is I am not able to get radius of circle; currently I have hard coded it to 15. Also I want to draw an ellipse (like in paint) not exact circle.
This is my code for drawing circle on canvas using mouse events. Please help me with code to achieve my above mentioned requirements.
function tool_circle() {
var tool = this;
this.started = false;
this.mousedown = function (ev) {
tool.started = true;
tool.x0 = ev._x;
tool.y0 = ev._y;
};
this.mousemove = function (ev) {
if (!tool.started) {
return;
}
context.fillStyle = 'red';
var distance = Math.sqrt(Math.pow(tool.x0 - ev._x, 2) + Math.pow(tool.y0 - ev._y));
context.beginPath();
context.arc(tool.x0, tool.y0,15, 0, Math.PI * 2, false);
context.stroke();
context.fill();
};
this.mouseup = function (ev) {
if (tool.started) {
tool.mousemove(ev);
tool.started = false;
img_update();
}
};
}
I would something similar as with markE's answer however, using Bezier curve will draw ellipses but it won't give you the exact radius that you probably would need.
For that a function to draw a manual ellipse is needed, and it's rather simple -
This function will take a corner start point and and end point and draw an ellipse exactly within that boundary:
Live demo
function drawEllipse(x1, y1, x2, y2) {
var radiusX = (x2 - x1) * 0.5, /// radius for x based on input
radiusY = (y2 - y1) * 0.5, /// radius for y based on input
centerX = x1 + radiusX, /// calc center
centerY = y1 + radiusY,
step = 0.01, /// resolution of ellipse
a = step, /// counter
pi2 = Math.PI * 2 - step; /// end angle
/// start a new path
ctx.beginPath();
/// set start point at angle 0
ctx.moveTo(centerX + radiusX * Math.cos(0),
centerY + radiusY * Math.sin(0));
/// create the ellipse
for(; a < pi2; a += step) {
ctx.lineTo(centerX + radiusX * Math.cos(a),
centerY + radiusY * Math.sin(a));
}
/// close it and stroke it for demo
ctx.closePath();
ctx.strokeStyle = '#000';
ctx.stroke();
}
The demo marks the rectangle area too to show that the ellipse is exactly within it.
Draw
To handle mouse operation that will let you draw the ellipse you can do:
var canvas = document.getElementById('myCanvas'),
ctx = canvas.getContext('2d'),
w = canvas.width,
h = canvas.height,
x1, /// start points
y1,
isDown = false; /// if mouse button is down
/// handle mouse down
canvas.onmousedown = function(e) {
/// get corrected mouse position and store as first point
var rect = canvas.getBoundingClientRect();
x1 = e.clientX - rect.left;
y1 = e.clientY - rect.top;
isDown = true;
}
/// clear isDown flag to stop drawing
canvas.onmouseup = function() {
isDown = false;
}
/// draw ellipse from start point
canvas.onmousemove = function(e) {
if (!isDown) return;
var rect = canvas.getBoundingClientRect(),
x2 = e.clientX - rect.left,
y2 = e.clientY - rect.top;
/// clear canvas
ctx.clearRect(0, 0, w, h);
/// draw ellipse
drawEllipse(x1, y1, x2, y2);
}
A tip can be to create a top canvas on top of your main canvas and do the drawing itself there. When mouse button is released then transfer the drawing to your main canvas. This way you don't have to redraw everything when drawing a new shape.
Hope this helps!
Here's an example of how to drag-draw an oval.
Demo: http://jsfiddle.net/m1erickson/3SFJy/
Example code using 2 Bezier curves to drag-draw an oval:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:0px;}
#canvas{ border:1px solid blue; }
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var startX;
var startY;
var isDown=false;
function drawOval(x,y){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.beginPath();
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.closePath();
ctx.stroke();
}
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
isDown=true;
}
function handleMouseUp(e){
if(!isDown){ return; }
e.preventDefault();
e.stopPropagation();
isDown=false;
}
function handleMouseOut(e){
if(!isDown){ return; }
e.preventDefault();
e.stopPropagation();
isDown=false;
}
function handleMouseMove(e){
if(!isDown){ return; }
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
drawOval(mouseX,mouseY);
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag to create a circle or oval</h4>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Here's my way of drawing an ellipse onto a canvas with mouse drag.
It uses radius of 1, but dynamic scaling to get the ellipse effect :)
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>