Variable is null after setting it to e.target, react - javascript

I'm trying to learn react and i creating a chess game.
I've to simulate a drag and click system to make the pieces move.
The function setActivePiece is called on mousedown, and it set the variable activePiece to the piece being clicked (only if it's a piece and not if it's the board being clicked), movePiece is only called on mouseup ( end of a click or end of a drag).
The drag system works, but i want to be able to click a piece and then click the position where i want the piece to move.
After a click, the activePiece is set to the piece clicked (using e.target) and the function movePiece is called (cause a click call both setActivePiece and movePiece), but during the second click the value of the Variable activePiece is null, in fact the piece wont move.
Any suggestions?
Here's the code.
function Board(){
const [pieces, setPieces] = useState([]);
const boardRef = useRef();
let activePiece = null;
function movePiece(e) {
if (activePiece === null)
return;
//determinate the position in the board (from cordinate to index of the board)
setPieces(prevState => {
const updatePieces = prevState.map(p => {
//finding the right piece
if (p.id === activePiece.id){
let lenghtmovingPiece = boardRef.current.offsetWidth / 8;
//aggiorno la posizione (int(posmovingPiece - posBoard / lenghtmovingPiece))
p.x = parseInt((e.clientX - boardRef.current.getBoundingClientRect().x) / lenghtmovingPiece);
p.y = parseInt((e.clientY - boardRef.current.getBoundingClientRect().y) / lenghtmovingPiece);
}
return p;
})
//reset hte active piece
activePiece = null
return updatePieces;
})
}
function setActivePiece(e) {
//no preview image
e.preventDefault();
//click of the board
if (e.target.id === "boardImg")
return;
activePiece = e.target
}
function dragPiece(e){
//nothing selected
if (activePiece === null)
return;
//set the element new position when dragged
//newPos = mousePos - spazio tra la finestra e la scacchiera (perche' i piece sono absolute alla scacchiera) - meta' della grandezza del piece (= larghezzaBoard / 4)
activePiece.style.left = e.clientX - boardRef.current.getBoundingClientRect().x - boardRef.current.getBoundingClientRect().x/4 + "px";
activePiece.style.top = e.clientY - boardRef.current.getBoundingClientRect().y - boardRef.current.getBoundingClientRect().x/4 + "px";
}
useEffect(() => {
// createMatch("matches", "match0/logs/log1", {})
// createMatch("matches", "match0", objBoard)
setPieces(generateBoard())
}, [activePiece]);
return(
<div id="board" onMouseDown={setActivePiece} onMouseUp={movePiece} onMouseMove={dragPiece} >
<img ref={boardRef} id="boardImg" src={boardImg} alt="board" draggable="false"/>
{
//pieces of the board
pieces.map(piece => return <Piece key={uuidv4()} piece={piece}/>)
}
</div>
)
}
Also tried to use an useState but i dont know if it's the right path.

