Draw polygons of fixed sides with mouse on canvas - javascript

I am trying to draw polygons(lets say 4 sided) on a canvas using mouse click and move events.
Click on canvas the moveTo(this point).
Now move the cursor a lineTo(the current point) but not intermediate point. Line should keep moving with mousemove and should be draw to the canvas only once clicked.
After fourth click(or any x) the polygon should closepath();
var pressed = false;
function myfunc1(e){
context.beginPath();
context.arc(e.clientX, e.clientY, radius, 0, Math.PI*2);
context.fill();
context.beginPath();
context.moveTo(e.clientX,e.clientY);
pressed = true;
}
function myfunc2(e){
if(pressed ===true){
context.lineTo(e.clientX,e.clientY);
context.stroke();
}
}
canvas.addEventListener('click',myfunc1);
canvas.addEventListener('mousemove',myfunc2);
I wrote this, but i don't want the intermediate lines

What you need is a stack. Don't think of drawing lines. Think of storing all your points of click in an array. And when you have clicked 4 times, draw the polygon (assuming that is what you want). Something like this:
var stack = [];
myfunc1(e){
stack.push(e.clientX, e.clientY);
if(stack.length == 4)
actuallyDraw();
}
var actuallyDraw(){
//take the 4 points in stack and draw the polygon
//clearing the stack for the next polygon
stack.length = 0;
}
canvas.addEventListener('click', myfunc1);

Use below code it will help you to solve your problem.
Click to assign polygon vertices point
<button id=done>Click when done assigning points</button>
<canvas id="canvas" width=450 height=450></canvas>
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
context.lineWidth=2;
context.strokeStyle='blue';
var coordinates = [];
var isDone=false;
$('#done').click(function(){
isDone=true;
});
$("#canvas").mousedown(function(e){handleMouseDown(e);});
function handleMouseDown(e){
if(isDone || coordinates.length>10){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
coordinates.push({x:mouseX,y:mouseY});
drawPolygon();
}
function drawPolygon(){
context.clearRect(0,0,cw,ch);
context.beginPath();
context.moveTo(coordinates[0].x, coordinates[0].y);
for(index=1; index<coordinates.length;index++) {
context.lineTo(coordinates[index].x, coordinates[index].y);
}
context.closePath();
context.stroke();
}

I created an array(cords[]) which holds the coordinates of the polygon i am drawing and push them to another array (polygons[]) if the current polygon is completed. Then i can clear the canvas when required and redraw the polygons from polygon[]
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = document.getElementById("myimg");
ctx.drawImage(img, 0, 0);
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var polygons = [];
var cords = [];
var start = false;
var control = false;
var clicks = 0;
ctx.strokeStyle = "orange";
ctx.lineWidth = 1;
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
function handleMouseDown(e) {
start = false;
clicks = clicks + 1;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
cords.push([mouseX, mouseY]);
console.log(cords);
clearanddraw();
if (clicks % 4 === 0) {
return;
}
start = true;
}
function handleMouseMove(e) {
if (!start) {
return;
}
canvasclear();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
ctx.beginPath();
ctx.moveTo(cords[clicks - 1][0], cords[clicks - 1][1]);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
}
function canvasclear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(myimg, 0, 0);
drawOtherPol();
ctx.beginPath();
ctx.moveTo(cords[0][0], cords[0][1]);
for (var i = 0; i < clicks - 1; i++) {
ctx.lineTo(cords[i + 1][0], cords[i + 1][1]);
//alert("redrwan");
}
ctx.stroke();
return;
}
function clearanddraw() {
if (clicks > 1) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(myimg, 0, 0);
drawOtherPol();
ctx.beginPath();
ctx.moveTo(cords[0][0], cords[0][1]);
for (var i = 0; i < clicks - 1; i++) {
ctx.lineTo(cords[i + 1][0], cords[i + 1][1]);
}
if (clicks < 4) {
ctx.stroke();
}
if (clicks === 4) {
ctx.closePath();
ctx.stroke();
savepolygon();
cords = [];
clicks = 0;
return;
}
}
start = true;
}
function savepolygon() {
polygons.push(cords);
console.log(polygons);
return
}
function drawOtherPol() {
if (polygons.length === 0) {
return;
} else {
for (var i = 0; i < polygons.length; i++) {
ctx.beginPath();
ctx.moveTo(polygons[i][0][0], polygons[i][0][1]);
ctx.lineTo(polygons[i][1][0], polygons[i][1][1]);
ctx.lineTo(polygons[i][2][0], polygons[i][2][1]);
ctx.lineTo(polygons[i][3][0], polygons[i][3][1]);
ctx.closePath();
ctx.stroke();
}
return;
}
}

