Drawing a parallelogram HTML5 Canvas - javascript

I am new to Javascript and Canvas of HTML5. I have to complete a project where I have to draw a parallelogram with three mouse clicks.
Click 1: Starts the first line of the parallelogram.
Click 2: Ends of the first line.
Click 3: When the user drags the mouse up or down from the second click point, a line should be drawn from the second click point along the mouse move and at the same time a third line should be drawn from the first click point parallel to the second line.Upon the third click on the canvas the parallelogram should be complete i.e, a line should be drawn from the second line to the third line.
I am stuck on Click 3. While I conceptually understand how this needs to be done...for the last one week...I could not do much headway. The following is my code:
var canvas, context;
var dragging = false;
var dragStartLocation;
var dragStopLocation;
var dragThirdLocation;
var beginFourthLine;
var snapshot;
var pointsNum;
//Get mouse click coordinates
function getCanvasCoordinates(event) {
var x = event.clientX - canvas.getBoundingClientRect().left;
var y = event.clientY - canvas.getBoundingClientRect().top;
return {
x: x,
y: y
};
}
//save the canvas original state
function takeSnapShot() {
snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
//restore the canvas original state
function restoreSnapShot() {
context.putImageData(snapshot, 0, 0);
}
//draw a point on mouse click
function drawPoint(position) {
context.beginPath();
context.lineWidth = 3;
context.strokeStyle = '#f4d03f';
context.arc(position.x, position.y, 5.5, 0, Math.PI * 2, false);
context.stroke();
}
//draw a line on mouse move
function drawLine(position) {
context.beginPath();
context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.lineTo(position.x, position.y);
context.stroke();
}
//start the event with first mouse click
function dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
drawPoint(dragStartLocation);
console.log(dragStartLocation.x, dragStartLocation.y);
takeSnapShot();
}
//draw a line along with the mouse move from the first click
function drag(event) {
var position;
if (dragging === true) {
restoreSnapShot();
position = getCanvasCoordinates(event);
drawLine(position);
}
}
//draw the third and fourth coordinates - this is where I am stuck
function drawThirdCoord(event) {
dragging = true;
var beginFourthLine = dragStopLocation.x - dragStartLocation.x;
restoreSnapShot();
dragThirdLocation = getCanvasCoordinates(event);
drawLine(event);
drawLine(beginFourthLine);
}
//stop the mouse movement and drawing line.
function dragStop(event) {
dragging = false;
restoreSnapShot();
var position = getCanvasCoordinates(event);
dragStopLocation = position;
drawLine(position);
drawPoint(position);
console.log(dragStopLocation.x, dragStopLocation.y);
drawThirdCoord(event);
}
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
context.strokeStyle = 'green';
context.lineWidth = 6;
context.lineCap = "round";
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
}
window.addEventListener('load', init, false);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="600" style="border:solid 1px;margin:0;padding:0;"></canvas>
<p id="status"> | </p>

