How to create countup timer with keyboard events in js - javascript

I am creating a program where the timer starts when i hit "keyup" and stops when i hit "keydown" and resets the timer when i hit "keydown" next time.
const Timer = () => {
const [timer, setTimer] = useState(0);
let state = 0;
let isFired = false;
const increment = useRef(null);
useEffect(() => {
window.addEventListener('keydown', (e) => {
if (isFired) {
if (e.code === 'Space' && state === 2) {
e.stopPropagation();
isFired = false;
handleReset();
}
if (e.code === 'Space' && state === 1) {
clearInterval(increment.current);
state = 2;
}
}
});
window.addEventListener('keyup', (e) => {
if (!isFired) {
if (e.code === 'Space' && state === 0) {
isFired = true;
state = 1;
handleStart();
}
}
});
return () => {
window.removeEventListener('keydown', handleReset);
window.removeEventListener('keyup', handleStart);
};
}, []);
const handleStart = () => {
increment.current = setInterval(() => {
// DON'T COPY THIS BIT
setTimer((timer) => timer + 10);
}, 10);
};
const handleReset = () => {
clearInterval(increment.current);
setTimer(0);
state = 0;
};
// DON'T COPY THIS BIT
const formatTime = () => {
console.log(timer);
const getMilliSeconds = `0${timer % 60}`.slice(-2);
const seconds = `${Math.floor(timer / 60)}`;
const getSeconds = `0${seconds % 60}`.slice(-2);
const getMinutes = `0${Math.floor(timer / 3600)}`.slice(-2);
// return `${getHours} : ${getMinutes} : ${getSeconds}`;
if (getMinutes === '00') {
return `${getSeconds}.${getMilliSeconds}`;
} else {
return `${getMinutes} : ${getSeconds} : ${getMilliSeconds} `;
}
};
// const formatTime = () => {
// // const milliSeconds = `0${}`;
// const seconds = `0${Math.floor(timer / 100)}`;
// const minute = `0${Math.floor(timer / 3600)}`.slice(-2);
// return `${minute}.${seconds}`;
// };
return (
<div className="Timer">
<h1>{formatTime()}</h1>
</div>
);
};
i have tried this so far
it works most of the time but sometimes it gets glitchy
and i know the time is not formated properly and also the increment is also wrong. Sometimes it stops on the "keydown" and fires the "keyup" in the same stroke making it reset the timer starting from zero I don't exactly know that if it fires keyup on the same stroke but it seems like it does
this is a link to what i have done so far timer

I checked your code and found it needs too many changes.
You are using state and isFired as variables only but you need their persisted values on rerendering. Therefore, these must be states.
You are not unbinding the same listener which you binded on keyup and keydown.
As per your current code, your timer will start on 1st keyup and then next keydown it will stop as such where it was. Now, on next keydown it will reset to 0 and then on keyup, again timer will start from 0.
I modified your code and see working changes here,
https://codesandbox.io/s/xenodochial-shannon-im8zt?file=/src/App.js

Related

React clearInterval not working in class Component

I am trying to make a timer that will start at the beginning of the sorting visualization and run until sorting is over. The timer starts accordingly but does not stop after sorting. this works absolutely fine in functional Component (with useEffect hook) but does not work in class Component.
here is my startTimer function -
startTimer = () => {
let isAlgo = this.state.isAlgorithmSortOver;
let interval;
if (isAlgo === true) {
interval = setInterval(() => {
this.setState({
time: this.state.time + 10,
});
}, 10);
} else if (isAlgo === false) {
clearInterval(interval);
}
// return () => clearInterval(interval);
};
and here is startVisualizer function -
startVisualizer = () => {
let steps = this.state.arraySteps;
let colorSteps = this.state.colorSteps;
this.clearTimeouts();
let timeouts = [];
let i = 0;
while (i < steps.length - this.state.currentStep) {
let timeout = setTimeout(() => {
let currentStep = this.state.currentStep;
this.setState({
array: steps[currentStep],
colorElement: colorSteps[currentStep],
currentStep: currentStep + 1,
isAlgorithmSortOver: false,
});
//? comparing the currentStep with arraySteps and the state of isAlgorithmSortOver will remain false until the array is fully sorted.. Adding '+ 1' to currentStep because the arraySteps state always will be '+1' bigger than the currentStep..
if (currentStep + 1 === i) {
this.setState({
isAlgorithmSortOver: true,
});
}
timeouts.push(timeout);
}, this.state.delayAnimation * i);
i++;
}
this.startTimer();
this.setState({
timeouts: timeouts,
// isAlgorithmSortOver: false,
});
};
because you are not clearing the interval. Try to save interval's id to state like this:
startTimer = () => {
let isAlgo = this.state.isAlgorithmSortOver;
if (isAlgo === true) {
interval = setInterval(() => {
this.setState({
time: this.state.time + 10,
});
}, 10);
this.setState({interval})
}
};
Then you can then call clearInterval wherever you want, like this:
clearInterval(this.state.interval)
You also should bring out timeouts.push(timeout) from setTimeout where in while. Because, otherwise timeouts.push(timeout) does not work synchronously, it works after a while.