Related

How i can draw new lines with convas js

i want to draw lines with convas but my previous lines was deleted when i try create a new line. I wark with convas the first time and i will be happy if you can say me about my mistakes and solutions of the problem
const convas = document.querySelector(".v");
const ctx = convas.getContext("2d");
let startPositionLine = { x: 0, y: 0 };
let endPositionLine = { x: 0, y: 0 };
let { xStart, yStart } = startPositionLine;
let { xEnd, yEnd } = endPositionLine;
function moveMouseEvent(e) {
xEnd = e.offsetX;
yEnd = e.offsetY;
ctx.beginPath();
ctx.clearRect(0, 0, convas.width, convas.height);
ctx.moveTo(xStart, yStart);
ctx.lineTo(xEnd, yEnd);
ctx.stroke();
}
convas.onmousedown = (e) => {
ctx.beginPath();
xStart = e.offsetX;
yStart = e.offsetY;
ctx.stroke();
convas.onmousemove = (e) => moveMouseEvent(e);
};
convas.onmouseup = () => {
convas.onmousemove = null;
};
I mentioned this in my comment to your post above, but thought I would just give an example you can run and test here. So you are correct in what you are doing, but you just need to save each drawn line to an array AS YOU DRAW THEM. You will see the code for this in the mousedown event handler here. Then you need to redraw those saved lines each time after you clear the canvas in mousemove event handler.
const canvas = document.getElementById('canvas');
var canvasrect = canvas.getBoundingClientRect();
var Xstart = 0;
var Ystart = 0;
var Xend = 0
var Yend = 0
var isDrawing = false;
var linesArray = [{}];
// MOUSE CLICK / BUTTON DOWN LISTENER
canvas.addEventListener('mousedown', e => {
e.preventDefault();
e.stopPropagation();
canvasrect = canvas.getBoundingClientRect();
Xstart = e.clientX - canvasrect.left;
Ystart = e.clientY - canvasrect.top;
// We need to know if the user is actuallydrawing or not.
// Each time the user clicks their canvas we toggle whether to start or stop drawing.
if (isDrawing) {
// If this is the end of a line, save the end coordinates to the latest array element.
linesArray[linesArray.length - 1].xe = Xend;
linesArray[linesArray.length - 1].ye = Yend;
isDrawing = false;
} else {
// If this is the start of a new line, save the start coordinates in a new array element along with end coordinate placeholders.
linesArray.push({
xs: Xstart,
ys: Ystart,
xe: 0,
ye: 0
})
isDrawing = true;
}
});
// MOUSE MOVE
canvas.addEventListener('mousemove', e => {
e.preventDefault();
e.stopPropagation();
// get the current mouse x & y locations along with any scrolling and window resizing offsets.
Xend = e.clientX - canvasrect.left;
Yend = e.clientY - canvasrect.top;
if (isDrawing === true) {
var ctx = canvas.getContext('2d');
//clear the canvas
ctx.clearRect(0, 0, canvasrect.width, canvasrect.height);
// Draw a line from the initial click coordinates to the current mouse pointer coordinates.
ctx.strokeStyle = '#fe0101';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(Xstart, Ystart);
ctx.lineTo(Xend, Yend);
ctx.stroke();
// now redraw the previous lines saved in the linesArray
if (linesArray.length >= 1) {
for (let i = 0; i < linesArray.length; i++) {
if (linesArray[i].xe != 0) {
ctx.strokeStyle = '#fe0101';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(linesArray[i].xs, linesArray[i].ys);
ctx.lineTo(linesArray[i].xe, linesArray[i].ye);
ctx.stroke();
}
}
}
}
});
<canvas id="canvas" width="500" height="500" style="background-color:lightGray"></canvas>

How to draw parallelogram with draggable points