I'm not sure how the mouse drag should work, so I tried to keep the code as close to the question as possible. So you need to drag the first line then just click to end the shape.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>parallelogram</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<canvas id="canvas" width="800" height="600" style="border:solid 1px;margin:0;padding:0;"></canvas>
<p id="status"> | </p>
</body>
</html>
<script type="text/javascript">
var canvas, context;
var dragging = false;
var startLocation;
var dragStartLocation;
var dragStopLocation;
var dragThirdLocation;
var snapshot;
var pointsNum = 0;
var d = {x:0, y:0};
//Get mouse click coordinates
function getCanvasCoordinates(event) {
var x = event.clientX - canvas.getBoundingClientRect().left;
var y = event.clientY - canvas.getBoundingClientRect().top;
return {x: x, y: y};
}
//save the canvas original state
function takeSnapShot() {
snapshot = context.getImageData(0,0,canvas.width, canvas.height);
}
//restore the canvas original state
function restoreSnapShot() {
context.putImageData(snapshot,0,0);
}
//draw a point on mouse click
function drawPoint(position) {
context.beginPath();
context.arc(position.x, position.y, 5.5, 0, Math.PI * 2, false);
context.stroke();
}
//draw a line on mouse move
function drawLine(start, end) {
context.beginPath();
context.moveTo(start.x, start.y);
context.lineTo(end.x, end.y);
context.stroke();
}
//start the event with first mouse click
function dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
drawPoint(dragStartLocation);
pointsNum++;
takeSnapShot();
if (pointsNum == 1) startLocation = dragStartLocation;
}
//draw a line along with the mouse move from the first click
function drag(event) {
var position;
if (snapshot && pointsNum && pointsNum < 3) {
restoreSnapShot();
position = getCanvasCoordinates(event);
drawLine(dragStartLocation, position);
drawPoint(position);
if (pointsNum == 2) drawFourthCoord(position)
}
}
//stop the mouse movement and drawing line.
function dragStop(event) {
dragging = false;
restoreSnapShot();
var position = getCanvasCoordinates(event);
dragStopLocation = position;
drawPoint(dragStopLocation);
pointsNum++;
drawLine(dragStartLocation, dragStopLocation);
takeSnapShot();
d = {
x: dragStartLocation.x - dragStopLocation.x,
y: dragStartLocation.y - dragStopLocation.y
};
dragStartLocation = position;
if (pointsNum > 3) pointsNum =0;
}
//draw the fourth coordinate
function drawFourthCoord(position) {
var p = {
x: position.x + d.x,
y: position.y + d.y
};
drawLine(position, p);
drawPoint(p);
drawLine(startLocation, p);
}
function init() {
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
context.lineCap = "round";
context.lineWidth = 3;
context.strokeStyle = '#f4d03f';
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
}
window.addEventListener('load', init, false);
</script>

Related

Executing Javascript File On Click

This is a javascript code to draw lines on canvas.
var canvas,
context,
dragging = false,
dragStartLocation,
snapshot;
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 dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
takeSnapshot();
}
function drag(event) {
var position;
if (dragging === true) {
restoreSnapshot();
position = getCanvasCoordinates(event);
drawLine(position);
}
}
function dragStop(event) {
dragging = false;
restoreSnapshot();
var position = getCanvasCoordinates(event);
drawLine(position);
}
function init() {
canvas = document.getElementById("canvas");
context = canvas.getContext('2d');
context.strokeStyle = 'black';
context.lineWidth = 6;
context.lineCap = 'round';
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
}
How can i add a button to this so that when the button clicked the code get executed? How can i do this? An example is given below to clarify the thing
<input type="BUTTON" value="Exit" onclick="execute the javascript file to draw line" >
first of all, you need to include the js file in your html :
<script src='file.js'></script>
then, you can execute the init() function onclick :
<input type="BUTTON" value="Exit" onclick="init()" >
First, I would use the "button" tag instead of "input" for better semantics.
Second, give the button an "onclick" parameter and set it equal to your "init" function.
<button name="draw-line" onclick="init()"

My mousedown function isn't drawing lines from the most recent point, but instead from the top left corner

