Image appear at mouse location - javascript

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);
}

Related

Drawing a straight line using mouse events inside a div using JavaScript

This code is work proper in canvas but I want to do this inside a div tag not in canvas.
var canvasWidth = 180;
var canvasHeight = 160;
var canvas = null;
var bounds = null;
var ctx = null;
var hasLoaded = false;
var startX = 0;
var startY = 0;
var mouseX = 0;
var mouseY = 0;
var isDrawing = false;
var existingLines = [];
function draw() {
ctx.fillStyle = "#333333";
ctx.fillRect(0, 0, canvasWidth, canvasHeight);
ctx.strokeStyle = "black";
ctx.lineWidth = 2;
ctx.beginPath();
for (var i = 0; i < existingLines.length; ++i) {
var line = existingLines[i];
ctx.moveTo(line.startX, line.startY);
ctx.lineTo(line.endX, line.endY);
}
ctx.stroke();
if (isDrawing) {
ctx.strokeStyle = "darkred";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
ctx.stroke();
}
}
function onmousedown(e) {
if (hasLoaded && e.button === 0) {
if (!isDrawing) {
startX = e.clientX - bounds.left;
startY = e.clientY - bounds.top;
isDrawing = true;
}
draw();
}
}
function onmouseup(e) {
if (hasLoaded && e.button === 0) {
if (isDrawing) {
existingLines.push({
startX: startX,
startY: startY,
endX: mouseX,
endY: mouseY
});
isDrawing = false;
}
draw();
}
}
function onmousemove(e) {
if (hasLoaded) {
mouseX = e.clientX - bounds.left;
mouseY = e.clientY - bounds.top;
if (isDrawing) {
draw();
}
}
}
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
canvas.onmousedown = onmousedown;
canvas.onmouseup = onmouseup;
canvas.onmousemove = onmousemove;
bounds = canvas.getBoundingClientRect();
ctx = canvas.getContext("2d");
hasLoaded = true;
draw();
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
position: absolute;
margin: auto;
left: 0;
right: 0;
border: solid 1px white;
border-radius: 10px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="drawBoard">
<!--I want to draw here-->
</div>
</body>
</html>
Above code is fine , But i want to draw line inside a div(direct on document page) not in canvas. I don't have any idea to do this. please help me to do this or refer me some article on this.
I dont have idea even how can i start. Please refer me some related answer.
First of all, let me apologyze for my enlgish, i'll try my best to explain!
You may be interested on using "SVG" lines for this purpose https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg since you can draw lines easly.
To acomplish this, you will need and SVG container, here you can find some information about how it works -> https://www.w3schools.com/html/html5_svg.asp
Once you have the container, you need to create and move lines inside using javascript, to do so, you need the following code:
//To create 1
document.createElementNS('http://www.w3.org/2000/svg','line');
//To select 1
document.querySelector('#nameOfTheLine')
//To change its position
line.setAttribute('x1',x1);
line.setAttribute('y1',y1);
line.setAttribute('x2',x2);
line.setAttribute('y2',y2);
//To change its stroke so you can see it:
line.setAttribute("stroke", "color")
i'll give you this example that i made, its not the best but i hope you will find it usefull!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
#canvas{
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="border">
<svg id="canvas" width="500" height="400">
</svg>
</div>
<script>
/*Store the "svg" item in a variable */
const canvas = document.querySelector('#canvas');
//Class to store the position
class Vector2D{
constructor(x,y){
this.x = x;
this.y = y;
}
}
//Variables that will store the initial and final position of the line before its drawn.
let initialPosOfLine;
let finalPosOfLine;
//Variable to store the stage of the canvsa, if the user its drawing or not.
let drawingOverCanvas = false;
//Variable to store the current index of the line
let lineIndex = 0;
// Code that will be executed once the user click with the mouse in the svg.
canvas.addEventListener('mousedown', event => {
//If we are drawing, do nothing.
if(drawingOverCanvas) return;
/*Calculate position relative to div -- Done by https://stackoverflow.com/questions/3234256/find-mouse-position-relative-to-element */
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left; //x position within the element.
var y = event.clientY - rect.top; //y position within the element.
//Change the variable drawingOverCanvas to true since now we are drawing
drawingOverCanvas = true;
//Store the mouse position over the div as the initialPos;
initialPosOfLine = new Vector2D(x , y);
//draw a line at the starting point;
drawToPos(initialPosOfLine, initialPosOfLine, 'line'+lineIndex , false);
});
// Code that will be executed once the user click with the mouse in the svg.
canvas.addEventListener('mouseup', event => {
//If we are not drawing, do nothing.
if(!drawingOverCanvas) return;
//Set the varible to "false" as we are not drawing now.
drawingOverCanvas = false;
/*Calculate position relative to div -- Done by https://stackoverflow.com/questions/3234256/find-mouse-position-relative-to-element */
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left; //x position within the element.
var y = event.clientY - rect.top; //y position within the element.
//Store the final position as a vector.
finalPosOfLine = new Vector2D(x, y);
//Set the line to its correct position
drawToPos(initialPosOfLine, finalPosOfLine, 'line'+lineIndex , true);
//Increse the index of the line for the next one.
lineIndex++;
});
//Draw the line when the user move the mouse
canvas.addEventListener('mousemove', event => {
//if we are not drawing, do nothing.
if(!drawingOverCanvas) return;
/*Calculate position relative to div -- Done by https://stackoverflow.com/questions/3234256/find-mouse-position-relative-to-element */
var rect = canvas.getBoundingClientRect();
var x = event.clientX - rect.left; //x position within the element.
var y = event.clientY - rect.top; //y position within the element.
//Store the mouse position as the "final" position
finalPosOfLine = new Vector2D(x, y);
//Draw a line from the initialPos to the current Mouse pos.
drawToPos(initialPosOfLine, finalPosOfLine, 'line'+lineIndex , true);
});
//Draw a line between 2 points, if move its true, it will move the line instead of making it
function drawToPos(initial, final, id, move){
//Declare a new Line in SVG
var line = document.createElementNS('http://www.w3.org/2000/svg','line');
//If we are moving and existent line, set "line" to the current line, else, give to the new line the id attribute.
if(move){ line = document.querySelector('#'+id) } else { line.setAttribute('id',id) };
// If we are creating a new line, define its initial position
if(!move) line.setAttribute('x1',initial.x);
if(!move) line.setAttribute('y1',initial.y);
//Define its final position
line.setAttribute('x2',final.x);
line.setAttribute('y2',final.y);
//Define its stroke.
line.setAttribute("stroke", "black")
//Apend the line to the SVG canvas
canvas.append(line);
}
</script>
</body>
</html>