HTML onmousedown event not working on mobile

I have made a prank calculator which takes an input from the user of the answer to be displayed when the '=' button is pressed. The input is taken in the form of a prompt in JavaScript which is triggered by long-pressing the '0' button. The long press feature is implemented by setting a timeout of 2 seconds when the buttons is pressed (using onmousedown) and clearing the timeout when the mouse key is lifted (onmouseup). This works fine on computers, but I don't know how to implement this on mobile. I have tried the onpointerdown and onpointerup events too. These also work fine on computers, but when I long-press on mobile, the prompt displays a second time shortly afterwards. The HTML and JavaScript code relating to this is as follows:
HTML:
<td>
<button
class="calculator-button"
onclick="insert(0)"
onmousedown="activateMagic()"
onmouseup="disableMagic()"
>
0
</button>
</td>
JavaScript:
let answer = null;
const input = document.getElementById("calcInput");
let pressTimer;
const insert = (objToInsert) => {
input.value += objToInsert;
};
const clearInput = () => {
input.value = null;
answer = null;
};
const activateMagic = () => {
pressTimer = window.setTimeout(() => {
answer = prompt("Enter the prank answer: ");
}, 2000);
return false;
};
const disableMagic = () => {
clearTimeout(pressTimer);
};
const findAnswer = () => {
if (answer == null) {
let problemAnswer = eval(input.value);
setTimeout(() => {
input.value = problemAnswer;
}, 10);
}
input.value = answer;
};
Thanks in advance.
I found an answer!! #DanyloHalaiko was right. The touchstart and touchend event listeners actually work! To those of you interested or those of you seeing this in the future, this is my final code:
HTML:
<td>
<button
class="calculator-button"
onclick="insert(0)"
onmousedown="activateMagic()"
onmouseup="disableMagic()"
id="activateBtn"
>
0
</button>
</td>
JavaScript:
let answer = null;
const input = document.getElementById("calcInput");
const activateBtn = document.getElementById("activateBtn");
let pressTimer;
const insert = (objToInsert) => {
input.value += objToInsert;
};
const clearInput = () => {
input.value = null;
answer = null;
};
const activateMagic = () => {
pressTimer = window.setTimeout(() => {
answer = prompt("Enter the prank answer: ");
}, 2000);
return false;
};
const disableMagic = () => {
clearTimeout(pressTimer);
};
activateBtn.addEventListener("touchstart", activateMagic);
activateBtn.addEventListener("touchend", disableMagic);
const findAnswer = () => {
if (answer == null) {
let problemAnswer = eval(input.value);
setTimeout(() => {
input.value = problemAnswer;
}, 10);
}
input.value = answer;
};

React - get time of long pressing button in seconds