http://codepen.io/PartTimeCoder/pen/qZJdPW?editors=0010
This is the link to my CodePen.
My HTML and the CSS are working fine. But the JavaScript isn't working the way I want it to. It should draw a line from the last point you clicked at.
The JavaScript is below -
var randomColor = function() {
return '#' + Math.random().toString(16).slice(2, 8);
}
var canvas = document.getElementById("canvas")
var ctx = canvas.getContext("2d")
color = randomColor();
var height = window.innerHeight
var width = window.innerWidth
canvas.width = width
canvas.height = height
var mouse = {};
var circle_count = 10;
var circles = [];
var generate = function() {
for (var i = 0; i < circle_count; i++) {
circles.push(new circle());
}
}
setInterval(generate, 7500);
canvas.addEventListener('mousedown', mousePos, false);
canvas.addEventListener('touch', mousePos, false);
function mousePos(e) {
mouse.x = e.pageX;
mouse.y = e.pageY;
}
canvas.addEventListener("mousedown", function() {
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
});
You need to save last clicked position before apply new one as on example:
codepen.io/themeler/pen/XdxboL?editors=0010
Each mousedown event calls ctx.moveTo(0, 0), which positions it in the upper left.
Move this code out of your mousedown event, and it works fine:
ctx.beginPath();
ctx.moveTo(0, 0);
CodePen
Change the mouse variable to set your starting point
var mouse = {x : 0, y : 0};
and then the event handler to update the mouse variable to the latest point
canvas.addEventListener('touch', stuff);
canvas.addEventListener("mousedown", stuff);
function stuff(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
ctx.lineTo(e.pageX, e.pageY);
ctx.stroke();
mouse = {x: e.pageX, y: e.pageY};
}
FIDDLE

Drawing a rectangle on Canvas

I am trying to create a simple canvas program where the user can consistently create new shapes. This one is just a basic rectangle creator (I am hoping to expand it more to circles, lines, and maybe even other stuff). Right now though I have created something that is working in a really weird way.
<html>
<head>
<meta chartset="utf-8">
<title>Dragging a square</title>
<script type="text/javascript">
var canvas, context, startX, endX, startY, endY;
var mouseIsDown = 0;
function init() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
document.body.addEventListener("mouseup", mouseUp, false);
}
function mouseUp() {
mouseIsDown = 0;
//mouseXY();
}
function mouseDown() {
mouseIsDown = 1;
startX = event.clientX;
startY = event.clientY;
mouseXY();
}
function mouseXY(eve) {
if (!eve) {
var eve = event;
}
endX = event.pageX - canvas.offsetLeft;
endY = event.pageY - canvas.offsetTop;
drawSquare();
}
function drawSquare() {
// creating a square
var width = Math.abs(startX - endX);
var height = Math.abs(startY - endY);
context.beginPath();
context.rect(startX, startY, width, height);
context.fillStyle = "yellow";
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
}
</script>
</head>
<body onload="init()">
<canvas id="canvas" width="400" height="400" style="border: 1px solid black; cursor: pointer;"></canvas>
</body>
</html>
Sorry about the slightly weird formatting when I copy and pasted my code. I think the problem is my mouseXY function. What I want is the user to click somewhere on the canvas a drag the mouse to create a rectangle, when the user lets go that is the end of that operation and they can create a whole new rectangle right after. At this point the program kind of just lets me click and create a new rectangle but if I let go of the mouse button it doesn't stop, in fact I have to click again to make it stop which then creates a new rectangle. I am still very new to this and I am having a lot of trouble with this, I will continue to work on this and if I figure it out I will let the site know. Thank you and have a great day!
Well I got this to work (thanks to #Ken) but now I am trying to solve a new problem. I want to be able to put multiple rectangles on the canvas. I created a function that represents the Rectangle and then created a draw function within the rectangle function to draw out a rectangle. I created a new function called addShape() that ideally creates the rectangle object and pushes into an array called square and drawShapes() that is supposed to erase everything on the canvas and redraws everything. Here is what I have so far:
<html>
<head>
<meta chartset="utf-8">
<title>Dragging a square</title>
<script type="text/javascript">
function Rectangle(canvas, x, y, width, height,color) {
//this.context = canvas.getContext("2d");
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.draw = function() {
this.context.globalAlpha = 0.85;
this.context.beginPath();
this.context.rect(this.x, this.y, this.width, this.height);
this.context.fillStyle = this.color;
this.context.strokeStyle = "black";
this.context.lineWidth = 1;
this.context.fill();
this.context.stroke();
};
};
// hold the canvas and context variable, as well as the
// starting point of X and Y and the end ones
var canvas, context, startX, endX, startY, endY;
var mouseIsDown = 0;
// An array that holds all the squares
var squares = [];
window.onload = function() {
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
canvas.addEventListener("mouseup", mouseUp, false);
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//Square(); //update on mouse-up
addShape(); // Update on mouse-up
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
// Square(); //update
addShape();
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//Square();
addShape();
}
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function addShape() {
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
var s = new Rectangle(startX + offsetX, startY + offsetY, width, height, "yellow");
squares.push(s);
// Update the display
drawShapes();
}
function drawShapes() {
context.clearRect(0,0,canvas.width,canvas.height);
for (var i = 0; i < squares.length; i++) {
var shape = squares[i];
shape.draw();
};
}
function clearCanvas() {
squares = [];
drawShapes();
}
</script>
</head>
<body onload="addShape()">
<canvas id="canvas" width="400" height="400" style="border: 1px solid black; cursor: pointer;"></canvas><br>
<button onclick="clearCanvas()">Clear Canvas</button>
</body>
</html>
I am pretty sure I broke the original code... thank you for any help!
You need to modify a couple of things in the code: (edit: there are many issues with this code. I went through some of them inline here, but haven't tested. If you put it in a fiddle it's easier for us to check)..
Fiddle
When mouse down occur initialize both start and end points. Call a common draw function that is not dependent on the event itself:
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
drawSquare(); //update
}
At mouse up, only register if isMouseDown is true, else this function will handle all incoming up-events (as you have attatched it to document, which is correct - window could have been used too):
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare(); //update on mouse-up
}
}
Only draw if mouseisdown is true:
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare();
}
}
In addition you will need to clear the previous area of the rectangle before drawing a new or else it won't show when you draw a bigger rectangle and then move the mouse back to draw a smaller one.
For simplicity you can do:
function drawSquare() {
// creating a square
var width = Math.abs(startX - endX);
var height = Math.abs(startY - endY);
context.clearRect(0, 0, context.width, context.height);
//or use fillRect if you use a bg color
context.beginPath();
context.rect(startX, startY, width, height);
context.fillStyle = "yellow";
context.fill();
context.lineWidth = 7;
context.strokeStyle = 'black';
context.stroke();
}
Use this for mouse position:
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}