I have been studying JS for a few days, but I need to draw a parallelogram and allow user to change its angles by dragging one of its points. I took a code from a related question, and tried to change it (I know, it's a nightmare). But the 4th point doesn't work properly. I get this:
https://i.stack.imgur.com/PAjE6.png
How can I make the 4th point create a parallelogram?
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var mouse = {};
var draggable = false;
context.lineWidth = 2;
context.strokeStyle = "blue";
var coordinates = [];
var isDone = false;
var clicks = 0;
canvas.addEventListener("mousedown", function(e) {
handleMouseDown(e);
});
function GetMassCenterAndFourthPoint(knownpoints) {
let point4X = knownpoints[2].x - knownpoints[1].x + knownpoints[0].x;
let point4Y = knownpoints[2].y - knownpoints[1].y + knownpoints[0].y;
coordinates.push({
x: point4X,
y: point4Y
});
}
function handleMouseDown(e) {
mouse = oMousePos(canvas, e);
//if isDone you can drag
if (isDone) {
for (index = 0; index < coordinates.length; index++) {
// you draw a small circle no stroke, no fill
context.beginPath();
context.arc(
coordinates[index].x,
coordinates[index].y,
5,
0,
2 * Math.PI
);
// if the mouse is inside the circle
if (context.isPointInPath(mouse.x, mouse.y)) {
// you can drag this point
// I'm using index + 1 because index == 0 is false
draggable = index + 1;
// if I have a point a can break the loop
break;
}
}
} else {
coordinates.push({
x: mouse.x,
y: mouse.y
});
drawPolygon();
clicks++;
if (clicks === 3) {
isDone = true;
}
}
}
function drawPolygon() {
context.clearRect(0, 0, cw, ch);
if (isDone) {
GetMassCenterAndFourthPoint(coordinates);
}
context.beginPath();
context.moveTo(coordinates[0].x, coordinates[0].y);
for (index = 1; index < coordinates.length; index++) {
context.lineTo(coordinates[index].x, coordinates[index].y);
}
context.closePath();
context.stroke();
// Additionaly I'm drawing a small circle around every point
// you can delete this.
for (index = 0; index < coordinates.length; index++) {
context.beginPath();
context.arc(coordinates[index].x, coordinates[index].y, 5, 0, 2 * Math.PI);
context.stroke();
}
}
canvas.addEventListener("mousemove", function(e) {
if (isDone) {
if (draggable) {
mouse = oMousePos(canvas, e);
// draggable - 1 is the index of the point in the coordinates array
coordinates[draggable - 1].x = mouse.x;
coordinates[draggable - 1].y = mouse.y;
drawPolygon();
}
}
});
canvas.addEventListener("mouseup", function(e) {
if (draggable) {
draggable = false;
}
});
// a function to detect the mouse position
function oMousePos(canvas, evt) {
var ClientRect = canvas.getBoundingClientRect();
return {
//objeto
x: Math.round(evt.clientX - ClientRect.left),
y: Math.round(evt.clientY - ClientRect.top)
};
}
canvas {
border: 1px solid black;
}
<canvas id="canvas" width="600" height="600"></canvas>
I also tried to draw my own parallelogram, but can't do it draggable
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
startX;
startY;
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var mouse = {};
var draggable = false;
var points = [];
let isDone = false;
var clicks =0;
let click = false;
canvas.addEventListener("click", function(e) {
console.log(clicks);
clicks++;
if(!isDone){
const point = new Point(e.offsetX, e.offsetY);
points.push(point);
context.beginPath();
context.arc(point.x, point.y, 5, 0, 2 * Math.PI);
context.fillStyle = "red";
context.fill();
if(clicks===3){
isDone=true;
}
}
if(isDone){
GetMassCenterAndFourthPoint(points);
drawParallelogramAndCircle();
}
});
function GetMassCenterAndFourthPoint(knownpoints){
const point4X = knownpoints[2].x-knownpoints[1].x+knownpoints[0].x;
const point4Y = knownpoints[2].y-knownpoints[1].y+knownpoints[0].y;
context.beginPath();
context.arc(point4X, point4Y, 5, 0, 2 * Math.PI);
context.fillStyle = "red";
context.fill();
points.push(new Point(point4X, point4Y));
const massCenterX = (knownpoints[1].x+knownpoints[3].x)/2;
const massCenterY = (knownpoints[1].y+knownpoints[3].y)/2;
points.push(new Point(massCenterX, massCenterY));
}
function drawParallelogramAndCircle(){
context.beginPath();
context.moveTo(points[0].x, points[0].y);
for(let i=1;i<points.length-1;i++){
context.lineTo(points[i].x, points[i].y);
if(i===3){
context.lineTo(points[0].x, points[0].y);
}
}
context.strokeStyle = "blue";
context.closePath();
context.stroke();
// find square. Here will be the logic to calculate square
let square = 250;
context.beginPath();
context.arc(points[4].x, points[4].y, 30, 0, 2 * Math.PI);
context.strokeStyle = "yellow";
context.closePath();
context.stroke();
}
canvas {
border: 1px solid black;
}
<canvas id="canvas" width="600" height="600"></canvas>

HTML5 Canvas - retain drawn rectangles on images

I have an image gallery. When a image from gallery is clicked, it is rendered on a canvas. The objective is to allow users to draw rectangles on regions of interest and capture the rectangle coordinates. The drawn rectangles vanishes when I move to the next image.
The following is the code and I have tried to comment as much as I can:
//get clicked image name and store in a variable
function clickedImage(clicked_id) {
var clickedImg = document.getElementById(clicked_id).src;
var clickedImg = clickedImg.replace(/^.*[\\\/]/, '');
localStorage.setItem("clickedImg", clickedImg);
//initiate canvas to load image
var canvas = document.getElementById("iriscanvas");
var ctx = canvas.getContext("2d");
var thumbNails = document.getElementById("loaded_img_panel");
var pic = new Image();
pic.onload = function() {
ctx.drawImage(pic, 0,0)
}
//load the image from the thumbnail on to the canvas
thumbNails.addEventListener('click', function(event) {
pic.src = event.target.src;
});
//thickness of rectangle and count of rectangles
var strokeWidth = 3;
drawCount = 1;
//initiate mouse events
canvas.addEventListener("mousemove", function(e) {
drawRectangleOnCanvas.handleMouseMove(e);
}, false);
canvas.addEventListener("mousedown", function(e) {
drawRectangleOnCanvas.handleMouseDown(e);
}, false);
canvas.addEventListener("mouseup", function(e) {
drawRectangleOnCanvas.handleMouseUp(e);
}, false);
canvas.addEventListener("mouseout", function(e) {
drawRectangleOnCanvas.handleMouseOut(e);
}, false);
function reOffset() {
var BB = canvas.getBoundingClientRect();
recOffsetX = BB.left;
recOffsetY = BB.top;
}
var recOffsetX, recOffsetY;
reOffset();
window.onscroll = function(e) {
reOffset();
}
window.onresize = function(e) {
reOffset();
}
var isRecDown = false;
var startX, startY;
var rects = [];
var newRect;
var drawRectangleOnCanvas = {
handleMouseDown: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX = parseInt(e.clientX - recOffsetX);
startY = parseInt(e.clientY - recOffsetY);
// Put your mousedown stuff here
isRecDown = true;
},
handleMouseUp: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
// Put your mouseup stuff here
isRecDown = false;
//if(!willOverlap(newRect)){
rects.push(newRect);
//}
drawRectangleOnCanvas.drawAll();
var brand = localStorage.getItem("brandNode");
var clickImg = localStorage.getItem("clickedImg");
//get x,y,w,h coordinates depending on how the rectangle is drawn.
if((mouseX-startX) < 0) {
stX = startX + (mouseX-startX)
} else {
stX = startX
}
if((mouseY-startY) < 0) {
stY = startY + (mouseY-startY)
} else {
stY = startY
}
if((mouseX-startX) < 0) {
stW = startX - stX
} else {
stW = mouseX - startX
}
if((mouseY-startY) < 0) {
stH = startY - stY
} else {
stH = mouseY - startY
}
//log the coordinates of the rectangles
var dat = {image : clickImg, brand: brand, x : stX, y : stY, w: stW, h: stH};
var dat = JSON.stringify(dat);
console.log(dat);
},
drawAll: function() {
ctx.drawImage(pic, 0, 0);
ctx.lineWidth = strokeWidth;
var brand = localStorage.getItem("brandNode");
for (var i = 0; i < rects.length; i++) {
var r = rects[i];
ctx.strokeStyle = r.color;
ctx.globalAlpha = 1;
ctx.strokeRect(r.left, r.top, r.right - r.left, r.bottom - r.top);
ctx.beginPath();
//ctx.arc(r.left, r.top, 15, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = r.color;
ctx.fill();
var text = brand;
ctx.fillStyle = "#fff";
var font = "bold " + 12 + "px serif";
ctx.font = font;
var width = ctx.measureText(text).width;
var height = ctx.measureText("h").height; // this is a GUESS of height
ctx.fillText(text, r.left-1, r.top - 10)
}
},
handleMouseOut: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
// Put your mouseOut stuff here
isRecDown = false;
},
handleMouseMove: function(e) {
if (!isRecDown) {
return;
}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
newRect = {
left: Math.min(startX, mouseX),
right: Math.max(startX, mouseX),
top: Math.min(startY, mouseY),
bottom: Math.max(startY, mouseY),
color: "#9afe2e"
}
drawRectangleOnCanvas.drawAll();
ctx.strokeStyle = "#9afe2e";
ctx.lineWidth = strokeWidth;
ctx.globalAlpha = 1;
ctx.strokeRect(startX, startY, mouseX - startX, mouseY - startY);
}
}
}
When I move to the next image the rectangles created on the previous image is removed. I don't know if I have to use canvas.toDataURL to retain the rectangles, because I have thousands of images in the gallery and not sure if I will have space in the browser, though not all the images are going to the used for drawing rectangles.
Moreover, after drawing the rectangles when I click on the same image, it clears all the rectangles.
How can I retain the drawn rectangles within a session at least?
Layer 2 canvases over each other. Render the image into the bottom canvas, and draw on the top one. That way, changing the image won't affect the drawn lines.
A <canvas> works just like a real-life painter's canvas. There is no concept of layers or "objects" on a canvas. It's all just paint on a single surface.
When you draw a different image on a canvas, you're overriding everything that was on the canvas already.

