event propagation in three.js - javascript

I have a scene with several objects. I use an orthographic camera controller. When I have a selected object, I want to rotate it with the mouse using shiftKey + but 1 (rotation around its own center) and translate it in the scene using shiftKey + but 3.
When setting up my mouse events handlers, I tried to stop the camera controls to fire, but it still does as soon as button is up.
Can someone show me where I'm wrong ?
$(canva).mousedown(function (e) {
if (selObject && e.shiftKey) {
e.preventDefault();
e.stopPropagation()
e.cancelBubble=true;
e.returnValue=false;
controls.enabled = false
mDown = e.which
clientX = e.clientX
clientY = e.clientY
return false
}
});
$(canva).mousemove(function (e) {
if (! selObject || ! mDown) {
return true
}
e.stopPropagation()
e.preventDefault();
e.cancelBubble=true;
e.returnValue=false;
dX = e.clientX - clientX
dY = e.clientY - clientY
if (mDown == 1) {
dX /= 100
dY /= 100
selObject.rotation.x += dX
selObject.rotation.y += dY
} else if (mDown == 3) {
dX /= 2
dY /= 2
var pos = mouse2world(e)
selObject.position = pos
}
clientX = e.clientX
clientY = e.clientY
return false
});
$(canva).mouseup(function (e) {
if (mDown) {
mDown = 0
e.preventDefault();
e.stopPropagation()
e.cancelBubble=true;
e.returnValue=false;
controls.enabled = true
return false
}
});

Try
event.stopImmediatePropagation();
instead of
event.stopPropagation();
Source: MDN https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation

Semicolon is missing on all e.stopPropagation() statements.

Related

Drag multiple elements in JS