Yes, useState is the right path. Consider this slight revision:
export default function Board() {
const [activePiece, setActivePiece] = useState(null);
const [pieces, setPieces] = useState([]);
const boardRef = useRef();
function movePiece(e) {
if (activePiece === null) return;
//determinate the position in the board (from cordinate to index of the board)
setPieces((prevState) => {
const updatePieces = prevState.map((p) => {
//finding the right piece
if (p.id === activePiece.id) {
let lenghtmovingPiece = boardRef.current.offsetWidth / 8;
//aggiorno la posizione (int(posmovingPiece - posBoard / lenghtmovingPiece))
p.x = parseInt(
(e.clientX - boardRef.current.getBoundingClientRect().x) /
lenghtmovingPiece
);
p.y = parseInt(
(e.clientY - boardRef.current.getBoundingClientRect().y) /
lenghtmovingPiece
);
}
return p;
});
//reset the active piece
setActivePiece(null);
return updatePieces;
});
}
function onMouseDown(e) {
//no preview image
e.preventDefault();
//click of the board
if (e.target.id === "boardImg") return;
setActivePiece(e.target);
}
function dragPiece(e) {
//nothing selected
if (activePiece === null) return;
const updatedActivePiece = { ...activePiece };
//set the element new position when dragged
//newPos = mousePos - spazio tra la finestra e la scacchiera (perche' i piece sono absolute alla scacchiera) - meta' della grandezza del piece (= larghezzaBoard / 4)
updatedActivePiece.style.left =
e.clientX -
boardRef.current.getBoundingClientRect().x -
boardRef.current.getBoundingClientRect().x / 4 +
"px";
updatedActivePiece.style.top =
e.clientY -
boardRef.current.getBoundingClientRect().y -
boardRef.current.getBoundingClientRect().x / 4 +
"px";
setActivePiece(updatedActivePiece);
}
useEffect(() => {
// createMatch("matches", "match0/logs/log1", {})
// createMatch("matches", "match0", objBoard)
setPieces(generateBoard());
}, [activePiece]);
return (
<div
id="board"
onMouseDown={onMouseDown}
onMouseUp={movePiece}
onMouseMove={dragPiece}
>
<img
ref={boardRef}
id="boardImg"
src={boardImg}
alt="board"
draggable="false"
/>
{
//pieces of the board
pieces.map((piece) => (
<Piece key={uuidv4()} piece={piece} />
))
}
</div>
);
}

Related

how to allow scroll on mobile using touchscreen passive handler