Image appear at mouse location

I am trying to make an image appear to the location of the mouse coordinates when I click the canvas.
Right now I have it appearing, but I can only figure out how to do it with automatic updating coordinates and the image will follow the mouse after an "onclick".
I need to make it so the image will just move to the location I click, not follow the cursor.
<!DOCTYPE html>
<html lang="en">
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<title>Click to make a sad face</title>
</head>
<body>
<canvas id="myCanvas" width="2000" height="1000", onClick="makeface();"></canvas>
<script type="text/javascript">
function writeMessage(canvas, message) {
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.font = '18pt Calibri';
ctx.fillStyle = 'black';
ctx.fillText(message, 10, 25);
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
canvas.addEventListener('mousemove', function(evt)
{
var mousePos = getMousePos(canvas, evt);
var message = 'Click to make a face appear at coordinates: ' + mousePos.x + ',' + mousePos.y;
writeMessage(canvas, message);
}, false);
function makeface()
{
canvas.addEventListener('mousemove', function(evt)
{
var mousePos2 = getMousePos(canvas, evt);
var headx = mousePos2.x;
var heady = mousePos2.y;
var message = 'You made the face appear, you are currently at coordinates: ' + mousePos2.x + ',' + mousePos2.y;
writeMessage(canvas, message);
var headrad = 50;
var smileoffsetx=0;
var frownoffsety = 33;
var smilerad=20;
var eyeoffsety = -10;
var lefteyeoffsetx = -15;
var righteyeoffsetx = -lefteyeoffsetx;
var eyerad = 8;
ctx.strokeStyle="blue";
ctx.lineWidth = 5;
ctx.beginPath();
ctx.arc(headx,heady,headrad,0,2*Math.PI,true);
ctx.closePath();
ctx.stroke();
ctx.beginPath()
ctx.arc(headx+smileoffsetx,heady+frownoffsety,smilerad,-.20*Math.PI,-.80*Math.PI,true);
ctx.stroke();
ctx.beginPath()
ctx.arc(headx+lefteyeoffsetx,heady+eyeoffsety,eyerad,0,2*Math.PI,true);
ctx.fillStyle="blue";
ctx.fill();
ctx.beginPath()
ctx.arc(headx+righteyeoffsetx,heady+eyeoffsety,eyerad,0,2*Math.PI,true);
ctx.fill();
}, false);
}
</script>
</body>
</html>
This is happening because your writeMessage function is clearing the entire canvas.
This is my quick and dirty fix:
<canvas id="myCanvas" width="2000" height="1000" onClick="document.madeFace = 0; makeface();"></canvas>
...
function makeface()
{
canvas.addEventListener('mousemove', function(evt)
{
var mousePos2 = getMousePos(canvas, evt);
document.madeFace = document.madeFace || mousePos2; /* added */
var message = 'You made the face appear, you are currently at coordinates: ' + mousePos2.x + ',' + mousePos2.y;
mousePos2 = document.madeFace; /* added */
var headx = mousePos2.x;
var heady = mousePos2.y;
...
What this code does is to store the coordinates of the face as soon as the user has clicked. When the user clicks again, the variable "document.madeFace" is reset to 0 and so the coordinates of the face are re-calculated.
But the face is still re-drawn every time the mouse moves, and so it will still appear even though the entire canvas gets cleared.
This is what to do to make it happen exactly onclick instead of after onclick.
Put this variable outside of the function:
var faceHandler = function(evt)
{
var mousePos2 = getMousePos(canvas, evt);
document.madeFace = document.madeFace || mousePos2;
... until the end of the function, i.e., the curly brace that is now in the line that looks like this:
}, false);
Then register the onclick outside the function and the mousemove inside the function:
canvas.addEventListener('click', faceHandler, false);
function makeface()
{
canvas.addEventListener('mousemove', faceHandler, false);
}

Canvas mouse event and focus

I have 2 circles and one line. The circles have a move option (u can press them and move). Mousemove event have a variable distance to calculate the distance between mouse and the circle.
The problem is, that when you move one circle to another close enough, they will join. How to avoid that? Is there an option to make some focus or something like that? Any ideas how to fix that (is it possible?)
My code:
var canvas = document.getElementById('myCanvas'),
context = canvas.getContext('2d'),
radius = 12,
p = null,
start = false;
point = {
p1: { x:100, y:250 },
p2: { x:400, y:100 }
}
function init() {
return setInterval(draw, 10);
}
canvas.addEventListener('mousedown', function(e) {
start = true;
});
canvas.addEventListener('mouseup', function(e) {
start = false;
});
canvas.addEventListener('mousemove', function(e) {
for (p in point) {
if(start) {
var
mouseX = e.clientX -10,
mouseY = e.clientY -10,
distance = Math.sqrt(Math.pow(mouseX - point[p].x, 2) + Math.pow(mouseY - point[p].y, 2));
if (distance -10<= radius) {
point[p].x = e.clientX -10 ;
point[p].y = e.clientY -10 ;
}
}
}
});
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.moveTo(point.p1.x,point.p1.y);
context.lineTo(point.p2.x,point.p2.y);
context.closePath();
context.fillStyle = '#8ED6FF';
context.fill();
context.stroke();
for (p in point) {
context.beginPath();
context.arc(point[p].x,point[p].y,radius,0,2*Math.PI);
context.fillStyle = 'red';
context.fill();
context.stroke();
}
context.closePath();
}
init();
​
Try to save which point was pressed in your mousedown event.
Like that: http://jsfiddle.net/cs5Sg/9/
In addition, it will not calculate the distance to each point every time the mouse moves so it will be faster.

Categories

Resources