I have the following code, which is working now. The question is why?
let resizing = false
let startX = 0
let startY = 0
window.addEventListener('mousedown', (e) => {
resizing = true
startX = e.clientX
startY = e.clientY
console.log('startX ' + startX)
document.body.addEventListener('mouseup', (e) => {
if (resizing) {
let endX = e.screenX
console.log('endX ' + endX)
let endY = e.screenY
this.resize(startX, endX, startY, endY, window)
}
resizing = false
e.target.removeEventListener('mouseup', window)
})
})
Previously I had defined my startX and startY inside the mouseup callback like so:
let resizing = false
window.addEventListener('mousedown', (e) => {
resizing = true
let startX = e.clientX
let startY = e.clientY
console.log('startX ' + startX)
document.body.addEventListener('mouseup', (e) => {
if (resizing) {
let endX = e.screenX
console.log('endX ' + endX)
let endY = e.screenY
this.resize(startX, endX, startY, endY, window)
}
resizing = false
e.target.removeEventListener('mouseup', window)
})
})
But I was getting the same values for startX and startY each time the event was triggered after the first time. Why? This dosen't make sense to me as the scope let should have the variable be reset every time the callback function for the mouseup event is done?
I updated my code according to Taplars comment and now the scope works as I expected
let window = this
window.addEventListener('mousedown', (e) => {
let startX = e.clientX
let startY = e.clientY
console.log('startX ' + startX)
var mouseUpHandler = function (e) {
console.log('mouseup')
let endX = e.screenX
console.log('endX ' + endX)
let endY = e.screenY
window.resize(startX, endX, startY, endY, window)
document.body.removeEventListener('mouseup', mouseUpHandler)
}
document.body.addEventListener('mouseup', mouseUpHandler)
})
}
Your original logic had e.target.removeEventListener('mouseup', window), where e.target resolves to document.body. So it is effectively performing:
document.body.removeEventListener('mouseup', window);
One issue here is that the second argument that is passed into the removeEventListener() method is expected to be one of the methods you previously attached. Ref. https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
Given that you are passing in the window, which is not one of the methods you previously attached (nor is it a method at all), my assumption would be that the logic either tests that the parameter is not a function and does not do any thing, or it tries to remove it, sees that it doesn't match any of the attached methods, and simply does nothing. This is, however, an assumption.
However, given that your modification to the logic to fix the passing in of the second argument resolved your issue, this leans towards this being the issue and your observed issue was most likely due to listener methods not being removed and garbage being observed by duplicate bindings.
You could test this by changing the parameter back to window, and if the issue appears again, this would pretty much assert this assumption.
Related
i'm creating function which send information to webserver about mouse position, when mouse button is down (click).
Generaly it works fine, but it fires too many times.
After page refresh:
first click -> method fires 1 time
second click -> methos fires 2 times
third click -> method fires 3 times
and so on...
The HTML code is:
<div id="draw-image-test">
<canvas
id="canvasId"
ref="canRef"
#mousedown="clickMe"
/>
</div>
and method :
clickMe() {
const canvas = document.getElementById('canvasId')
canvas.addEventListener('click', event => {
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left - canvas.clientLeft
const y = event.clientY - rect.top - canvas.clientTop
this.xpos = Math.round(x)
this.ypos = Math.round(y)
this.click = {
cmd: 'rightClick',
x: Math.round(x),
y: Math.round(y),
}
this.sendMessage(this.click)
})
},
Could you please help me with it?
everytime you click on your canvas, you add an event listener to it.
canvas.addEventListener('click', event => { [...]
this is your issue. You just need to do the logic you need in the clickMe, not add an other event listener to your canvas. The #mousedown event will send the event parameter with the wanted coordinates :
clickMe(event) {
const canvas = document.getElementById('canvasId')
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left - canvas.clientLeft
const y = event.clientY - rect.top - canvas.clientTop
this.xpos = Math.round(x)
this.ypos = Math.round(y)
this.click = {
cmd: 'rightClick',
x: Math.round(x),
y: Math.round(y),
}
this.sendMessage(this.click)
},
I have an issue with a game in JavaScript.
My game lives inside a canvas, and I make large use of function almost like:
document.onmousemove = function(event) {
var mouseX = event.clientX - canvas.getBoundingClientRect().left;
var mouseY = event.clientY - canvas.getBoundingClientRect().top;
//mouse position is relative to player position
mouseX -= CANVAS_WIDTH/2;
mouseY -= CANVAS_HEIGHT/2;
player.aimAngle = Math.atan2(mouseY, mouseX) / Math.PI * 180;
}
document.onclick = function(event) {
if(player.canAttack && player.distance >= 80) { //not for sword attack
performAttack(player);
player.canAttack = false;
}
if(player.distance < 80)
performAttack(player);
event.preventDefault();
}
But before dynamically creating the canvas I have a login form. When I click with mouse to select those form I got in console the error Uncaught TypeError: Cannot read property 'canAttack' of undefined . That's because I have not called yet the Player() constructor, so canAttack doesn't exists and for the onMouseMove canvas doesn't exist yet.
How do I "disable" or unbind the document.onclick and document.onmousemove?
If they were done with addEventListener I would disable them with removeEventListener. How could I do with document.onclick instead?
Thanks
Try following when have to remove listener
function noop(){}
document.onclick = noop // when have to remove click binding
I have a scroll function for my canvas which detects distance moved by my mouse and offsets all my images in the canvas.
The problem is i barely move the mouse and the offset number exponentially increases and im not sure why... this is my function that deals with offset calculation:
canvas.addEventListener('mousedown', scrol_cnv, false);
function scroll_cnv(e) {
if (e.button == 2) {//right click only
var x = e.pageX; // get click X
var y = e.pageY; //get click Y
function clear() {
this.removeEventListener('mousemove', updt, false);
}
function updt(evt) {
var difx = evt.pageX - x;
var dify = evt.pageY - y;
//this is where offset is becoming incorrect
//offsets is globally defined `window.offsets = {}`
offsets.cur_offsetx -= difx;
offsets.cur_offsety -= dify;
}
this.addEventListener('mousemove', updt, false);
this.addEventListener('mouseup', clear, false);
}
}
Am i subtracting the offset incorrectly ?
You want the offset to be based on the offset at the time of mousedown. Events that happen frequently shouldn't be changing things without a basis.
You probably also want to remove your mouseup listener, otherwise you get an additional one every click (no functional harm, just unnecessary overhead).
canvas.addEventListener('mousedown', scrol_cnv, false);
function scroll_cnv(e) {
if (e.button == 2) {//right click only
var x = e.pageX; // get click X
var y = e.pageY; //get click Y
// store the initial offsets
var init_offsetx = offsets.cur_offsetx;
var init_offsety = offsets.cur_offsety;
function clear() {
this.removeEventListener('mousemove', updt, false);
this.removeEventListener('mouseup', clear, false);
}
function updt(evt) {
var difx = evt.pageX - x;
var dify = evt.pageY - y;
//this is where offset is becoming incorrect
//offsets is globally defined `window.offsets = {}`
offsets.cur_offsetx = init_offsetx - difx;
offsets.cur_offsety = init_offsetx - dify;
}
this.addEventListener('mousemove', updt, false);
this.addEventListener('mouseup', clear, false);
}
}
How do I get the x and y pixel value of the mouse click on the image after a canvas translate & scale? What's the needed calculation from the event x and y?
I am using panning & zooming code from this answer:
var zoom = function(clicks) {
var pt = ctx.transformedPoint(lastX,lastY);
ctx.translate(pt.x,pt.y);
var factor = Math.pow(scaleFactor,clicks);
ctx.scale(factor,factor);
ctx.translate(-pt.x,-pt.y);
redraw();
}
var handleScroll = function(evt) {
var delta = evt.wheelDelta ? evt.wheelDelta/40 : evt.detail ? -evt.detail : 0;
if (delta) zoom(delta);
return evt.preventDefault() && false;
};
Example website
If you're just trying to get the mouse X and Y position after a click, then you should attach a function to the mousedown event in Javascript. This is called event binding. In short, while in the DOM you can bind events to elements within the page. Here's an example I made which shows an event bound to the #box element.
document.getElementById("box").onmousedown = function() {
var posx = 0;
var posy = 0;
if (!e) var e = window.event;
if (e.pageX || e.pageY) {
posx = e.pageX;
posy = e.pageY;
}
else if (e.clientX || e.clientY) {
posx = e.clientX + document.body.scrollLeft
+ document.documentElement.scrollLeft;
posy = e.clientY + document.body.scrollTop
+ document.documentElement.scrollTop;
}
alert("Mouse x: " + posx + "\nMouse y: " + posy);
};
This code finds an element with an ID of box and tells the code in the function to run every time after the mouse is depressed. In this example we also fall back for older system to ensure that it works cross-platform and cross-browser. If you wanted to bind this event to the whole webpage rather than just an element then you can replace document.getElementById("box") with window.
This however does not compute the relative position within a DOM element. There's multiple ways to do that which I won't go into detail on here, but I'll include a few methods below. Best of luck!
RESOURCES
More on handling mouseclicks in Javascript
Relative position of mouse clicks within an element
jQuery solution for the previous link
I came across the following very simple code for dragging a square around using javascript. It is drawn on the html5 canvas. Despite being very simple it has certainly exposed some gaps in my pretty flakey javascript knowledge. I am generally ok with the idea of drag and drop (i.e. start drag on mouse click, stop drag on mouse release) but my questions are as follows:
(1) I cannot see where the variable e is defined, yet it is used all the time.
(2) In the init funciton at the bottom, an onmousedown listener seems to be attached to the canvas. However it equals the function myDown, but myDown doesn't have parentheses after it. So the myDown function is not actually going to be exectuted. So what is it doing instead?
Thanks in advance. I have tried to research this myself but haven't had any success yet.
Matt
<html>
<head>
</head>
<body>
<section>
<div>
<canvas id="canvas" width="400" height="300">
</canvas>
</div>
<script type="text/javascript">
var canvas;
var ctx;
var x = 75;
var y = 50;
var dx = 5;
var dy = 3;
var WIDTH = 400;
var HEIGHT = 300;
var dragok = false;
function rect(x,y,w,h) {
ctx.beginPath();
ctx.rect(x,y,w,h);
ctx.closePath();
ctx.fill();
}
function clear() {
ctx.clearRect(0, 0, WIDTH, HEIGHT);
}
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
return setInterval(draw, 10);
}
function draw() {
clear();
ctx.fillStyle = "#FAF7F8";
rect(0,0,WIDTH,HEIGHT);
ctx.fillStyle = "#444444";
rect(x - 15, y - 15, 30, 30);
}
function myMove(e){
if (dragok){
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
}
}
function myDown(e){
if (e.pageX < x + 15 + canvas.offsetLeft && e.pageX > x - 15 +
canvas.offsetLeft && e.pageY < y + 15 + canvas.offsetTop &&
e.pageY > y -15 + canvas.offsetTop){
x = e.pageX - canvas.offsetLeft;
y = e.pageY - canvas.offsetTop;
dragok = true;
canvas.onmousemove = myMove;
}
}
function myUp(){
dragok = false;
canvas.onmousemove = null;
}
init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;
</script>
</section>
</body>
</html>
You should really learn basic of the js language first.
1) e is param that is passed to functions. Callbacks receives one param: event object. So e stands for event.
2) myDown is not suppose to be executed when it is attached to onmousedown listener.
it is function object that is called everytime user clicks on canvas. It is callback.
e is the event variable which you get from onmousedown and onmouseup events. since you are attaching the mouse events with the canvas, so here e contains some information about mouse positions.
myDown is directly assigned to onmousedown which means that all the code of myDown function shall be assigned to onmousedown. If you add parenthesis after myDown then it would mean that you are assigning the response of myDown function to onmousedown event.
the other way of writing those events is like following
canvas.onmousedown = function(e)
{
myDown(e);
};
canvas.onmouseup = function(e)
{
myUp(e);
};
(1) I cannot see where the variable e is defined, yet it is used all the time.
You may know that a function is a set of instructions with input and output. They get their input through parameters and their output is what they return.
Now, the parameters they get are available in their body. This is why the e they get can be used inside.
(2) In the init funciton at the bottom, an onmousedown listener seems to be attached to the canvas. However it equals the function myDown, but myDown doesn't have parentheses after it. So the myDown function is not actually going to be exectuted. So what is it doing instead?
Function is a special object in javascript, with an extra internal property [[Call]]. When you type the function name alone, you're talking about the function itself. And as it is a first-class object it can be assigned to a variable, passed as an argument, returned from other functions, etc.
When you type the function name with parenthesize after it you execute the code in the function body by the [[Call]] internal property.