JavaScript, canvas - drawn lines disappear after placing mouse over other element - javascript

my idea for the page is to load an image (done by <input type="file/>) and to draw some lines on it (those will represent spool points on welding map drawing.
I have tag in order to do that. However my current code is not working because I add canvas.addEventListener("mouseover", handler, false); event. Adding extra mouseout event doesn't solve the problem. Lines disappear when mouse proceed event over other elements in document. I tried to add arrow function, or add document.addEventListener('DOMContentLoaded') event. Both are not helpful.
Please answer how to keep lines visible as long as file is loaded.
Moreover I have some problems adding event listeners to clear and undo buttons - my variable lines = []; seems to store more data that I expected. How should I prepare this feature to undo last drawn line?
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://unpkg.com/chota">
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
</head>
<body>
<h1 id="header" name="header">Spool assistant</h1>
<div>
<p>Click to draw lines</p>
</div>
<br/>
<div id="main-area">
<div id="draftsman-menu">
<input type="button" id="file-selector-button" value="Load pdf" onclick="document.querySelector('#file-selector').click();" />
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png, .pdf" style="display:none;">
</div>
<div id="canvas-area">
<canvas id="canvas" width=1000 height=400></canvas>
</div>
<div id="edit-menu">
<button id="clear">Clear</button>
<button id="undo">Undo</button>
<button id="save">Save</button>
</div>
</div>
<p id="status"></p>
<img id="output" style="display:none;">
<script type="text/javascript" src="../static/js/drawing_events.js"></script>
</body>
</html>
JS
// constants and variables
const status = document.querySelector("#status");
const output = document.querySelector("#output");
const canvas = document.querySelector("#canvas");
const ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX, startY, mouseX, mouseY;
var isDown = false;
var lines = [];
var imageOpacity = 1;
const canvasPosition = canvas.getBoundingClientRect();
const clearButton = document.querySelector("#clear");
const undoButton = document.querySelector("#undo");
var imageData;
// start with image change event
if (window.FileList && window.File && window.FileReader) {
document.getElementById("file-selector").addEventListener("change", event => {
output.src = "";
status.textContent = "";
// allow only one file even if user selected more
const file = event.target.files[0];
// validations
if (!file.type) {
status.textContent = "Error: The File.type property does not appear to be supported on this browser.";
return;
};
if (!file.type.match("image.*")) {
status.textContent = "Error: The selected file does not appear to be an image."
return;
};
const reader = new FileReader();
reader.addEventListener("load", event => {
output.src = event.target.result;
output.onload = function() {
lines = [];
ctx.drawImage(output, 0, 0);
};
});
reader.readAsDataURL(file);
});
};
// drawing events
canvas.addEventListener("mouseover", handler, false);
function handler(event) {
var img = new Image();
img.onload = start;
img.src = output.src;
function start() {
canvas.width = canvas.width = img.width;
canvas.height = img.height;
ctx.strokeStyle = "black";
ctx.lineWidth = 3;
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseUp(e);});
// redraw the image
drawTheImage(img, imageOpacity);
};
function drawLines(toX, toY) {
// clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// redraw the image
drawTheImage(img,imageOpacity);
// redraw all previous lines
for(var i = 0; i < lines.length; i++) {
drawLine(lines[i]);
};
// draw the current line
drawLine({x1:startX,y1:startY,x2:mouseX,y2:mouseY});
};
function drawTheImage(img, opacity) {
ctx.globalAlpha = opacity;
ctx.drawImage(img, 0, 0);
ctx.globalAlpha = 1.00;
};
function drawLine(line){
ctx.beginPath();
ctx.moveTo(line.x1, line.y1);
ctx.lineTo(line.x2, line.y2);
ctx.stroke();
};
function handleMouseDown(e){
e.stopPropagation();
e.preventDefault();
mouseX = parseInt(e.clientX - canvasPosition["x"] + window.scrollX);
mouseY = parseInt(e.clientY - canvasPosition["y"] + window.scrollY);
// Put your mousedown stuff here
startX = mouseX;
startY = mouseY;
isDown = true;
};
function handleMouseUp(e) {
e.stopPropagation();
e.preventDefault();
// Put your mouseup stuff here
isDown = false;
lines.push({x1:startX, y1:startY, x2:mouseX, y2:mouseY});
};
function handleMouseMove(e) {
if (!isDown) {return;}
e.stopPropagation();
e.preventDefault();
mouseX = parseInt(e.clientX - canvasPosition["x"] + window.scrollX);
mouseY = parseInt(e.clientY - canvasPosition["y"] + window.scrollY);
// Put your mousemove stuff here
drawLines(mouseX, mouseY);
};
// clearing
// TODO
// function has to be replaced with undoing or loading blank page
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
lines = []
};
function undoLine() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawTheImage(img, imageOpacity);
lines.pop();
for(var i = 0; i < lines.length; i++) {
drawLine(lines[i]);
};
};
clearButton.addEventListener("click", clearCanvas);
undoButton.addEventListener("click", undoLine);
};

