How to draw parallelogram with draggable points - javascript

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>

Related

How to clear a circle drawn with arc in javascript?

I am having problems when drawing a circle. How do I clear it?
I also still want to maintain the transparent background as much as possible as I am planning on making particles rain down. I also would want to not use images to lower the load on the server.
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
const ParticleFactory = function(){
this.interval = 100;
this.lastOutput = Date.now();
this.particles = [];
}
ParticleFactory.prototype.tick = function(){
if (Date.now() > this.lastOutput + this.interval) {
const particle = new Particle(500, 100, 4);
this.particles.push(particle);
this.lastOutput = Date.now();
}
for (var i=0; i < this.particles.length; i++) {
this.particles[i].tick();
};
}
ParticleFactory.prototype.draw = function(){
for (var i=0; i < this.particles.length; i++) {
this.particles[i].draw();
};
}
ParticleFactory.prototype.del = function(toDelete){
this.particles = this.particles.filter(item => item !== toDelete);
}
const Particle = function(x, y, r){
this.x = x;
this.y = y;
this.r = r;
}
Particle.prototype.tick = function(){
this.x -= 0.1;
}
Particle.prototype.draw = function(){
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
ctx.fillStyle = "rgb(0, 0, 255)";
ctx.fill();
ctx.closePath();
}
// Definitions
let particleFactory = new ParticleFactory;
function draw(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
particleFactory.draw();
}
function tick(){
particleFactory.tick();
draw()
window.requestAnimationFrame(tick)
}
document.addEventListener("DOMContentLoaded", function() {
tick();
});
ctx.clearRect() doesn't clear the curcle that is being draws every tick by Particle.draw()
The dot moves and leaves a trail behind even when ctx.clearRect() is run before every draw.

HTML5 loop of a array of objects

I'm trying to make a grid that when clicking in a square it turns green, but i keep having trouble with adding objects to my array, if there preset they display fine but if add them once i click my mouse they wont render.
var canvas = document.getElementById("ctx");
var ctx = canvas.getContext("2d");
var Img = {};
Img.tileMap = new Image();
Img.tileMap.src = 'TitleMap.png';
WIDTH = 1536;
HEIGHT = 896;
currentImage = [32, 32];
ctx.strokeStyle = '#ffffff';
function createGrid() {
ctx.strokeStyle = '#ffffff'
for (var i = 0; i < WIDTH; i++) {
ctx.beginPath();
ctx.moveTo(i * 32, 0);
ctx.lineTo(i * 32, HEIGHT);
ctx.stroke();
}
for (var i = 0; i < HEIGHT; i++) {
ctx.beginPath();
ctx.moveTo(0, i * 32);
ctx.lineTo(1536, i * 32);
ctx.stroke();
}
}
var tiles = [{
x: 1,
y: 1
}];
var mousePos = null;
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: Math.round((evt.clientX - rect.left) / (rect.right - rect.left) *
canvas.width),
y: Math.round((evt.clientY - rect.top) / (rect.bottom - rect.top) *
canvas.height)
};
}
canvas.addEventListener('mousemove', function(evt) {
mousePos = getMousePos(canvas, evt);
}, false);
document.body.onmousedown = function() {
pos = {
x: Math.floor(mousePos.x / 32),
y: Math.floor(mousePos.y / 32),
};
tiles.push(pos);
}
function drawTiles() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
createGrid();
if (tiles.length) {
for (var id in tiles) {
ctx.fillStyle = "#42f456";
ctx.strokeStyle = '#42f456';
ctx.fillRect(tiles[id].x, tiles[id].y, 32, 32);
}
}
}
setInterval(drawTiles(), 1000 / 30);
<center>
<canvas id="ctx" width="1536" height="896" style="border:1px solid #ffffff;">
</canvas>
</center>
You were doing your setInterval wrong-- you want to pass the function, not call it-- otherwise whatever the function returns is what is passed to setInterval.
<body bgcolor="#000000">
<center><canvas id="ctx" width="1536" height="896" style="border:1px solid #ffffff;">
</canvas></center>
<script>
var canvas = document.getElementById("ctx");
var ctx = canvas.getContext("2d");
var Img = {};
Img.tileMap = new Image();
Img.tileMap.src = 'TitleMap.png';
WIDTH = 1536;
HEIGHT = 896;
currentImage = [32,32];
ctx.strokeStyle = '#ffffff';
function createGrid(){
ctx.strokeStyle = '#ffffff'
for (var i = 0 ; i < WIDTH; i++){
ctx.beginPath();
ctx.moveTo(i*32,0);
ctx.lineTo(i*32,HEIGHT);
ctx.stroke();
}
for (var i = 0 ; i < HEIGHT; i++){
ctx.beginPath();
ctx.moveTo(0,i*32);
ctx.lineTo(1536,i*32);
ctx.stroke();
}
}
var tiles = [{x:1,y:1}];
var mousePos = null;
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: Math.round((evt.clientX-rect.left)/(rect.right-rect.left)*canvas.width),
y: Math.round((evt.clientY-rect.top)/(rect.bottom-rect.top)*canvas.height)
};
}
canvas.addEventListener('mousemove', function(evt) {
mousePos = getMousePos(canvas, evt);
}, false);
document.body.onmousedown = function() {
pos = {
x:Math.floor(mousePos.x/32),
y:Math.floor(mousePos.y/32),
};
tiles.push(pos);
}
function drawTiles(){
ctx.clearRect(0,0,WIDTH,HEIGHT);
createGrid();
if(tiles.length){
for (var id in tiles){
ctx.fillStyle = "#42f456";
ctx.strokeStyle = '#42f456';
ctx.fillRect(tiles[id].x,tiles[id].y,32,32);
}
}
}
setInterval(drawTiles,1000/30);
</script>
</body>
Also, a few quick notes-- you're playing fast and loose with your var statements-- make sure if you don't want a variable to be global you declare it with a var. And also note that for...in loops are for iterating over object keys-- to iterate over an array, use a standard for loop. And finally, consider if a setInterval is even required-- seems like it might be sufficient to simply call drawTiles in the onmousedown after you push the new position into the tiles array.