I'm new to JS so I need help to solve my problem :). I found a codepen that helped me drag one element of my website but the thing is that I would like to drag 4 elements separately. I applied the same class to all of them but it works only on the first one.
Link of the codepen : https://codepen.io/Coding-Artist/pen/zYWbYXV
I'm sure the solution is obvious to you (I would say a var or a for ?) but I'm learning and I really want to progress so if you could explain that would be perfect ! Thanks a lot
JS —
var draggableElem = document.querySelector(".draggable-elem");
let initialX = 0,
initialY = 0;
let moveElement = false;
//events object
let events = {
mouse: {
down: "mousedown",
move: "mousemove",
up: "mouseup"
},
touch: {
down: "touchstart",
move: "touchmove",
up: "touchend"
}
};
let deviceType = "";
//Detect touch device
const isTouchDevice = () => {
try {
//We try to create TouchEvent (it would fail for desktops and throw error)
document.createEvent("TouchEvent");
deviceType = "touch";
return true;
} catch (e) {
deviceType = "mouse";
return false;
}
};
isTouchDevice();
// start(mouse down/touch start)
draggableElem.addEventListener(events[deviceType].down, (e) => {
e.preventDefault();
//initial x and y points
initialX = !isTouchDevice() ? e.clientX : e.touches[0].clientX;
initialY = !isTouchDevice() ? e.clientY : e.touches[0].clientY;
// start movement
moveElement = true;
});
// Move
draggableElem.addEventListener(events[deviceType].move, (e) => {
//if movement==true then set top and left to new X and y while removing any offset
if (moveElement) {
e.preventDefault();
let newX = !isTouchDevice() ? e.clientX : e.touches[0].clientX;
let newY = !isTouchDevice() ? e.clientY : e.touches[0].clientY;
draggableElem.style.top = draggableElem.offsetTop - (initialY - newY) + "px";
draggableElem.style.left =
draggableElem.offsetLeft - (initialX - newX) + "px";
initialX = newX;
initialY = newY;
}
});
//mouse up/touch end
draggableElem.addEventListener(
events[deviceType].up,
(stopMovement = (e) => {
//stop movement
moveElement = false;
})
);
draggableElem.addEventListener("mouseleave", stopMovement);
document.addEventListener(events[deviceType].up, (e) => {
moveElement = false;
});
For it to work with multiple elements you should instantiate variables for each element and then add event listeners to them.
This can be done dynamically like in this codepen fork I made by using document.querySelectorAll and a for loop to iterate through the elements, instantiate variables, and add event listeners to each one.
My modified code (it's not perfect but it gets the job done):
let draggableElems = document.querySelectorAll("#draggable-elem");
let initialX = {},
initialY = {};
let moveElement = {};
//events object
let events = {
mouse: {
down: "mousedown",
move: "mousemove",
up: "mouseup"
},
touch: {
down: "touchstart",
move: "touchmove",
up: "touchend"
}
};
let deviceType = "";
//Detect touch device
const isTouchDevice = () => {
try {
//We try to create TouchEvent (it would fail for desktops and throw error)
document.createEvent("TouchEvent");
deviceType = "touch";
return true;
} catch (e) {
deviceType = "mouse";
return false;
}
};
isTouchDevice();
for (let i = 0; i < draggableElems.length; i++) {
var draggableElem = draggableElems[i];
// start(mouse down/touch start)
draggableElem.addEventListener(events[deviceType].down, (e) => {
e.preventDefault();
//initial x and y points
initialX[this] = !isTouchDevice() ? e.clientX : e.touches[0].clientX;
initialY[this] = !isTouchDevice() ? e.clientY : e.touches[0].clientY;
// start movement
moveElement[this] = true;
});
// Move
draggableElem.addEventListener(events[deviceType].move, (e) => {
//if movement==true then set top and left to new X and y while removing any offset
if (moveElement[this]) {
var elem = e.target;
e.preventDefault();
let newX = !isTouchDevice() ? e.clientX : e.touches[0].clientX;
let newY = !isTouchDevice() ? e.clientY : e.touches[0].clientY;
elem.style.top = elem.offsetTop - (initialY[this] - newY) + "px";
elem.style.left = elem.offsetLeft - (initialX[this] - newX) + "px";
initialX[this] = newX;
initialY[this] = newY;
}
});
//mouse up/touch end
draggableElem.addEventListener(
events[deviceType].up,
(stopMovement = (e) => {
//stop movement
moveElement[this] = false;
})
);
draggableElem.addEventListener("mouseleave", stopMovement);
document.addEventListener(events[deviceType].up, (e) => {
moveElement[this] = false;
});
}

Detect direction of touchpad swipe properly

I was able to scale in scale out x axis and y axis , Its working very good with arrow keys , I want to do that with touchpad aswel.I tried this below code ,its working but its not smooth .Sometimes when i zoom in X , its even zooming in Y and vice versa.
window.addEventListener('mousewheel', function(e) {
window.addEventListener('mousewheel', function(e) {
e.preventDefault();
yDelta = e.deltaY;
xDelta = e.deltaX;
if (yDelta < -1 && Math.round(xDelta) < 1) {
zoomOutY();
} else if (yDelta > 1 && Math.round(xDelta) < 1) {
zoomInY();
} else if (xDelta < -1 && Math.round(yDelta) < 1) {
zoomOut();
} else if (xDelta > -1 && Math.round(yDelta) < 1) {
zoomIn();
}
}, {
passive: false
});
And Again Same issue with mousemove method , how to detect the 4 directions smoothly , below is my code.
document.addEventListener('mousemove', mouseMoveMethod);
document.addEventListener('mousedown', mouseDownMethod);
document.addEventListener('mouseup', mouseUpMethod);
// Prevent context menu popup, so we can move our mouse.
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
return false;
}, false);
mouseMoveMethod = function(e) {
if (e.ctrlKey || mouseIsHeld) {
let offsetX = 0
let offsetY = 0
if (e.pageX > oldx && e.pageY == oldy) {
direction = "East";
offsetX -= 1
} else if (e.pageX == oldx && e.pageY > oldy) {
direction = "South";
offsetY += 1
} else if (e.pageX == oldx && e.pageY < oldy) {
direction = "North";
offsetY -= 1
} else if (e.pageX < oldx && e.pageY == oldy) {
offsetX += 1
direction = "West";
}
updateKeyboardPan(offsetX, offsetY);
oldx = e.pageX;
oldy = e.pageY;
})
Again in the above code I am able to find the direction , but its lagging and hanging in middle.Is this the right approach ? or can I improve my code to improve my swipe/mousewheel direction , thank you.
I found a quite interesting example of multi-touch trackpad gestures in JavaScript.
The code snippet below utilizes this for overriding LCJS chart interactions for trackpad. To me it seems to perform in a surprisingly intuitive manner for zooming in/out on pinch interaction (2 fingers, move to opposite directions) and panning with dragging 2 fingers in same direction.
I did not find any way to differentiate pinch interaction along X and Y separately, it seems that the JS events just get a single value for both, which is assigned to deltaY.
const {
lightningChart
} = lcjs;
const {
createProgressiveTraceGenerator
} = xydata;
const chart = lightningChart().ChartXY();
const series = chart.addLineSeries()
createProgressiveTraceGenerator()
.setNumberOfPoints(1000)
.generate()
.toPromise()
.then(data => {
series.add(data)
})
chart.setMouseInteractionWheelZoom(false)
chart.onSeriesBackgroundMouseWheel((_, e) => {
const xInterval = chart.getDefaultAxisX().getInterval()
const yInterval = chart.getDefaultAxisY().getInterval()
if (e.ctrlKey) {
// Zoom in / out (no separation of X or Y amount!)
const zoomAmount = e.deltaY * 0.01
chart.getDefaultAxisX().setInterval(xInterval.start + zoomAmount * (xInterval.end - xInterval.start), xInterval.end - zoomAmount * (xInterval.end - xInterval.start), false, true)
chart.getDefaultAxisY().setInterval(yInterval.start + zoomAmount * (yInterval.end - yInterval.start), yInterval.end - zoomAmount * (yInterval.end - yInterval.start), false, true)
} else {
// Pan X and Y simultaneously.
const panX = e.deltaX * 0.001 * (xInterval.end - xInterval.start)
const panY = e.deltaY * -0.001 * (yInterval.end - yInterval.start)
chart.getDefaultAxisX().setInterval(xInterval.start + panX, xInterval.end + panX, false, true)
chart.getDefaultAxisY().setInterval(yInterval.start + panY, yInterval.end + panY, false, true)
}
e.preventDefault()
})
<script src="https://unpkg.com/#arction/xydata#1.4.0/dist/xydata.iife.js"></script>
<script src="https://unpkg.com/#arction/lcjs#3.0.0/dist/lcjs.iife.js"></script>

move element on mousemove event: FAILS when moving too fast (vuejs)

I'm building an element which could be moved on mouse events.
Here's an example PEN I found on the internet. General concept is: 1) get original cursor location on mousedown, 2) move the element on mousemove, 3) finish on mouseleave or mouseup.
var offset = [0,0];
var divOverlay = document.getElementById ("overlay");
var isDown = false;
divOverlay.addEventListener('mousedown', function(e) {
isDown = true;
offset = [
divOverlay.offsetLeft - e.clientX,
divOverlay.offsetTop - e.clientY
];
}, true);
document.addEventListener('mouseup', function() {
isDown = false;
}, true);
document.addEventListener('mousemove', function(e) {
event.preventDefault();
if (isDown) {
divOverlay.style.left = (e.clientX + offset[0]) + 'px';
divOverlay.style.top = (e.clientY + offset[1]) + 'px';
}
}, true);
I used the same concept but with Vuejs. It worked, but it's far from perfect. If I move faster, the cursor would somehow leave the element, which ends mousemove event. Couldn't figure out what was wrong. Here's my jsfiddle.
new Vue({
el: "#app",
data: {
blocks: [{
top: 0,
left: 0,
active: false
}],
offsetX: undefined,
offsetY: undefined,
},
methods: {
mousedown(e, i) {
this.blocks[i].active = true;
this.offsetX = e.offsetX;
this.offsetY = e.offsetY;
},
mouseup(i) {
this.blocks[i].active = false;
},
mousemove(e, i) {
if (this.blocks[i].active) {
let x = e.offsetX;
let y = e.offsetY;
let dx = x - this.offsetX;
let dy = y - this.offsetY;
this.blocks[i].top += dy;
this.blocks[i].left += dx;
}
}
}
})
How should I modify my code so that it works as smooth as the pure Javascript version?
Thanks!

touchmove handler after touchstart handler wont work

I have a problem with an touchmove event. When the user touches the display (touchstart) the touchmove event handler and game() should be executed and if the user leaves the screen everything should be stopped. But then the if conditions for the collisiondetection interval won't work right because e.pageX and e.pageY always have the coordinates of the touchstart and won't update their values when the user moves their finger (touchmove) on the screen. How can I fix this? demo
$("body").on({
'touchstart mousedown': function (e) {
$(this).on('touchmove mousemove');
collisiondetection = setInterval(function() {
var xp1 = $("#n1").position();
if (e.pageY >= xp1.top && e.pageY <= xp1.top + cy * 10 && e.pageX >= xp1.left && e.pageX <= xp1.left + cx * 25) {
console.log("hit");
}
var xp2 = $("#n2").position();
if (e.pageY >= xp2.top && e.pageY <= xp2.top + cy * 10 && e.pageX >= xp2.left && e.pageX <= xp2.left + cx * 25) {
console.log("hit");
}
},10);
game();
},
'touchend mouseup': function (e) {
$(this).off('touchmove mousemove');
clearInterval(animaterects);
clearInterval(collisiondetection);
}
});
UPDATE: If I edit it to 'touchstart mousedown touchmove mousemove': function (e) { the collision detection and the updating coordinates works well but the animation dont.
Becasue your code doesn't update the coordinates when users move their fingers.
$("body").on({
'touchstart mousedown': function (e) {
var pageX = e.pageX
var pageY = e.pageY;
$(this).on('touchmove mousemove',function(e){
pageX = e.pageX;
pageY = e.pageY;
});
collisiondetection = setInterval(function() {
var xp1 = $("#n1").position();
if (pageY >= xp1.top && pageY <= xp1.top + cy * 10 && pageX >= xp1.left && pageX <= xp1.left + cx * 25) {
console.log("hit");
}
var xp2 = $("#n2").position();
if (pageY >= xp2.top && pageY <= xp2.top + cy * 10 && pageX >= xp2.left && pageX <= xp2.left + cx * 25) {
console.log("hit");
}
},10);
game();
},
'touchend mouseup': function (e) {
$(this).off('touchmove mousemove');
clearInterval(animaterects);
clearInterval(collisiondetection);
}
});

auto clicker and auto key press in javascript console

i need a little help. i want to make something that you put in console and it press Enter bottom for 2000 times and auto click for 2000 times with no delay ! and a key for stop this action. anyone can help me ? thanks a lot !
With jQuery:
function enter_key(ctrl, alt, shift, which) {
var e = $.Event("keydown");
e.ctrlKey = false;
e.altKey = false;
e.shiftKey = false;
e.which = e.keyCode = 13;
$(document.documentElement || window).trigger(e);
}
var stop = false;
for (var i=0; i<2000; ++i) {
if (!stop) {
enter_key();
}
}
click is simpler:
var stop = false;
for (var i=0; i<2000; ++i) {
if (!stop) {
$('button').click();
}
}
and you can stop the iteration by setting:
stop = true;
i thing about this and i found a code that click on the specific position :
var elem = document.elementFromPoint(x, y);
elem.addEventListener('click', function() {
console.log('clicked')
}, false);
var support = true;
try {
if (new MouseEvent('click', {bubbles: false}).bubbles !== false) {
support = false;
} else if (new MouseEvent('click', {bubbles: true}).bubbles !== true) {
support = false;
}
} catch (e) {
support = false;
}
setInterval(function() {
if (support) {
var event = new MouseEvent('click');
}else{
var event = document.createEvent('Event');
event.initEvent('click', true, true);
}
elem.dispatchEvent(event);
},1000);
and i found this code for get mouse position :
function FindPosition(e) {
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;
}
// posx and posy contain the mouse position relative to the document
// Do something with this information
}
so how can i use this code to import mouse position in auto click code ???

Categories