i'm desining a horizzontal scrolling website, but i want that feature only in Desktop mode and i would like to let standard scrolling in tablets and mobile devices.
right now this is my setup:
<script>
document.addEventListener('touchstart', handler, {passive: true});
addEventListener(document, "touchstart", function(e) {
console.log(e.defaultPrevented); // will be false
e.preventDefault(); // does nothing since the listener is passive
console.log(e.defaultPrevented); // still false
});
const SCROLL_SPEED = 70;
requestAnimationFrame(function scroll() {
const nextScrollX = sectionAnchorPointer[nextSectionIndex];
// linear animtion
// if (Math.abs(window.scrollX - nextScrollX) > SCROLL_SPEED) {
// const val =
// -Math.abs(window.scrollX - nextScrollX) / (window.scrollX - nextScrollX);
// window.scroll(window.scrollX + val * SCROLL_SPEED, window.scrollY);
// } else {
// window.scroll(nextScrollX, window.scrollY);
// }
// curve animation
if (Math.abs(window.scrollX - nextScrollX) > 1) {
let val = (nextScrollX - window.scrollX) / 8;
val = val > 0 ? Math.max(val, 1) : Math.min(val, -1);
window.scroll(window.scrollX + val, window.scrollY);
} else {
window.scroll(nextScrollX, window.scrollY);
}
requestAnimationFrame(scroll);
});
let sectionAnchorPointer = [];
const resizeHandler = () => {
const content1 = document.getElementById("content1");
const content2 = document.getElementById("content2");
const content3 = document.getElementById("content3");
const content4 = document.getElementById("content4");
sectionAnchorPointer = [
content1.offsetLeft,
content2.offsetLeft,
content3.offsetLeft,
content4.offsetLeft
];
};
window.addEventListener("resize", resizeHandler);
let nextSectionIndex = 0;
const getCurrentSectionIndex = () =>
sectionAnchorPointer.findIndex((leftValue, i, array) => {
const scrollX = Math.ceil(window.scrollX); // Fixed a bug where scrollX was decimalized
const rightValue = array[i + 1] ?? Infinity;
return leftValue <= scrollX && scrollX < rightValue;
});
window.addEventListener("wheel", ({ deltaY }) => {
const currentSectionIndex = getCurrentSectionIndex();
const add = Math.abs(deltaY) / deltaY;
nextSectionIndex = currentSectionIndex + add;
nextSectionIndex = Math.min(
sectionAnchorPointer.length - 1,
Math.max(0, nextSectionIndex)
);
});
resizeHandler();
nextSectionIndex = getCurrentSectionIndex();
</script>
#media and screen (min-width: 1050px){
}
body {
overflow-y: hidden;
}
section {
min-width: 100vw!important;
min-height: 100vh!important;
}
}
}
I pasted the first lines of the JS code from documentation about passive Event listeners (official documentation) but i cannot understand how to apply that to my code in order to allow the scrolling in narrow screens.
right now the console output is the following:
Warning: Uncaught ReferenceError: handler is not defined
[Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive. See https://www.chromestatus.com/feature/5745543795965952
link to the site: site
thank you in advance for your time.

ReactJS - Get onMouseMove and onMouseEnter to work togher

What I'm trying to build is a card with a photo as a background image. The idea is that when I hover on the photo (MouseEnter) the photo changes from a black and white one, to a colored one, but when I move the mouse horizontally on the photo the background image changes to another photo (the effect is similar to the apple album preview).
Now I got the code to work, but when I enter with the mouse on the photo the effect of the mouse enter is not even visible, because the mouse move function triggers right after that.
So the effect I want to get is: when I move the mouse over the photo, it changes to a colored one. THEN when I move the mouse again the scroll effect starts to work and I can change photo scrolling.
Here is the code:
import React, { useState } from "react";
import { Link } from "react-router-dom";
import $ from 'jquery';
const AboutCard = ({id, name, role, description, link, image, colored_image}) => {
const [backImg, setBackImg] = useState(0);
var active = 0;
var currentProfile = 0;
var unitPhoto= 0;
const handeMouseEnter = (event) => {
setBackImg(colored_image);
};
const handleMouseMove = (event) => {
unitPhoto = 100/(image.length-1);
var offset = $('#'+event.target.attributes.id.value).offset();
let x = event.pageX- offset.left;
let w =$('#'+event.target.attributes.id.value).width();
x = (x*100)/w;
let index = Math.floor(x/unitPhoto);
if(index >= image.length){
index = image.length-1;
}
if(index <0){
return;
}
if(index !== active || index != colored_image){
setBackImg(index);
active = index;
}
};
const handleTouchMove = (event) => {
unitPhoto = 100/(image.length-1);
var offset = $('#'+event.target.attributes.id.value).offset();
let x = event.touches[0].pageX- offset.left;
let w = $('#'+event.target.attributes.id.value).width();
x = (x*100)/w;
let index = Math.floor(x/unitPhoto);
if(index === 0){
setBackImg(colored_image);
return;
}
if(index >= image.length-1){
index = image.length-2;
}
if(index <0){
return;
}
if(index !== active || index !== colored_image){
setBackImg(index);
active = index;
}
};
$(document).on('mousemove', function(event){
if($('#'+event.target.attributes.id.value).attr('class') !== 'profileImage'){
setBackImg(0);
}
})
$(document).on('touchend', function(){
setBackImg(0);
})
return (
<div className="aboutDiv" id={id}>
<Link to={`${link}`}>
<div
onMouseEnter={(ev) => handeMouseEnter(ev)}
onMouseMove={(ev)=> handleMouseMove(ev)}
onTouchMove={(ev)=>
handleTouchMove(ev)}
id={'image-'+id}
style={{
background: `url(${image[backImg]})`,
}}
className="profileImage"
>
</div>
</Link>
<h3 className="profileName">{name}</h3>
<p className="profileRole">{role}</p>
</div>
);
};
export default AboutCard;
Any tips?

Progressively add image (arrays)

So I am creating a game where a spaceship moves and it must avoid a fireball image in order to win. My issue is that I have only one fireball looping over and over. Instead, I would like to have many fireballs, which are multiplied as time passes. I think I should need to incorporate an array and use push() method but I tried and it didn't worked. If anyone could help me, it would be very appreciated. Thanks
//Fireball script
function fireballScript(offset) {
return Math.floor(Math.random() * (window.innerWidth - offset))
}
let fireballMovement = {
x: fireballScript(fireball.offsetWidth),
y: 0
}
const fireLoop = function () {
fireballMovement.y += 1
fireball.style.top = fireballMovement.y + 'px'
if (fireballMovement.y > window.innerHeight) {
fireballMovement.x = fireballScript(fireball.offsetWidth)
fireball.style.left = fireballMovement.x + 'px'
fireballMovement.y = 0
fireball.setAttribute('hit', false)
}
}
fireball.style.left = fireballMovement.x + 'px'
let fireballSpeed = setInterval(fireLoop, 1000 / 250)
let fireball = document.querySelector("#fireball")
<img src = "Photo/fireball.png" id = "fireball" >
//Stop game on collision
function checkCollision() {
if (detectOverlap(spaceship, fireball) && fireball.getAttribute('hit') == 'false') {
hits++
fireball.setAttribute('hit', true)
alert("lost")
}
setTimeout(checkCollision, 1)
}
var detectOverlap = (function () {
function getPositions(spaceship) {
var pos = spaceship.getBoundingClientRect()
return [[pos.left, pos.right], [pos.top, pos.bottom]]
}
function comparePositions(p1, p2) {
let r1 = p1[0] < p2[0] ? p1 : p2
let r2 = p1[0] < p2[0] ? p2 : p1
return r1[1] > r2[0] || r1[0] === r2[0]
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b)
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1])
}
})()
let spaceship = document.querySelector("#icon")
<img src = "Photo/Spaceship1.png" id="icon">
Ps: I asked this question a dozen of times but I could never get an answer which is incorporate into my code. It would be very helpful if someone could fix this... thanks again
You need to have an array of fireballs
var fireballs = [];
Make a constructor for fireballs instead of putting them directly in the html
function fireball(x, y) {
movementX = x;
movementY = y;
}
Then push new ones into the array with dynamic position values. To add them to the document, you need to append them to a parent element. If the <body> is that parent, you'd do this:
let f = new fireball(10, 20)
fireballs.push(f)
document.body.appendChild(f)
In your update, iterate through the fireballs and update their movement.
fireballs.forEach((fireball) => {
// update position for each fireball
});