I'm trying to return the number of seconds whilst holding in a button.
eg: "click+ hold, inits -> counts & displays 1, 2, 3, 4, 5 -> leaves button -> resets back to 0"
I've gotten close. It works fine, in my console, but whenever I try to update the state it ends up in an infinite loop.
import React, { useState, useEffect } from "react";
const Emergency = () => {
let counter = 0;
let timerinterval;
const [ms, setMs] = useState(counter);
const timer = start => {
console.log("tick tock");
console.log(start);
if (start === true && counter >= 1) {
timerinterval = setInterval(() => {
counter += 1;
console.log(counter);
setMs(counter); //When I remove this, the infinite loop disappears.
}, [1000]);
} else {
setMs(0);
}
};
const pressingDown = e => {
console.log("start");
e.preventDefault();
counter = 1;
timer(true);
};
const notPressingDown = e => {
console.log("stop");
e.preventDefault();
timer(false);
setMs(0);
clearInterval(timerinterval);
};
return (
<>
<button
onMouseDown={pressingDown}
onMouseUp={notPressingDown}
onTouchStart={pressingDown}
onTouchEnd={notPressingDown}
className="button is-primary mt-3"
>
Emergency
</button>
<br />
Time holding it is.... {ms}
</>
);
};
export default Emergency;
An easy way would be to calculate the time difference between mouseDown and mouseUp, but for the sake of UX, I would like to {ms} to update live as I'm holding the button.
Any suggestions?
Thanks!
There are two problems with your code:
You are not clearing interval. timeInterval is a new variable whenever your component is re-rendered. You need to use ref (const timeInterval = React.useRef(null); ... timeInterval.current = ... ; clearInterval(timeInterval.current);
Also you need to remove counter = 1; from your pressingDowm function, because before each setMs you are incrementing it by one
const Emergency = () => {
let counter = 0;
let timerinterval = React.useRef((null as unknown) as any);
const [ms, setMs] = React.useState(counter);
const timer = (start: any) => {
console.log('tick tock');
console.log(start);
if (start === true && counter >= 1) {
timerinterval.current = setInterval(() => {
console.log(counter);
setMs(counter); //When I remove this, the infinite loop disappears.
counter += 1;
//#ts-ignore
}, [1000]);
} else {
setMs(0);
}
};
const pressingDown = (e: any) => {
console.log('start');
e.preventDefault();
counter = 1;
timer(true);
};
const notPressingDown = (e: any) => {
console.log('stop');
e.preventDefault();
timer(false);
setMs(0);
clearInterval(timerinterval.current);
};
return (
<>
<button
onMouseDown={pressingDown}
onMouseUp={notPressingDown}
onTouchStart={pressingDown}
onTouchEnd={notPressingDown}
className="button is-primary mt-3"
>
Emergency
</button>
<br />
Time holding it is.... {ms}
</>
);
};
This is edited code (with some TypeScript stuff, sorry for that)

Selective timeout based events handling: immediate first, debounce next

Let's say there are random sequences of external actions (e.g. scroll events). I need to handle the first action immediately, then dismiss all actions occurred with intervals less than some given delta, and then handle the next one which should be delayed for that delta. Further actions should be processed in the same manner.
This looks like a combination of debounce-immediate and simple debounce. I prepared a diagram to demonstrate the idea.
What is the best solution/approach here? I wonder if there is some ready-made pattern...
UPDATE
I would like to thank all participants! For the research I created plunker with four five different realizations suggested in answers: https://plnkr.co/N9nAwQ.
const handler = [
processEvent, // normal
debounceNext(processEvent, DELAY), // dhilt
makeRateLimitedEventHandler(DELAY, processEvent), // user650881
debounceWithDelay(processEvent, DELAY, 0), // willem-dhaeseleer
_.debounce(processEvent, DELAY, {leading: true}) // lodash debounce + leading,
debounceish(DELAY, processEvent) //Mikk3lRo
];
A great news was the Lodash has a leading-flag debounce implementation which satisfies the issue (thanks to Willem D'Haeseleer). And here is the cool demo from Mikk3lRo' answer, he also provided some useful synthesis.
I investigated the sources and the results: form just visual point to memory allocation stuff... I didn't find any performance issues, and the views seem okey. So the ultima ratio was the code itself. All sources were converted to ES6 (as you can see in Plunker) for I can compare them fully. I excluded my own try (it is a bit excessive, despite I like how it looks). The timestamp version is very interesting! The postDelay version's nice, though it wasn't a requested feature (so that snippet demo has double delay for two lodash demos).
I decided not to have a lodash dependency (in other way I certainly would use lodash debounce with leading option), so I chose debounceish by Mikk3lRo.
PS I would like to share that little bounty (unfortunately there is no such an option) or even take some more scores from my reputation for it (but not 200, is too much and would be unfair to the winner which would have only 100). I even can't vote twice... Nevermind.
A very simple solution in vanilla JS using a single timer:
function debounceish(delta, fn) {
var timer = null;
return function(e) {
if (timer === null) {
//Do now
fn(e);
//Set timer that does nothing (but is not null until it's done!)
timer = setTimeout(function(){
timer = null;
}, delta);
} else {
//Clear existing timer
clearTimeout(timer);
//Set a new one that actually does something
timer = setTimeout(function(){
fn(e);
//Set timer that does nothing again
timer = setTimeout(function(){
timer = null;
}, delta);
}, delta);
}
};
}
function markEvt(e) {
var elm = document.createElement('div');
elm.style.cssText = 'position:absolute;background:tomato;border-radius:3px;width:6px;height:6px;margin:-3px;';
elm.style.top = e.clientY + 'px';
elm.style.left = e.clientX + 'px';
document.body.appendChild(elm);
}
document.addEventListener('click', debounceish(2000, markEvt));
<p>Click somewhere (2000ms delta) !</p>
Comparing 6 proposals using the same type of visualization:
var methods = {
default: function(delay, fn) {
return fn;
},
dhilt_debounceNext: (delay, cb) => {
let timer = null;
let next = null;
const runTimer = (delay, event) => {
timer = setTimeout(() => {
timer = null;
if(next) {
next(event);
next = null;
runTimer(delay);
}
}, delay);
};
return (event) => {
if(!timer) {
cb(event);
}
else {
next = cb;
clearTimeout(timer);
}
runTimer(delay, event);
}
},
Mikk3lRo_debounceish(delta, fn) {
var timer = null;
return function(e) {
if (timer === null) {
//Do now
fn(e);
//Set timer that does nothing (but is not null until it's done!)
timer = setTimeout(function(){
timer = null;
}, delta);
} else {
//Clear existing timer
clearTimeout(timer);
//Set a new one that actually does something
timer = setTimeout(function(){
fn(e);
//Set timer that does nothing again
timer = setTimeout(function(){
timer = null;
}, delta);
}, delta);
}
};
},
user650881_makeRateLimitedEventHandler: function(delta_ms, processEvent) {
var timeoutId = 0; // valid timeoutId's are positive.
var lastEventTimestamp = 0;
var handler = function (evt) {
// Any untriggered handler will be discarded.
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = 0;
}
var curTime = Date.now();
if (curTime < lastEventTimestamp + delta_ms) {
// within delta of last event, postpone handling
timeoutId = setTimeout(function () {
processEvent(evt);
}, delta_ms);
} else {
// long enough since last event, handle now
processEvent(evt);
}
// Set lastEventTimestamp to time of last event after delta test.
lastEventTimestamp = Date.now();
};
return handler;
},
Willem_DHaeseleer_debounceWithDelay: (delay, func) => {
let postDebounceWait;
let timeOutLeading = false;
const debounced = _.debounce((...args) => {
// wrap the handler so we can add an additional timeout to the debounce invocation
if (timeOutLeading) {
/*
for the first invocation we do not want an additional timeout.
We can know this is the leading invocation because,
we set timeOutLeading immediately to false after invoking the debounced function.
This only works because the debounced leading functionality is synchronous it self.
( aka it does not use a trampoline )
*/
func(...args);
} else {
postDebounceWait = setTimeout(() => {
func(...args)
}, delay);
}
}, delay, {leading: true});
return (...args) => {
// wrap the debounced method it self so we can cancel the post delay timer that was invoked by debounced on each invocation.
timeOutLeading = true;
clearTimeout(postDebounceWait);
debounced(...args);
timeOutLeading = false;
}
},
Willem_DHaeseleer_lodashWithLeading: (delta, cb) => {
return _.debounce(cb, delta * 2, {leading: true});
},
Javier_Rey_selfCancelerEventListener: function (delta, fn) {
return function(ev) {
var time = new Date().getTime();
if (ev.target.time && time - ev.target.time < delta) {return;}
ev.target.time = time;
fn(ev);
};
},
};
var method_count = 0;
var colors = ['grey', 'tomato', 'green', 'blue', 'red', 'orange', 'yellow', 'black'];
function markEvt(method) {
var style = 'position:absolute;border-radius:3px;width:6px;height:6px;margin:-3px;';
style += 'background:' + colors[method_count] + ';';
if (method_count > 0) {
style += 'transform:rotate(' + Math.floor(360 * method_count / (Object.keys(methods).length - 1)) + 'deg) translateY(-8px);';
}
var elm = document.createElement('div');
elm.innerHTML = '<span style="width:.8em;height:.8em;border-radius:.4em;display:inline-block;background:' + colors[method_count] + '"></span> ' + method;
document.body.appendChild(elm);
method_count++;
return function(e) {
elm = document.createElement('div');
elm.style.cssText = style;
elm.style.top = e.clientY + 'px';
elm.style.left = e.clientX + 'px';
document.body.appendChild(elm);
};
}
for (var method in methods) {
document.addEventListener('click', methods[method](2000, markEvt(method)));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Note that I needed to make minor adjustments to some of the methods to get a common interface. Adapting Cully's answer took more effort than I was willing to put in considering the comments suggest it doesn't do what the OP wants anyway.
It should be pretty clear that Javier Rey's approach behaves completely differently from the rest. Dhilt, user650881 and my own methods seem consistent. Both of Willem D'Haeseleer's methods have double the delay (and other subtle differences), but seem to behave consistently too. As far as I understand the double delay is completely intentional, though that is not how I understand the OP.
I would say that Willem D'Haeseleer's lodash method is without a doubt the simplest - if you already use lodash that is. Without external dependencies my method is IMO simplest - but I may be biased on that one ;)
You might track the last event time and only create a timer event when a follow-up check is required.
function makeRateLimitedEventHandler(delta_ms, processEvent) {
var timeoutId = 0; // valid timeoutId's are positive.
var lastEventTimestamp = 0;
var handler = function (evt) {
// Any untriggered handler will be discarded.
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = 0;
}
var curTime = Date.now();
if (curTime < lastEventTimestamp + delta_ms) {
// within delta of last event, postpone handling
timeoutId = setTimeout(function () {
processEvent(evt);
}, delta_ms);
} else {
// long enough since last event, handle now
processEvent(evt);
}
// Set lastEventTimestamp to time of last event after delta test.
lastEventTimestamp = Date.now();
};
return handler;
}
var DELTA_MS = 5000;
var processEvent = function (evt) { console.log('handling event'); };
el.addEventHandler('some-event', makeRateLimitedEventHandler(DELTA_MS, processEvent));
The behavior in your visual is no different then the standard lodash debouncing behavior with the leading option, the only difference is that your only displaying half of the delta instead of the full delta.
Therefore, your solution can be as simple as this.
_.debounce(cb, delta * 2, {leading: true});
https://lodash.com/docs/4.17.4#debounce
If you want the last delay to be longer, you can solve that by wrapping both the debounced method and the handler. That way you can set the timeout in the handler, and cancel it in the debounce wrapper.
You do have to check if the current invocation was the leading one in order to not add the timeout in that case.
It could look like this:
const _ = require('lodash');
const bb = require('bluebird');
function handler(arg) {
console.log(arg, new Date().getSeconds());
}
const debounceWithDelay = (func, delay, postDelay) => {
let postDebounceWait;
let timeOutLeading = false;
const debounced = _.debounce((...args) => {
// wrap the handler so we can add an additional timeout to the debounce invocation
if (timeOutLeading) {
/*
for the first invocation we do not want an additional timeout.
We can know this is the leading invocation because,
we set timeOutLeading immediately to false after invoking the debounced function.
This only works because the debounced leading functionality is synchronous it self.
( aka it does not use a trampoline )
*/
func(...args);
} else {
postDebounceWait = setTimeout(() => {
func(...args)
}, postDelay);
}
}, delay, {leading: true});
return (...args) => {
// wrap the debounced method it self so we can cancel the post delay timer that was invoked by debounced on each invocation.
timeOutLeading = true;
clearTimeout(postDebounceWait);
debounced(...args);
timeOutLeading = false;
}
};
const debounceDelay = debounceWithDelay(handler, 50, 2000);
(async function () {
console.log(new Date().getSeconds());
debounceDelay(1);
debounceDelay(2);
debounceDelay(3);
debounceDelay(4);
await bb.delay(3000);
debounceDelay(5);
await bb.delay(3000);
debounceDelay(6);
debounceDelay(7);
debounceDelay(8);
})();
Runnable script:
Here's something that I think works the way you described. If not, it's at least something to go off of.
// set up the event bus
const start = getMilli()
const bus = createBus()
bus.on('event', e => console.log(`[${getPassage(start)}] [${e}] original bus: saw event`))
const wrappedBus = wrapBus(1600, 'event', bus)
wrappedBus.on('event', e => console.log(`[${getPassage(start)}] [${e}] wrapped bus: saw event`))
wrappedBus.on('skipped', e => console.log(`[${getPassage(start)}] [${e}] skipped by wrapped bus`))
wrappedBus.on('last before interval', e => console.log(`[${getPassage(start)}] [${e}] this was the last event before the end of the interval`))
wrappedBus.on('interval tick', _ => console.log(`[${getPassage(start)}] interval tick`))
// trigger events on the bus every so often
let totalTime = 0
const intervalTime = 300
setInterval(() => {
totalTime += intervalTime
bus.trigger('event', totalTime)
}, intervalTime)
function getMilli() {
return (new Date()).getTime()
}
function getPassage(from) {
return getMilli() - from
}
// creates a simple event bus
function createBus() {
const cbs = {}
return {
on: (label, cb) => {
if(cbs.hasOwnProperty(label)) cbs[label].push(cb)
else cbs[label] = [cb]
},
trigger: (label, e) => {
if(cbs.hasOwnProperty(label)) cbs[label].forEach(f => f(e))
},
}
}
// creates a new bus that should trigger the way you described
function wrapBus(waitInterval, eventLabel, bus) {
const newBus = createBus()
let deliveredFirst = false
let gotIgnoredEvent = false
let lastIgnoredEvent = undefined
setInterval(() => {
// just here so we know when this interval timer is ticking
newBus.trigger('interval tick', null)
// push the last event before the end of this interval
if(gotIgnoredEvent) {
gotIgnoredEvent = false
deliveredFirst = false
newBus.trigger(eventLabel, lastIgnoredEvent)
newBus.trigger('last before interval', lastIgnoredEvent)
}
}, waitInterval)
bus.on(eventLabel, function(e) {
if(!deliveredFirst) {
newBus.trigger(eventLabel, e)
deliveredFirst = true
gotIgnoredEvent = false
}
else {
gotIgnoredEvent = true
lastIgnoredEvent = e
// this is here just to see when the wrapped bus skipped events
newBus.trigger('skipped', e)
}
})
return newBus
}
Here's my try:
const debounceNext = (cb, delay) => {
let timer = null;
let next = null;
const runTimer = (delay, event) => {
timer = setTimeout(() => {
timer = null;
if(next) {
next(event);
next = null;
runTimer(delay);
}
}, delay);
};
return (event) => {
if(!timer) {
cb(event);
}
else {
next = cb;
clearTimeout(timer);
}
runTimer(delay, event);
}
};
const processEvent = (event) => console.log(event);
const debouncedHandler = debounceNext(processEvent, 125);
myElement.addEventListener('scroll', debouncedHandler);

