I need create smooth drawing lines with transparent without clearRect method i try use: globalAlpha and strokeStyle with rgba like this:
ctx.strokeStyle = "rgba( redChannel, greenChannel, blueChannel, AlphaChannel)";
But did not work both methods. How i can drawing transparent lines without clearRect method. While i use clearRect before each drawing globalAlpha works, but i need that working without it.
my code example:
var el = document.getElementById('c');
var ctx = el.getContext('2d');
ctx.lineWidth = 10;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.globalAlpha = "0.2";
//ctx.strokeStyle = "rgba(255, 0, 0, 150)";
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.closePath();
};
el.onmouseup = function() {
isDrawing = false;
points.length = 0;
};
canvas { border: 1px solid #ccc }
<canvas id="c" width="500" height="300"></canvas>
You are redrawing the entire path every time the mouse moves, so even though the globalAlpha value is set to 0.2 the layering effect makes the line appear solid.
Option 1:
use clearRect to clear the path onmousemove then redraw;
Option 2:
draw only the last segment of the path, but overlaps are visible:
var el = document.getElementById('c');
var ctx = el.getContext('2d');
ctx.lineWidth = 10;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.globalAlpha = "0.2";
//ctx.strokeStyle = "rgba(255, 0, 0, 150)";
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();
//draw just the last segment
if(points.length>1) {
ctx.moveTo(points[points.length-2].x, points[points.length-2].y);
ctx.lineTo(points[points.length-1].x, points[points.length-1].y);
}
ctx.stroke();
ctx.closePath();
};
el.onmouseup = function() {
isDrawing = false;
points.length = 0;
};
canvas { border: 1px solid #ccc }
<canvas id="c" width="500" height="300"></canvas>
Option 3:
set the opacity of the canvas element
var el = document.getElementById('c');
var ctx = el.getContext('2d');
ctx.lineWidth = 10;
ctx.lineJoin = ctx.lineCap = 'round';
//ctx.globalAlpha = "0.2";
//ctx.strokeStyle = "rgba(255, 0, 0, 150)";
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.closePath();
};
el.onmouseup = function() {
isDrawing = false;
points.length = 0;
};
canvas { border: 1px solid #ccc; opacity:0.2; }
<canvas id="c" width="500" height="300"></canvas>
Option 3: use two canvas, on main - draw only on mouse release, and on second preview canvas, just show progress, so drawing will be visible even on mouse move. Also for preview canvas we need to do some tricks like clean previous line segment, so everything looks good.
//main canvas
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//preview
var el2 = document.getElementById('c2');
var ctx2 = el2.getContext('2d');
ctx.lineWidth = 10;
ctx2.lineWidth = 10;
ctx.lineJoin = ctx.lineCap = 'round';
ctx2.lineJoin = ctx2.lineCap = 'round';
ctx.strokeStyle = "rgba(255, 0, 0, 0.5)";
ctx2.strokeStyle = "rgba(255, 0, 0, 0.5)";
var isDrawing, points = [ ];
el2.onmousedown = function(e) {
isDrawing = true;
points.push({ x: e.clientX, y: e.clientY });
ctx.beginPath();
ctx2.beginPath();
};
el2.onmousemove = function(e) {
if (!isDrawing) return;
points.push({ x: e.clientX, y: e.clientY });
//draw just the last segment
if(points.length>1) {
ctx.moveTo(points[points.length-2].x, points[points.length-2].y);
ctx.lineTo(points[points.length-1].x, points[points.length-1].y);
//start preview
ctx2.beginPath();
//clean from last line
ctx2.globalCompositeOperation = "destination-out";
ctx2.strokeStyle = "rgba(255, 0, 0, 1)";
ctx2.moveTo(points[points.length-2].x, points[points.length-2].y);
ctx2.lineTo(points[points.length-1].x, points[points.length-1].y);
ctx2.stroke();
//rest
ctx2.strokeStyle = "rgba(255, 0, 0, 0.5)";
ctx2.globalCompositeOperation = "source-over";
//draw new line segment
ctx2.moveTo(points[points.length-2].x, points[points.length-2].y);
ctx2.lineTo(points[points.length-1].x, points[points.length-1].y);
ctx2.stroke();
}
};
el2.onmouseup = function() {
ctx2.clearRect(0, 0, ctx2.canvas.width, ctx2.canvas.height);
ctx.stroke();
isDrawing = false;
points.length = 0;
};
canvas {
border: 1px solid #ccc;
position:absolute;
}
<canvas id="c" width="500" height="200"></canvas>
<canvas id="c2" width="500" height="200"></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 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.
Hello i need make smooth brush likes this:
I try to create it, i make circle and fill it, but result not successful:
Can be seen circles.. this is not smooth like first example
my example code:
function distanceBetween(point1, point2) {
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
}
function angleBetween(point1, point2) {
return Math.atan2( point2.x - point1.x, point2.y - point1.y );
}
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//ctx.fillStyle = "rgba('255, 0, 0, 0.1')";
ctx.fillStyle = "red";
ctx.strokeStyle = "red";
ctx.globalAlpha = "0.05";
ctx.lineWidth = 0;
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 };
var dist = distanceBetween(lastPoint, currentPoint);
var angle = angleBetween(lastPoint, currentPoint);
for (var i = 0; i < dist; i+=5) {
x = lastPoint.x + (Math.sin(angle) * i) - 25;
y = lastPoint.y + (Math.cos(angle) * i) - 25;
ctx.beginPath();
ctx.arc(x+10, y+10, 20, false, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
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()">
http://codepen.io/anon/pen/NPjwry
Try with a smaller globalAlpha and decrease the stepping (so you draw more circles)
function distanceBetween(point1, point2) {
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));
}
function angleBetween(point1, point2) {
return Math.atan2( point2.x - point1.x, point2.y - point1.y );
}
var el = document.getElementById('c');
var ctx = el.getContext('2d');
//ctx.fillStyle = "rgba('255, 0, 0, 0.1')";
ctx.fillStyle = "red";
ctx.strokeStyle = "red";
ctx.globalAlpha = "0.01";
ctx.lineWidth = 0;
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 };
var dist = distanceBetween(lastPoint, currentPoint);
var angle = angleBetween(lastPoint, currentPoint);
for (var i = 0; i < dist; i+=3) {
x = lastPoint.x + (Math.sin(angle) * i) - 25;
y = lastPoint.y + (Math.cos(angle) * i) - 25;
ctx.beginPath();
ctx.arc(x+10, y+10, 20, false, Math.PI * 2, false);
ctx.closePath();
ctx.fill();
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()">
Updated codepen: http://codepen.io/gpetrioli/pen/ramqBz
There is more simple solution: just set width of line to 25px
let ctx = this.d.transparentUpdateImage.getContext('2d');
if (!this.lastPos) {
this.lastPos = {x: x, y: y};
return
}
ctx.beginPath();
ctx.moveTo(this.lastPos.x, this.lastPos.y);
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.strokeStyle = 'red';
ctx.lineWidth = 25;
ctx.lineTo(x, y);
ctx.stroke();
ctx.closePath();
this.lastPos = {x: x, y: y};
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>