Related

How to make an area in canvas html droppable?

How do you transfer an image of a div or file to some droppable canvas area (inside canvas)? My intention is to make a photobook.
I was doing it with div tags, but I have seen that all photobooks do it with canvas. They even send the photo as drop as canvas.
<canvas id="canvas" style="position:absolute;"></canvas>
<canvas id="canvas-encima" style="position:absolute;left:8em;top:7em;"></canvas>
<script>
var canvas = document.getElementById("canvas"),
ctx = canvas.getContext("2d");
canvas.width= 1000;
canvas.height = 481;
var background = new Image();
background.src = "upload/plantilla5prueba.jpg";
background.onload = function() {
ctx.drawImage(background,0,0);
}
var canvas2 = document.getElementById("canvas-encima"),
ctx2 = canvas2.getContext("2d");
canvas2.width= 330;
canvas2.height = 280;
var image2 = new Image();
image2.src = "upload/celular.png";
image2.onload = function() {
ctx2.drawImage(image2,0,0);
;}
</script>
I believe that with the drag and drop of a blob or uploaded file to the canvas droppable, the photobook would almost be made.
In order to make an area in the canvas droppable I mark first the droppable zone. See the markDroppableZone() function. On dragenter, dragover and drop I check first if the mouse is inside the droppable zone using isPointInPath. Please see onEvent() function.
If the mouse is in path I use e.stopPropagation(); e.preventDefault();. This is preventing the opening of the dragged image in a new window.
Next on drop I procede to handle the dropped files. See the handleFiles() function.
const ctx = canvas.getContext("2d")
let cw = canvas.width;
let ch = canvas.height;
//the mouse
let m = {}
ctx.setLineDash([4]);
markDroppableZone();
ctx.stroke();
ctx.setLineDash([]);
function markDroppableZone(){
ctx.beginPath();
ctx.rect(10,10,160,160);
}
canvas.addEventListener("dragenter", dragenter, false);
canvas.addEventListener("dragover", dragover, false);
canvas.addEventListener("drop", drop, false);
function dragenter(e) {
onEvent(e);
}
function dragover(e) {
onEvent(e);
}
function drop(e) {
onEvent(e);
let data = e.dataTransfer;
let files = data.files;
// handle files
handleFiles(files);
}
function handleFiles(files){
for (var i = 0; i < files.length; i++) {
var theFile = files[i];
// check if the file is an image
var isImagen = /^image\//;
// if it's not an image continu
if (!isImagen.test(theFile.type)) {
continue;
}
var img = new Image();
img.src = window.URL.createObjectURL(theFile);
img.onload = function() {
ctx.save();
markDroppableZone();
// clip the context
ctx.clip();
// draw the image
ctx.drawImage(this, 10, 10);
ctx.restore();
window.URL.revokeObjectURL(this.src);
}
}
}
function onEvent(e){
m = oMousePos(canvas, e);
markDroppableZone();
if (ctx.isPointInPath(m.x, m.y)){
e.stopPropagation();
e.preventDefault();
}
}
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{background:#e9e9e9}
<canvas id="canvas" width="500" height="500"></canvas>

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>

fill-in image with canvas drawing

code description:
i am using canvas to draw using some java-script .. i am expecting the user to draw some thing in the canvas area then save it or clean the canvas area ..
this is what i have done so far .. here is the code/; but it needs a browser to work
https://jsfiddle.net/RababAlkhalifa/k0y1yzh8/
java script:
var lastPt = null;
var canvas;
var ctx;
function init() {
canvas = document.getElementById("mycanvas");
ctx = canvas.getContext("2d");
var offset = getOffset(canvas);
if (window.PointerEvent) {
canvas.addEventListener("pointerdown", function() {
canvas.addEventListener("pointermove", draw, false);
}, false);
canvas.addEventListener("pointerup", endPointer, false);
} else {
//Provide fallback for user agents that do not support Pointer Events
canvas.addEventListener("mousedown", function() {
canvas.addEventListener("mousemove", draw, false);
}, false);
canvas.addEventListener("mouseup", endPointer, false);
}
}
// Event handler called for each pointerdown event:
function draw(e) {
if (lastPt != null) {
ctx.beginPath();
// Start at previous point
ctx.moveTo(lastPt.x, lastPt.y);
// Line to latest point
ctx.lineTo(e.pageX, e.pageY);
// Draw it!
ctx.stroke();
}
//Store latest pointer
lastPt = { x: e.pageX, y: e.pageY };
}
function getOffset(obj) {
//...
}
function endPointer(e) {
//Stop tracking the pointermove (and mousemove) events
canvas.removeEventListener("pointermove", draw, false);
canvas.removeEventListener("mousemove", draw, false);
//Set last point to null to end our pointer path
lastPt = null;
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
var w = canvas.width;
canvas.width = 1;
canvas.width = w;
}
function download() {
var dt = canvas.toDataURL();
this.href = dt; //this may not work in the future..
clearCanvas();
}
document.getElementById('download').addEventListener('click', download, false);
html:
<canvas id="mycanvas" width="600px" height="600px" style="border:1px solid black;"></canvas>
<div class="convas_contrllers">
<button onclick="clearCanvas()">Clear</button>
<a id="download" download="CanvasDemo.png">Download as image</a>
</div>
<a id="download" download="CanvasDemo.png">Download as image</a>
<div class="slide" id="img1"><img src="http://placehold.it/300x100&text=FooBar1" /></div>
the problem:
i need to put the saved canvas in the image id=img1 element before clear or saving the canvas .. is this possible ?
Yes, this is possible. Here's how you could achieve that ...
var image = document.querySelector('#img1');
var canvas = document.querySelector('#mycanvas');
var ctx = canvas.getContext('2d');
var isMousePressed = false;
canvas.onmousedown = function(e) {
isMousePressed = true;
ctx.beginPath();
ctx.moveTo(e.offsetX, e.offsetY);
};
canvas.onmouseup = function() {
isMousePressed = false;
};
canvas.onmousemove = function(e) {
if (isMousePressed) {
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
}
};
function clearCanvas() {
image.src = canvas.toDataURL();
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function download() {
image.src = canvas.toDataURL();
var a = document.createElement('a');
a.href = canvas.toDataURL();
a.download = 'myImage.png'; //image name
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
body{margin:10px 0 0 0;overflow:hidden}.slide{position:absolute;top:10px;left:200px}
<canvas id="mycanvas" width="180" height="180" style="border:1px solid black; cursor: default;"></canvas>
<div class="convas_contrllers">
<button id="clear" onclick="clearCanvas()">Clear</button>
<button id="download" onclick="download()">Download as image</button>
</div>
<div class="slide"><img id="img1" src="https://placehold.it/300x100&text=FooBar1"></div>

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

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

Categories

Resources