Setting up canvas background animation

I'm trying to set up a background in canvas and have some small circles just flow throughout the background, eventually I'll change the shapes and add more details in, but I'm just having trouble with the set up.
I know my code is janky, but are there any suggestions to the structure of the code?
var dx = 1;
var dy = 2;
var circle=new Circle(400,30,10);
var timer;
function Circle(x,y,r){
this.x=x;
this.y=y;
this.r=r;
}
function init() {
// Get the canvas element.
canvas = document.getElementById("canvas");
if (canvas.getContext) {
ctx = canvas.getContext("2d");
ctx.fillStyle = "black";
}
timer=setInterval(draw, 10);
return timer;
}
function gradient (){
var my_gradient=ctx.createLinearGradient(0,0,1000,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(1,"white");
ctx.fillStyle=my_gradient;
ctx.fillRect(0,0,1000,1000);
ctx.rect(0, 0, 1000, 1000);
stars();
}
function stars(){
for (i = 0; i <= 50; i++) {
// Get random positions for stars
var x = Math.floor(Math.random() * 1000)
var y = Math.floor(Math.random() * 1000)
ctx.fillStyle = "yellow";
//if (x < 30 || y < 30) ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
}
function move(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = gradient.my_gradient;
ctx.fillRect(0,0,canvas.width,canvas.height);
ctx.fillStyle = "#003300";
drawBall(circle);
if (circle.x +dx > canvas.width || circle.x +dx < 0)
dx=-dx;
if(circle.y+dy>bar.y && circle.x>bar.x && circle.x<bar.x+barImg.width)
dy=-dy;
if (circle.y +dy > canvas.height || circle.y +dy < 0)
dy=-dy;
circle.x += dx;
circle.y += dy;
}
I tried to code a working exemple. Here stars are popping up continuously.
HTML
<!DOCTYPE html>
<html>
<head>
<title>Exemple</title>
</head>
<body>
<canvas id="viewport"></canvas>
<script src='test.js'></script>
</body>
</html>
JS
var doc = document;
var canvas = doc.getElementById('viewport');
var ctx = canvas.getContext('2d');
var settings = {
area : {
height : 100,
width : 100
}
};
canvas.width = settings.area.width;
canvas.height = settings.area.height;
function draw() {
for (var i = 10; i--;) {
var x = Math.floor(Math.random() * 1000)
var y = Math.floor(Math.random() * 1000)
ctx.beginPath();
ctx.arc(x, y, 3, 0, Math.PI * 2, true);
ctx.fillStyle = "yellow";
ctx.closePath();
ctx.fill();
}
}
function gameLoop (render, element) {
var running, lastFrame = +new Date;
function loop( now ) {
// stop the loop if render returned false
if ( running !== false ) {
requestAnimationFrame( loop, element );
running = render( now - lastFrame );
lastFrame = now;
}
}
loop( lastFrame );
}
gameLoop (function (deltaT) {
draw();
}, canvas );
Here is the fiddle : https://jsfiddle.net/q4q0uLht/
----- EDIT -----
/*
Basic config
*/
var doc = document,
canvas = doc.getElementById('viewport'),
ctx = canvas.getContext('2d');
var settings = {
canvas: {
height: 200,
width: 300
}
}
canvas.height = settings.canvas.height;
canvas.width = settings.canvas.width;
canvas.style.border = '1px #000 solid';
/*
easy gets a random number, inside a range of [0, x);
*/
function getRandomNumber(x) {
return parseInt(Math.random() * x, 10);
}
/*
Checks if the obj passed in argument is still in the canvas limits
*/
function incorrectPosition(obj) {
return obj.x < 0 || obj.y < 0 || obj.x > settings.canvas.width || obj.y > settings.canvas.height;
}
/*
stars array and Star object.
*/
var stars = [];
function Star(r) {
this.x = getRandomNumber(canvas.width);
this.y = getRandomNumber(canvas.height);
this.r = r || 10;
this.move = function(dx, dy) {
this.x += dx;
this.y += dy;
};
}
/*
This function adds new stars,
calculates new coordinates of each star,
and removes them from the stars array
when they are out of the canvas limits.
*/
function update() {
var len = stars.length;
if (len < 10) {
stars.push(new Star());
}
for (var i = len; i--;) {
var star = stars[i];
star.move(1, 2);
if (incorrectPosition(star)) {
stars.splice(i, 1);
}
}
}
/*
This function clears the canvas each turn and
draws each star which is stored inside the stores array.
*/
function draw() {
ctx.clearRect(0, 0, settings.canvas.width, settings.canvas.height);
var len = stars.length;
for (var i = len; i--;) {
var star = stars[i];
ctx.beginPath();
ctx.arc(star.x, star.y, 3, 0, Math.PI * 2, true);
ctx.fillStyle = "yellow";
ctx.closePath();
ctx.fill();
}
}
// Here is the loop inside which are called functions
setInterval(loop, 33);
function loop() {
update(); // update first
draw(); // then draw
}
<!DOCTYPE html>
<html>
<head>
<title>Exemple</title>
</head>
<body>
<canvas id="viewport"></canvas>
<script src='test.js'></script>
</body>
</html>

How to make all drawn (rectangle, circles, lines, polygon) draggable? Pure JS

I have a simple paint canvas html5. Its can draw through a selection option some shapes like lines, circles, rectangles, polygon, but now i want to make all draws draggable if possible resizable, without 3 part library only pure JS.
var canvas,
context,
dragStartLocation,
snapshot;
dragdrop = false;
isDrag = false;
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
function getCanvasCoordinates(event) {
var x = event.clientX - canvas.getBoundingClientRect().left;
y = event.clientY - canvas.getBoundingClientRect().top;
return {x: x, y: y};
}
function takeSnapshot() {
snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
function restoreSnapshot() {
context.putImageData(snapshot, 0, 0);
}
function drawLine(position) {
context.beginPath();
context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.lineTo(position.x, position.y );
context.stroke();
}
function drawRect(position) {
context.beginPath();
//context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.fillRect(position.x, position.y, dragStartLocation.x - position.x, dragStartLocation.y - position.y);
//context.stroke();
}
function drawCircle(position) {
var radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2));
context.beginPath();
context.arc(dragStartLocation.x, dragStartLocation.y, radius, 0, 2 * Math.PI, false);
}
/*
function drawPolygon(position, sides, angle) {
var coordinates = [],
radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2)),
index = 0;
for (index = 0; index < sides; index++) {
coordinates.push({x: dragStartLocation.x + radius * Math.cos(angle), y: dragStartLocation.y - radius * Math.sin(angle)});
angle += (2 * Math.PI) / sides;
}
context.beginPath();
context.moveTo(coordinates[0].x, coordinates[0].y);
for (index = 1; index < sides; index++) {
context.lineTo(coordinates[index].x, coordinates[index].y);
}
context.closePath();
}*/
function draw(position) {
var fillBox = document.getElementById("fillBox"),
shape = document.querySelector('#tools option:checked').value,
/*polygonSides = document.getElementById("polygonSides").value,
polygonAngle = document.getElementById("polygonAngle").value,*/
lineCap = document.querySelector('input[type="radio"][name="lineCap"]:checked').value;
/*composition = document.querySelector('input[type="radio"][name="composition"]:checked').value;*/
context.lineCap = lineCap;
/*context.globalCompositeOperation = composition;*/
if (shape === "circle") {
drawCircle(position);
}
if (shape === "line") {
drawLine(position);
}
if (shape === "rect") {
drawRect(position);
}
if (shape === "polygon") {
drawPolygon(position, polygonSides, polygonAngle * (Math.PI / 180));
}
if (shape !== "line") {
if (fillBox.checked) {
context.fill();
} else {
context.stroke();
}
}
}
function dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
takeSnapshot();
}
function drag(event) {
var position;
if (dragging === true) {
restoreSnapshot();
position = getCanvasCoordinates(event);
draw(position);
}
}
function dragStop(event) {
dragging = false;
restoreSnapshot();
var position = getCanvasCoordinates(event);
draw(position);
}
function changeLineWidth() {
context.lineWidth = this.value;
event.stopPropagation();
}
function changeFillStyle() {
context.fillStyle = this.value;
event.stopPropagation();
}
function changeStrokeStyle() {
context.strokeStyle = this.value;
event.stopPropagation();
}
function changeBackgroundColor() {
context.save();
context.fillStyle = document.getElementById("backgroundColor").value;
context.fillRect(0, 0, canvas.width, canvas.height);
context.restore();
}
function eraseCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
function init() {
canvas = document.getElementById("canvas");
context = canvas.getContext('2d');
var lineWidth = document.getElementById("lineWidth"),
fillColor = document.getElementById("fillColor"),
strokeColor = document.getElementById("strokeColor"),
//canvasColor = document.getElementById("backgroundColor"),
clearCanvas = document.getElementById("clearCanvas");
//saveCanvas = document.getElementById("saveCanvas");
context.strokeStyle = strokeColor.value;
context.fillStyle = fillColor.value;
context.lineWidth = lineWidth.value;
/*window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
resizeCanvas();*/
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
lineWidth.addEventListener("input", changeLineWidth, false);
fillColor.addEventListener("input", changeFillStyle, false);
strokeColor.addEventListener("input", changeStrokeStyle, false);
//canvasColor.addEventListener("input", changeBackgroundColor, false);
clearCanvas.addEventListener("click", eraseCanvas, false);
//saveCanvas.addEventListener("click", salvaCanvas, false);
}
window.addEventListener('load', init, false);
It is an essential feature of canvas that it stores only the raster image formed as a result of all the draw operations. This why canvas is fast and memory efficient.
The downside is that you have to erase the affected rectangle on the canvas (or the whole canvas in the worst case) and redraw all the shapes that need to be resized, moved, etc. The canvas does not store them as objects, so your JS code must take care of storing, modifying and re-drawing them on the canvas. The effort is substantial unless you use some third party library.
The alternative is to use SVG-like features of HTML5 instead of canvas: <line>, <path>, <rect>, etc. They are kept as objects by the browser and accessible via DOM. This is a totally different approach, however, and requires a full rewrite of your code.

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