Drawing multiple polygons in js

I'm using this code, and it works with charm - It draws a polygon (with canvas) on a given picture, however I'm struggling to modify code, so that it would enable me to draw multiple polygons instead of just one.
I'm a noob to js and haven't found yet anything that might solve it, I'd appreciate any help/hint in some direction.
Code:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="main.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script>
//radius of click around the first point to close the draw
var END_CLICK_RADIUS = 15;
//the max number of points of your polygon
var MAX_POINTS = 8;
var mouseX = 0;
var mouseY = 0;
var isStarted = false;
var points = null;
var canvas = null;
window.onload = function() {
background = document.getElementById('justanimage');
//initializing canvas and draw color
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
changeColor("blue");
image = new Image();
image.onload = function() {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
};
image.src = 'justanimage.gif';
canvas.addEventListener("click", function(e) {
var x = e.clientX-canvas.offsetLeft;
var y = e.clientY-canvas.offsetTop;
if(isStarted) {
//drawing the next line, and closing the polygon if needed
if(Math.abs(x - points[0].x) < END_CLICK_RADIUS && Math.abs(y - points[0].y) < END_CLICK_RADIUS) {
isStarted = false;
} else {
points[points.length] = new Point(x, y);
if(points.length >= MAX_POINTS) {
isStarted = false;
}
}
} else if(points == null) {
//opening the polygon
points = new Array();
points[0] = new Point(x, y);
isStarted = true;
}
}, false);
//we just save the location of the mouse
canvas.addEventListener("mousemove", function(e) {
mouseX = e.clientX - canvas.offsetLeft;
mouseY = e.clientY - canvas.offsetTop;
}, false);
//refresh time
setInterval("draw();", 5);
}
//object representing a point
function Point(x, y) {
this.x = x;
this.y = y;
}
//resets the application
function reset() {
isStarted = false;
points = null;
document.getElementById("coordinates").innerHTML = " ";
}
//displays coordinates of the the point list
function save() {
if(points == null) {
alert("No picture!");
} else {
var s = "";
for(var a in points) {
//inversing y axis by (canvas.height - points[a].y)
s += "(" + points[a].x + "," + (canvas.height - points[a].y) + ")\n";
}
document.getElementById("coordinates").innerHTML = s + '\n';
}
}
//draws the current shape
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
if(points != null && points.length > 0) {
ctx.moveTo(points[0].x, points[0].y);
for(i = 1 ; i < points.length ; i++) {
ctx.lineTo(points[i].x, points[i].y);
}
if(isStarted) {
ctx.lineTo(mouseX, mouseY);
} else {
ctx.lineTo(points[0].x, points[0].y);
}
}
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
ctx.stroke();
}
</script>
</head>
<body>
<div id="outer">
<canvas id="canvas" width=300 height=300; ></canvas>
</div>
<p id="coordinates"> </p>
<input type="button" value="Save" onclick="save();" />
<input type="button" value="Reset" onclick="reset();" />
</body>
</html>
Basically this solution adds a new array polygons, which keeps all polygons. The points array is now included in the polygons.
var polygons = [];
window.onload = function () {
// ...
canvas.addEventListener("click", function (e) {
// ...
if (isStarted) {
//drawing the next line, and closing the polygon if needed
if (Math.abs(x - polygons[polygons.length - 1][0].x) < END_CLICK_RADIUS && Math.abs(y - polygons[polygons.length - 1][0].y) < END_CLICK_RADIUS) {
isStarted = false;
} else {
polygons[polygons.length - 1].push(new Point(x, y));
if (polygons[polygons.length - 1].length >= MAX_POINTS) {
isStarted = false;
}
}
} else {
//opening the polygon
polygons.push([new Point(x, y)]);
isStarted = true;
}
}, false);
// ...
}
function draw() {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
polygons.forEach(function (points, i) {
ctx.beginPath();
points.forEach(function (p, j) {
if (j) {
ctx.lineTo(p.x, p.y);
} else {
ctx.moveTo(p.x, p.y);
}
});
if (i + 1 === polygons.length && isStarted) { // just the last one
ctx.lineTo(mouseX, mouseY);
} else {
ctx.lineTo(points[0].x, points[0].y);
}
ctx.stroke();
});
}
(Another solution might be to save the image with the last polygon and use it again for the new polygon.)
Working example:
//radius of click around the first point to close the draw
var END_CLICK_RADIUS = 15;
//the max number of points of your polygon
var MAX_POINTS = 8;
var mouseX = 0;
var mouseY = 0;
var isStarted = false;
var polygons = [];
var canvas = null;
var ctx;
var image;
window.onload = function () {
var background = document.getElementById('justanimage');
//initializing canvas and draw color
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
//changeColor("blue"); // <-- is missing!
image = new Image();
image.onload = function () {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
};
image.src = 'http://lorempixel.com/10/10/';
canvas.addEventListener("click", function (e) {
var x = e.clientX - canvas.offsetLeft;
var y = e.clientY - canvas.offsetTop;
if (isStarted) {
//drawing the next line, and closing the polygon if needed
if (Math.abs(x - polygons[polygons.length - 1][0].x) < END_CLICK_RADIUS && Math.abs(y - polygons[polygons.length - 1][0].y) < END_CLICK_RADIUS) {
isStarted = false;
} else {
polygons[polygons.length - 1].push(new Point(x, y));
if (polygons[polygons.length - 1].length >= MAX_POINTS) {
isStarted = false;
}
}
} else {
//opening the polygon
polygons.push([new Point(x, y)]);
isStarted = true;
}
}, false);
//we just save the location of the mouse
canvas.addEventListener("mousemove", function (e) {
mouseX = e.clientX - canvas.offsetLeft;
mouseY = e.clientY - canvas.offsetTop;
}, false);
//refresh time
setInterval("draw();", 5);
}
//object representing a point
function Point(x, y) {
this.x = x;
this.y = y;
}
//resets the application
function reset() {
isStarted = false;
points = null;
document.getElementById("coordinates").innerHTML = " ";
}
//draws the current shape
function draw() {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
polygons.forEach(function (points, i) {
ctx.beginPath();
points.forEach(function (p, j) {
if (j) {
ctx.lineTo(p.x, p.y);
} else {
ctx.moveTo(p.x, p.y);
}
});
if (i + 1 === polygons.length && isStarted) { // just the last one
ctx.lineTo(mouseX, mouseY);
} else {
ctx.lineTo(points[0].x, points[0].y);
}
ctx.stroke();
});
}
<canvas id="canvas" width="500" height="500"></canvas>
<img id="justanimage" />