How to detect a long press on a button/image

I am working on a phonegap project. I need to implement a long press event. How can we detect long press on a image/button using JavaScript?
$('#target').mousedown(function() {
alert('Handler for .mousedown() called.');
//start a timer
});
$('#target').mouseup(function() {
alert('Handler for .mouseup() called.');
//stop the timer and decide on long click
});
One way that comes in my mind is:
In the start of the onclick event, record the time, this gives you the time of the first click.
Then check the time span. Suppose, you say 5 seconds time span is a long press event. If check is success, this is a long press event.
head-on solution:
const btn = document.querySelector("button");
const info = document.querySelector("h3");
let time;
btn.onmousedown = () => {
time = new Date(Date.now()).getSeconds();
setTimeout(() => {
let timecurrent = new Date(Date.now()).getSeconds();
if (timecurrent - time == 5) {
info.innerText = "yes pressed";
time = undefined;
}
}, 5000);
}
btn.onmouseup = () => {
time = undefined;
info.innerText = "no pressed";
}
<button>press me</button>
<h3>No pressed</h3>
Function solution:
function catchLongPress(element, delay) {
const elem = document.querySelector(element);
let time;
elem.onmousedown = () => {
time = new Date(Date.now()).getSeconds();
setTimeout(() => {
let timecurrent = new Date(Date.now()).getSeconds();
if (timecurrent - time == delay) {
alert("yes pressed");
time = undefined;
}
}, delay * 1000);
}
elem.onmouseup = () => {
time = undefined;
alert("no pressed");
}
}
catchLongPress("button", 2);
<button>press me</button>
<h3>No pressed</h3>

Categories

Resources