Drawing a parallelogram HTML5 Canvas

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>

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

RXJS draw line on html5 canvas

I'm trying to achieve the same effect I'm posting here using Reactive Extensions for Javascript (RX-JS).
I'm a bit puzzled on how to do it.
Here is the page:
<!DOCTYPE html>
<html>
<head>
<title>drag and drop</title>
</head>
<style type="text/css">
canvas {
border:1px solid steelblue;
background-color: whitesmoke;
}
</style>
<body>
<canvas id="canvas" width=300 height=300></canvas>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script type="text/javascript">
$(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var drawing = false;
var mouseX = 0;
var mouseY = 0;
function handleMouseDown(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
drawing= true;
}
function handleMouseUp(e) {
drawing = false;
}
function handleMouseMove(e) {
if(drawing){
mouseeX = parseInt(e.clientX - offsetX);
mouseeY = parseInt(e.clientY - offsetY);
$("#movelog").html("Move: " + mouseX + " / " + mouseY);
var ctx = canvas.getContext("2d");
// some cleanup code
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.beginPath();
ctx.moveTo(mouseX,mouseY);
ctx.lineTo(mouseeX,mouseeY);
ctx.stroke();
}
}
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
});
</script>
</body>
</html>
I think I should create observables for the mouseDown, mouseMove and mouseUp events.
var mouseDown = Rx.Observable.fromEvent(canvas, 'mousedown');
var mouseMove = Rx.Observable.fromEvent(canvas, 'mousemove');
var mouseUp = Rx.Observable.fromEvent(canvas, 'mouseup');
but I don't know how to combine them. I think should start observing the mousedown, then collect all the moves until the mouseup is raised, and in the whil redraw the line from the starting point to the current point where the mouse is during the mousemove.
Do you have any ideas? Thanks a lot.
°°°°°°°°°°°°°°°°°°°°°°EDIT°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
Here is my code after the answer by Brandon:
$(function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var mouseDown = Rx.Observable.fromEvent($("#canvas"), 'mousedown');
var mouseMove = Rx.Observable.fromEvent($("#canvas"), 'mousemove');
var mouseUp = Rx.Observable.fromEvent($("#canvas"), 'mouseup');
// keep a reference to the pisition when the mouse down was fired
// then flatten the stream with concatAll
var traceLineStream = mouseDown.map(function(md) {
var movesFromMouseDown = mouseMove.takeUntil(mouseUp);
var movesFromMouseDownAndMouseDown = movesFromMouseDown.map(function(mm) {
return {
mouseDownPoint: md,
mouseMovePoint: mm
}
});
return movesFromMouseDownAndMouseDown;
}).concatAll();
var subscription = traceLineStream.subscribe(
function(y) {
var mouseDown = y.mouseDownPoint;
var mouseMove = y.mouseMovePoint;
var mouseDownX = parseInt(mouseDown.clientX - offsetX);
var mouseDownY = parseInt(mouseDown.clientY - offsetY);
var mouseMoveX = parseInt(mouseMove.clientX - offsetX);
var mouseMoveY = parseInt(mouseMove.clientY - offsetY);
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
ctx.beginPath();
ctx.moveTo(mouseDownX, mouseDownY);
ctx.lineTo(mouseMoveX, mouseMoveY);
ctx.stroke();
},
function(e) {
console.log('onError: ' + e.message);
},
function() {
console.log('onCompleted');
});
});
First, combined the streams so you have a stream of events that represent a single drag.
var drag = mouseDown.first().concat(mouseMove.takeUntil(mouseUp));
Next, project this stream of events into a stream of previous,current tuples.
var moves = drag
.scan({}, function(acc, x) {
return { previous: acc.current, current: x };
})
.skip(1);
Now we have a stream that only works the first time. When it ends, we want to start listening for the next drag:
var allMoves = moves.repeat();
Finally, subscribe:
allMoves.subscribe(function (move) {
var mouseX = move.previous.clientX - offsetX,
mouseY = move.previous.clientY - offsetY,
mouseeX = move.current.clientX - offsetX,
mouseeY = move.current.clientY - offsetY,
...
});
Putting it all together without all of the intermediate variables:
mouseDown
.first()
.concat(mouseMove.takeUntil(mouseUp))
.scan({}, function(acc, x) {
return { previous: acc.current, current: x };
})
.skip(1)
.repeat()
.subscribe(function (move) {
var mouseX = move.previous.clientX - offsetX,
mouseY = move.previous.clientY - offsetY,
mouseeX = move.current.clientX - offsetX,
mouseeY = move.current.clientY - offsetY,
...
});

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
};
}

Categories

Resources