how to remove a unconnected points when i mouseout from canvas

i need to remove unconnected points when i mouseout from canvas. I just draw lines when mousemove using moveTo and LineTo. when mouseout from canvas have to omit the unconnected points.
Here is code for jquery:
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript">
$(function() {
var canvas = $('#canvas');
var context = canvas.get(0).getContext("2d");
var clicked = false;
var b=0;
var storedLines = [];
var storedLine = {};
var mouse = {
x: -1,
y: -1
}
var parentOffset = $('#canvas').offset();
canvas.click(function(e) {
if (b==1)
{
$(this).unbind(e);
}
else
{
clicked = true;
mouse.x = e.pageX - parentOffset.left;
mouse.y = e.pageY - parentOffset.top;
context.moveTo(mouse.x, mouse.y);
if (clicked) {
storedLines.push({
startX: storedLine.startX,
startY: storedLine.startY,
endX: mouse.x,
endY: mouse.y
});
}
storedLine.startX = mouse.x;
storedLine.startY = mouse.y;
$(this).mousemove(function(k) {
context.clearRect(0, 0, 960, 500);
context.beginPath();
context.strokeStyle = "blue";
for (var i = 0; i < storedLines.length; i++) {
var v = storedLines[i];
context.moveTo(v.startX, v.startY);
context.lineTo(v.endX, v.endY);
context.stroke();
}
context.moveTo(mouse.x, mouse.y);
context.lineTo(k.pageX - parentOffset.left, k.pageY - parentOffset.top);
context.stroke();
context.closePath();
});
}
});
$('#canvas').mouseout(function(e){
$(this).unbind("mousemove");
b=1;
});
});
HTML code:
<html>
<body>
<canvas id="canvas" width=600 height=600 ></canvas>
</body>
</html>
First thing to do is to clarify the code : Have one part that deals only with the mouse, and another part that deals only with the lines.
This way you will have a much better view on what will happen on each event.
I started a bit to clarify the code, you should even make a class handling lines (which will be very useful if you handle several of them).
jsbin is here : http://jsbin.com/eseTODo/2/edit?js,output
var canvas = $('#canvas');
var context = canvas.get(0).getContext("2d");
// -----------------------------------------
// Mouse
var clicked = false;
var onCanvas = false;
var mouse = {
x: -1,
y: -1
}
var parentOffset = $('#canvas').offset();
canvas.mousedown(function (e) {
clicked = true;
if (!onCanvas) return;
mouse.x = e.pageX - parentOffset.left;
mouse.y = e.pageY - parentOffset.top;
addPoint(mouse.x, mouse.y);
clearScreen();
drawLines();
});
canvas.mouseup(function (e) {
clicked = false;
if (!onCanvas) return;
});
canvas.mousemove(function (e) {
if (!onCanvas) return;
clearScreen();
drawLines();
drawPendingLine(e.pageX - parentOffset.left,
e.pageY - parentOffset.top);
});
canvas.mouseout(function (e) {
onCanvas = false;
clearScreen();
drawLines();
clearLines();
});
canvas.mouseenter(function (e) {
onCanvas = true;
});
// -----------------------------------------
// Lines
var storedLines = [];
var storedLine = {};
var startedALine = false;
function clearLines() {
storedLines.length = 0;
startedALine = false;
}
function addPoint(x, y) {
if (startedALine) {
storedLines.push({
startX: storedLine.startX,
startY: storedLine.startY,
endX: x,
endY: y
});
}
startedALine = true;
storedLine.startX = x;
storedLine.startY = y
}
function drawLines() {
context.strokeStyle = "blue";
if (!startedALine) return;
if (!storedLines.length) return;
for (var i = 0; i < storedLines.length; i++) {
var v = storedLines[i];
context.beginPath();
context.moveTo(v.startX, v.startY);
context.lineTo(v.endX, v.endY);
context.stroke();
context.closePath();
}
context.stroke();
}
function drawPendingLine(lastX, lastY) {
if (!startedALine) return;
context.beginPath();
context.strokeStyle = "green";
context.moveTo(storedLine.startX, storedLine.startY);
context.lineTo(lastX, lastY);
context.stroke();
context.closePath();
}
function clearScreen() {
context.clearRect(0, 0, 600, 600);
}
Can't you set a flag like
var hasLeftCanvas = false;
and set it to true when you leave the canvas?
canvas.onmouseleave = function() {
hasLeftCanvas = true;
}
and then, in your script:
$(this).mousemove(function(k) {
if(!hasLeftCanvas) {
context.clearRect(0, 0, 960, 500);
context.beginPath();
context.strokeStyle = "blue";
for (var i = 0; i < storedLines.length; i++) {
var v = storedLines[i];
context.moveTo(v.startX, v.startY);
context.lineTo(v.endX, v.endY);
context.stroke();
}
context.moveTo(mouse.x, mouse.y);
context.lineTo(k.pageX - parentOffset.left, k.pageY - parentOffset.top);
context.stroke();
context.closePath();
}
});
remember to set it back to false when the cursor re enters the canvas

Categories