Adding a simple left/right swipe gesture

I need to add a simple left/right swipe gesture so that the 'selected' image cycles when swiped on mobile, similar to clicking the buttons in the hero component, also similar to pressing the left/right arrow keys on a keyboard
I don't have the most experience with JavaScript so if anyone could tell me what exactly to write and where so that I can completely wrap up this project.
Here is a demo: http://nufaith.ca/justinatkins/
Code:
Vue.component('hero-bg', {
template: `
<div class="hero-bg">
<div class="hero">
<img id="pushed" :src="selected"/>
</div>
</div>
`,
props: ['selected']
});
Vue.component('hero-bg-empty', {
template: `
<div class="hero-bg">
<div class="hero">
<span style="display:block;height:100px;"></span>
</div>
</div>
`
});
Vue.component('hero', {
template: `
<div>
<topbar v-if="!gridEnabled"></topbar>
<topbar2 v-if="gridEnabled"></topbar2>
<hero-bg :selected="selectedItem.img" v-if="!gridEnabled"></hero-bg>
<hero-bg-empty v-if="gridEnabled"></hero-bg-empty>
<div class="hero-container" v-if="!gridEnabled">
<div class="hero">
<img :src="selectedItem.img" v-if="thing" alt=""/>
</div>
<div class="hero-desc">
<button class="control left" #click="previous">
<i class="zmdi zmdi-chevron-left"></i>
</button>
<span class="hero-desc-title" v-html="title"></span>
<button class="control right" #click="next">
<i class="zmdi zmdi-chevron-right"></i>
</button>
<br/>
<button class="view-all-button" #click="enableGrid">OVERVIEW</button>
</div>
</div>
</div>
`,
data() {
return {
gridEnabled: false,
selected: 0,
thing: true
};
},
computed: {
selectedItem() {
return info[this.selected];
},
title() {
const comma = this.selectedItem.title.indexOf(',');
const len = this.selectedItem.title.length;
const strBeginning = this.selectedItem.title.substring(comma, 0);
const strEnd = this.selectedItem.title.substring(comma, len);
if (this.selectedItem.title.includes(',')) {
return `<span>${strBeginning}<span class="font-regular font-muted">${strEnd}</span></span>`;
}
return this.selectedItem.title;
},
maxImages() {
return info.length - 1;
}
},
created() {
window.addEventListener('keydown', e => {
if (e.keyCode === 37) {
this.previous();
return;
}
if (e.keyCode === 39) {
this.next();
return;
}
});
Event.$on('updateImg', index => {
this.selected = index;
this.gridEnabled = !this.gridEnabled;
});
},
methods: {
next() {
this.selected === this.maxImages ? (this.selected = 0) : (this.selected += 1);
},
previous() {
this.selected === 0 ? (this.selected = this.maxImages) : (this.selected -= 1);
},
enableGrid() {
this.gridEnabled = !this.gridEnabled;
window.scroll(0, 0);
Event.$emit('enableGrid');
}
}
});
This is how I implemented a simple swipe gesture in one of my projects. You may check this out.
Code:
touchableElement.addEventListener('touchstart', function (event) {
touchstartX = event.changedTouches[0].screenX;
touchstartY = event.changedTouches[0].screenY;
}, false);
touchableElement.addEventListener('touchend', function (event) {
touchendX = event.changedTouches[0].screenX;
touchendY = event.changedTouches[0].screenY;
handleGesture();
}, false);
function handleGesture() {
if (touchendX < touchstartX) {
console.log('Swiped Left');
}
if (touchendX > touchstartX) {
console.log('Swiped Right');
}
if (touchendY < touchstartY) {
console.log('Swiped Up');
}
if (touchendY > touchstartY) {
console.log('Swiped Down');
}
if (touchendY === touchstartY) {
console.log('Tap');
}
}
Basically, touchableElement mentioned here, refers to the DOM Element that will receive the touch event. If you want to activate swipe options on your entire screen, then you may use your body tag as the touchable element. Or you may configure any specific div element as the touchable element, in case you just want the swipe gesture on that specific div.
On that touchableElement, we are adding 2 event-listeners here:
touchstart:
this is when user starts swiping. We take that initial coordinates (x,y) and
store them into touchstartX, touchstartY respectively.
touchend: this is when user stops swiping. We take that final coordinates (x, y) and store them into touchendX, touchendY respectively.
Keep in mind that, the origin of these coordinates is the top left corner of the screen. x-coordinate increases as you go from left to right and y-coordinate increases as you go from top to bottom.
Then, in handleGesture(), we just compare those 2 pair of coordinates (touchstartX, touchstartY) and (touchendX, touchendY), to detect different types of swipe gesture (up, down, left, right):
touchendX < touchstartX: says that, user started swiping at a higher X value & stopped swiping at a lower X value. That means, swiped from right to left (Swiped Left).
touchendX > touchstartX: says that, user started swiping at a lower X value & stopped swiping at a higher X value. That means, swiped from left to right (Swiped Right).
touchendY < touchstartY: says that, user started swiping at a higher Y value & stopped swiping at a lower Y value. That means, swiped from bottom to top (Swiped Up).
touchendY > touchstartY: says that, user started swiping at a lower Y value & stopped swiping at a higher Y value. That means, swiped from top to bottom (Swiped Down).
You may add the code for these 4 different events (Swipe Up/Down/Left/Right), on the corresponding if blocks, as shown on the code.
I took smmehrab’s answer, added some thresholds to avoid accidental swipes, and turned it into a little library. Might come in handy, so here it is:
export default class TouchEvent
{
static SWPIE_THRESHOLD = 50 // Minumum difference in pixels at which a swipe gesture is detected
static SWIPE_LEFT = 1
static SWIPE_RIGHT = 2
static SWIPE_UP = 3
static SWIPE_DOWN = 4
constructor(startEvent, endEvent)
{
this.startEvent = startEvent
this.endEvent = endEvent || null
}
isSwipeLeft()
{
return this.getSwipeDirection() == TouchEvent.SWIPE_LEFT
}
isSwipeRight()
{
return this.getSwipeDirection() == TouchEvent.SWIPE_RIGHT
}
isSwipeUp()
{
return this.getSwipeDirection() == TouchEvent.SWIPE_UP
}
isSwipeDown()
{
return this.getSwipeDirection() == TouchEvent.SWIPE_DOWN
}
getSwipeDirection()
{
let start = this.startEvent.changedTouches[0]
let end = this.endEvent.changedTouches[0]
if (!start || !end) {
return null
}
let horizontalDifference = start.screenX - end.screenX
let verticalDifference = start.screenY - end.screenY
// Horizontal difference dominates
if (Math.abs(horizontalDifference) > Math.abs(verticalDifference)) {
if (horizontalDifference >= TouchEvent.SWPIE_THRESHOLD) {
return TouchEvent.SWIPE_LEFT
} else if (horizontalDifference <= -TouchEvent.SWPIE_THRESHOLD) {
return TouchEvent.SWIPE_RIGHT
}
// Verical or no difference dominates
} else {
if (verticalDifference >= TouchEvent.SWPIE_THRESHOLD) {
return TouchEvent.SWIPE_UP
} else if (verticalDifference <= -TouchEvent.SWPIE_THRESHOLD) {
return TouchEvent.SWIPE_DOWN
}
}
return null
}
setEndEvent(endEvent)
{
this.endEvent = endEvent
}
}
How to use
Simply feed it the events from touchstart and touchend:
import TouchEvent from '#/TouchEvent'
let touchEvent = null;
document.addEventListener('touchstart', (event) => {
touchEvent = new TouchEvent(event);
});
document.addEventListener('touchend', handleSwipe);
function handleSwipe(event)
{
if (!touchEvent) {
return;
}
touchEvent.setEndEvent(event);
if (touchEvent.isSwipeRight()) {
// Do something
} else if (touchEvent.isSwipeLeft()) {
// Do something different
}
// Reset event for next touch
touchEvent = null;
}
This sounds like a job for Hammer.JS, unless you're trying to avoid dependencies. They have good documentation and examples for getting started
My Vue knowledge is next to nothing, so I'm wary of this becoming a blind leading the blind scenario, but the first thing you'll have to do is add the dependency using either npm or yarn - then add it to the top of your file using
import Hammer from 'hammerjs'
Try adding the below code right above this line: Event.$on('updateImg', index => {
const swipeableEl = document.getElementsByClassName('.hero')[0];
this.hammer = Hammer(swipeableEl)
this.hammer.on('swipeleft', () => this.next())
this.hammer.on('swiperight', () => this.previous())
If it doesn't work you'll have to check your developer tools / console log to see if it's logged any useful errors.
This codepen might be a useful resource too:
Good luck.
Using #smmehrab answer, I created a Vue 3 composable that also works for SSR builds.
import { onMounted, Ref } from 'vue'
export type SwipeCallback = (event: TouchEvent) => void;
export type SwipeOptions = {
directinoal_threshold?: number; // Pixels offset to trigger swipe
};
export const useSwipe = (touchableElement: HTMLElement = null, options: Ref<SwipeOptions> = ref({
directinoal_threshold: 10
})) => {
const touchStartX = ref(0);
const touchEndX = ref(0);
const touchStartY = ref(0);
const touchEndY = ref(0);
onMounted(() => {
if (!touchableElement)
touchableElement = document.body;
touchableElement.addEventListener('touchstart', (event) => {
touchStartX.value = event.changedTouches[0].screenX;
touchStartY.value = event.changedTouches[0].screenY;
}, false);
touchableElement.addEventListener('touchend', (event) => {
touchEndX.value = event.changedTouches[0].screenX;
touchEndY.value = event.changedTouches[0].screenY;
handleGesture(event);
}, false);
});
const onSwipeLeft: Array<SwipeCallback> = [];
const onSwipeRight: Array<SwipeCallback> = [];
const onSwipeUp: Array<SwipeCallback> = [];
const onSwipeDown: Array<SwipeCallback> = [];
const onTap: Array<SwipeCallback> = [];
const addEventListener = (arr: Array<SwipeCallback>, callback: SwipeCallback) => {
arr.push(callback);
};
const handleGesture = (event: TouchEvent) => {
if (touchEndX.value < touchStartX.value && (Math.max(touchStartY.value, touchEndY.value) - Math.min(touchStartY.value, touchEndY.value)) < options.value.directinoal_threshold) {
onSwipeLeft.forEach(callback => callback(event));
}
if (touchEndX.value > touchStartX.value && (Math.max(touchStartY.value, touchEndY.value) - Math.min(touchStartY.value, touchEndY.value)) < options.value.directinoal_threshold) {
onSwipeRight.forEach(callback => callback(event));
}
if (touchEndY.value < touchStartY.value && (Math.max(touchStartX.value, touchEndX.value) - Math.min(touchStartX.value, touchEndX.value)) < options.value.directinoal_threshold) {
onSwipeUp.forEach(callback => callback(event));
}
if (touchEndY.value > touchStartY.value && (Math.max(touchStartX.value, touchEndX.value) - Math.min(touchStartX.value, touchEndX.value)) < options.value.directinoal_threshold) {
onSwipeDown.forEach(callback => callback(event));
}
if (touchEndY.value === touchStartY.value) {
onTap.forEach(callback => callback(event));
}
}
return {
onSwipeLeft: (callback: SwipeCallback) => addEventListener(onSwipeLeft, callback),
onSwipeRight: (callback: SwipeCallback) => addEventListener(onSwipeRight, callback),
onSwipeUp: (callback: SwipeCallback) => addEventListener(onSwipeUp, callback),
onSwipeDown: (callback: SwipeCallback) => addEventListener(onSwipeDown, callback),
onTap: (callback: SwipeCallback) => addEventListener(onTap, callback)
}
}
Example usage:
const { onSwipeLeft, onSwipeRight } = useSwipe(document.body);
onSwipeLeft((e:TouchEvent) => {
//logic
});

Update onMouseLeave event

In JavaScript I re-order an element of a list if the mouseLeave `s it:
This works fine for the first leave-event. However the next time(s) the mouse leaves the element the leave-event is not triggered reliable.
My code is basically this (ES6 with reactJS):
onMouseDownOnListItem (index, event) {
this.draggedElementIndex = index
this.initialDragPos_Y = event.pageY
const listItem = this.refs[('ListItem_' + index)].getDOMNode()
listItem.addEventListener('mouseleave', this.onMouseLeaveOnListItem)
},
onMouseLeaveOnListItem (event) {
const delta = event.pageY - this.initialDragPos_Y
if (delta !== 0) {
let {elements} = this.state
let element = elements[this.draggedElementIndex]
let oldPos = this.draggedElementIndex
let newPos = -1
if (delta < 0) { // move element up
newPos = this.draggedElementIndex - 1
} else if (delta > 0) { // move element down
newPos = this.draggedElementIndex + 1
}
if (newPos >= 0 && newPos < elements.length) {
// move element in elements-array
elements.splice(oldPos, 1) // remove 1 element at oldPos
elements.splice(newPos, 0, element) // at newPos, delete 0, add element
this.draggedElementIndex = newPos
this.initialDragPos_Y = event.pageY
this.setState({
elements: elements
})
}
}
},
render () {
const {elements} = this.state
let content = []
elements.map((element, index) => {
let boundMouseDown = this.onMouseDownOnListItem.bind(this, index)
content.push(
<div ref={'ListItem_' + index} onMouseDown={boundMouseDown}>{element} </div>
)
})
return (
<div ref={'myList'}>
{content}
</div>
)
}
After the first leave-event you should call again onMouseDownOnListItem event in order to wait for another addEventListener.

Categories