Touchscreen Press & Hold - javascript

I want the user to be able to touch and hold a button, and after a certain period of time, a function is called.
E.g. the button text starts as black, turns orange after 0.2s of pressing, and then green after 0.5s of pressing. If it is green, a function, myFunction(), is triggered.
I have made a start on it, more help would be appreciated. Thanks :)
var btn = document.getElementById("pressBtn");
var pressedTime = 0;
var elaspedHoldTime;
btn.onmousedown = function() {
if (pressedTime != 0) {
pressedTime = performance.now();
} else {
elaspedHoldTime = performance.now() - pressedTime;
}
if (elaspedHoldTime > 200) {
btn.style.color = "orange";
}
if (elaspedHoldTime > 1000) {
btn.style.color = "green";
}
};
btn.addEventListener("mouseup", function() {
elaspedHoldTime = performance.now() - pressedTime;
btn.style.color = "black";
if (elaspedHoldTime > 500) {
console.log("Call Function Here");
}
pressedTime = 0;
elaspedHoldTime = 0;
});
<button id="btn">Button Text</button>
(It also has a bug for some reason)

UPDATED
for not fully functioanlity I edited the code and also changed the logic
I come up with variable timerValue which increases in every 0.1s when mouse is pressed and when that timerValue reaches 2, button changes color to orange and on 5 changes on red and prints triggered as well
and on mouseup which will be called after user picks up finger from mouse, timerValue backs to 0 and resets also button class
interval is variable where are I store setInterval function and on mouse release I clear it
I included also paragpraph tag where is shown the timer to understand how it works
const btn = document.querySelector(".btn")
const timer = document.querySelector("p") //can be deleted
let timerValue = 0
let interval;
const mousePress = () => {
interval = setInterval(() => {
timerValue++
timer.innerHTML = timerValue //can be deleted
if(timerValue === 2) btn.classList.toggle("orange")
if(timerValue === 5) {
btn.classList.toggle("red")
console.log("triggered")
}
}, 100)
}
const mouseRelease = () => {
clearInterval(interval)
timerValue = 0
timer.innerHTML = timerValue //can be deleted
btn.className = "btn"
}
btn.addEventListener("mousedown", mousePress)
btn.addEventListener("mouseup", mouseRelease)
.btn.orange{
color: orange;
}
.btn.red{
color: red;
}
<button class="btn">Click</button>
<p></p>

mousedown, mouseup, touchstart, touchend triggers just once when the key is pressed.
To check, if the user is still holding it, you can check for a truly variable inside a setTimeout() function-call, stop the timeout on release or use a setInterval()-function-call that only runs when it's pressed.
For example:
let pressed = false;
button.addEventListener("mousedown", () => {
pressed = true;
setTimeout(() => {
if (pressed) { ... }
}, 200);
});
button.addEventListener("mouseup", () => { pressed = false; });
let timer = null;
button.addEventListener("mousedown", () => {
pressed = true;
timer = setTimeout(() => { ... }, 200);
});
button.addEventListener("mouseup", () => { clearTimeout(timer) });
As there is already an answer with setTimeout(), here is another solution with setInterval().
let vars = {
interval: null, // used to store the interval id
start: 0, // changes to Date.now() on every start.
// used to avoid myFunction be called more than once per "hold"
myFunctionCalled: false
}, myFunction = () => console.log("Yes...?");
button.addEventListener("mousedown", (event) => {
// avoid start w/ rightclick
if (event.which == 1) {
vars.start = Date.now();
vars.myFunctionCalled = false;
vars.interval = setInterval(() => {
let dur = Date.now() - vars.start;
if (dur > 1000) {
button.style.color = "green";
if (!vars.myFunctionCalled) {
vars.myFunctionCalled = true;
myFunction();
}
} else if (dur > 500) {
button.style.color = "orange";
} else if (dur > 100) {
button.style.color = "red";
}
}, 10);
}
});
// using window, so the user can move the mouse
window.addEventListener("mouseup", (event) => {
// checking again for the mouse key, to avoid disabling it on rightlick
if (vars.interval && event.which == 1) {
// stop the interval and reset the color to default
clearInterval(vars.interval);
button.style.color = "";
vars.interval = null;
}
})
<button id="button">Hold me</button>

If you're making it for a touchscreen, you need to use TouchEvents:
ontouchstart -> when a target is being pressed by a finger
ontouchmove -> the active finger moves off the target
ontouchcancel -> when the the target has lost focus of a touch event
ontouchend -> lifting the finger off of the target
MouseEvents are reserved for mouse / trackpad-controlled devices, such as Computers.
TouchEvents are reserved for touch-screen devices, such as tablets and phones.
Also read this answer for code.

Related

setTimeout gets faster and faster - how do I pause it?

I have this script here, and it works great. Once the element scrolls into view, it transforms the element by scrolling it up. But I can't get it to stop once it scrolls out of view, and what's worse, it gets faster and faster every time it scrolls into view! How do I reset the timeout? Clearly I'm using clearTimeout wrong, but I don't know how to fix it.
observer = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
reviewScroll();
} else {
stopReviewScroll();
//What do I put here to pause reviewScroll?
}
});
});
var reviewscroller = document.querySelector('.ReviewList__reviewCardContainer__1hiY0');
function reviewScroll() {
reviewscroller.style.opacity = 1;
i++;
reviewscroller.style.transform = 'translate3D(0px, -'+i+'px , 0px)';
opac = i * .001;
reviewscroller.style.opacity = 1-opac;
clearTimeout(setTimeout(reviewScroll, 40));
setTimeout(reviewScroll, 40);
if (reviewscroller.style.opacity < -0.25) {
reviewscroller.opacity = 1;
i = 0;
reviewscroller.style.transform = 'translate3D(0px, -'+i+'px , 0px)';
}
}
function stopReviewScroll() {
clearTimeout(reviewScroll);
}
document.querySelectorAll('.ReviewList__reviewCardContainer__1hiY0').forEach(image => { observer.observe(image); });
You should be canceling the old timer and installing a new one, like so:
var timerId = null;
function reviewScroll() {
// ...
if (timerId) {
clearTimeout(timerId);
}
timerId = setTimeout(reviewScroll, 40);
// ...
}

How can I pause and resume a setInterval function with Jquery/JS within a loop? [duplicate]

How do I pause and resume the setInterval() function using Javascript?
For example, maybe I have a stopwatch to tell you the number of seconds that you have been looking at the webpage. There is a 'Pause' and 'Resume' button. The reason why clearInterval() would not work here is because if the user clicks on the 'Pause' button at the 40th second and 800th millisecond, when he clicks on the 'Resume' button, the number of seconds elapsed must increase by 1 after 200 milliseconds. If I use the clearInterval() function on the timer variable (when the pause button is clicked) and then using the setInterval() function on the timer variable again (when the resume button is clicked), the number of seconds elapsed will increase by 1 only after 1000 milliseconds, which destroys the accuracy of the stopwatch.
So how do I do that?
You could use a flag to keep track of the status:
var output = $('h1');
var isPaused = false;
var time = 0;
var t = window.setInterval(function() {
if(!isPaused) {
time++;
output.text("Seconds: " + time);
}
}, 1000);
//with jquery
$('.pause').on('click', function(e) {
e.preventDefault();
isPaused = true;
});
$('.play').on('click', function(e) {
e.preventDefault();
isPaused = false;
});
h1 {
font-family: Helvetica, Verdana, sans-serif;
font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Seconds: 0</h1>
<button class="play">Play</button>
<button class="pause">Pause</button>
This is just what I would do, I'm not sure if you can actually pause the setInterval.
Note: This system is easy and works pretty well for applications that don't require a high level of precision, but it won't consider the time elapsed in between ticks: if you click pause after half a second and later click play your time will be off by half a second.
You shouldn't measure time in interval function. Instead just save time when timer was started and measure difference when timer was stopped/paused. Use setInterval only to update displayed value. So there is no need to pause timer and you will get best possible accuracy in this way.
While #Jonas Giuro is right when saying that:
You cannot PAUSE the setInterval function, you can either STOP it (clearInterval), or let it run
On the other hand this behavior can be simulated with approach #VitaliyG suggested:
You shouldn't measure time in interval function. Instead just save time when timer was started and measure difference when timer was stopped/paused. Use setInterval only to update displayed value.
var output = $('h1');
var isPaused = false;
var time = new Date();
var offset = 0;
var t = window.setInterval(function() {
if(!isPaused) {
var milisec = offset + (new Date()).getTime() - time.getTime();
output.text(parseInt(milisec / 1000) + "s " + (milisec % 1000));
}
}, 10);
//with jquery
$('.toggle').on('click', function(e) {
e.preventDefault();
isPaused = !isPaused;
if (isPaused) {
offset += (new Date()).getTime() - time.getTime();
} else {
time = new Date();
}
});
h1 {
font-family: Helvetica, Verdana, sans-serif;
font-size: 12px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>Seconds: 0</h1>
<button class="toggle">Toggle</button>
Why not use a simpler approach? Add a class!
Simply add a class that tells the interval not to do anything. For example: on hover.
var i = 0;
this.setInterval(function() {
if(!$('#counter').hasClass('pauseInterval')) { //only run if it hasn't got this class 'pauseInterval'
console.log('Counting...');
$('#counter').html(i++); //just for explaining and showing
} else {
console.log('Stopped counting');
}
}, 500);
/* In this example, I'm adding a class on mouseover and remove it again on mouseleave. You can of course do pretty much whatever you like */
$('#counter').hover(function() { //mouse enter
$(this).addClass('pauseInterval');
},function() { //mouse leave
$(this).removeClass('pauseInterval');
}
);
/* Other example */
$('#pauseInterval').click(function() {
$('#counter').toggleClass('pauseInterval');
});
body {
background-color: #eee;
font-family: Calibri, Arial, sans-serif;
}
#counter {
width: 50%;
background: #ddd;
border: 2px solid #009afd;
border-radius: 5px;
padding: 5px;
text-align: center;
transition: .3s;
margin: 0 auto;
}
#counter.pauseInterval {
border-color: red;
}
<!-- you'll need jQuery for this. If you really want a vanilla version, ask -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="counter"> </p>
<button id="pauseInterval">Pause</button></p>
I've been looking for this fast and easy approach for ages, so I'm posting several versions to introduce as many people to it as possible.
i wrote a simple ES6 class that may come handy.
inspired by https://stackoverflow.com/a/58580918/4907364 answer
export class IntervalTimer {
callbackStartTime;
remaining = 0;
paused = false;
timerId = null;
_callback;
_delay;
constructor(callback, delay) {
this._callback = callback;
this._delay = delay;
}
pause() {
if (!this.paused) {
this.clear();
this.remaining = new Date().getTime() - this.callbackStartTime;
this.paused = true;
}
}
resume() {
if (this.paused) {
if (this.remaining) {
setTimeout(() => {
this.run();
this.paused = false;
this.start();
}, this.remaining);
} else {
this.paused = false;
this.start();
}
}
}
clear() {
clearInterval(this.timerId);
}
start() {
this.clear();
this.timerId = setInterval(() => {
this.run();
}, this._delay);
}
run() {
this.callbackStartTime = new Date().getTime();
this._callback();
}
}
usage is pretty straightforward,
const interval = new IntervalTimer(console.log('aaa'), 3000);
interval.start();
interval.pause();
interval.resume();
interval.clear();
My simple way:
function Timer (callback, delay) {
let callbackStartTime
let remaining = 0
this.timerId = null
this.paused = false
this.pause = () => {
this.clear()
remaining -= Date.now() - callbackStartTime
this.paused = true
}
this.resume = () => {
window.setTimeout(this.setTimeout.bind(this), remaining)
this.paused = false
}
this.setTimeout = () => {
this.clear()
this.timerId = window.setInterval(() => {
callbackStartTime = Date.now()
callback()
}, delay)
}
this.clear = () => {
window.clearInterval(this.timerId)
}
this.setTimeout()
}
How to use:
let seconds = 0
const timer = new Timer(() => {
seconds++
console.log('seconds', seconds)
if (seconds === 8) {
timer.clear()
alert('Game over!')
}
}, 1000)
timer.pause()
console.log('isPaused: ', timer.paused)
setTimeout(() => {
timer.resume()
console.log('isPaused: ', timer.paused)
}, 2500)
function Timer (callback, delay) {
let callbackStartTime
let remaining = 0
this.timerId = null
this.paused = false
this.pause = () => {
this.clear()
remaining -= Date.now() - callbackStartTime
this.paused = true
}
this.resume = () => {
window.setTimeout(this.setTimeout.bind(this), remaining)
this.paused = false
}
this.setTimeout = () => {
this.clear()
this.timerId = window.setInterval(() => {
callbackStartTime = Date.now()
callback()
}, delay)
}
this.clear = () => {
window.clearInterval(this.timerId)
}
this.setTimeout()
}
The code is written quickly and did not refactored, raise the rating of my answer if you want me to improve the code and give ES2015 version (classes).
I know this thread is old, but this could be another solution:
var do_this = null;
function y(){
// what you wanna do
}
do_this = setInterval(y, 1000);
function y_start(){
do_this = setInterval(y, 1000);
};
function y_stop(){
do_this = clearInterval(do_this);
};
The following code, provides a precision way to pause resume a timer.
How it works:
When the timer is resumed after a pause, it generates a correction cycle using a single timeout, that will consider the pause offset (exact time when the timer was paused between cycles). After the correction cycle finishes, it schedules the following cycles with a regular setInteval, and continues normally the cycle execution.
This allows to pause/resume the timer, without losing the sync.
Code :
function Timer(_fn_callback_ , _timer_freq_){
let RESUME_CORRECTION_RATE = 2;
let _timer_statusCode_;
let _timer_clockRef_;
let _time_ellapsed_; // will store the total time ellapsed
let _time_pause_; // stores the time when timer is paused
let _time_lastCycle_; // stores the time of the last cycle
let _isCorrectionCycle_;
/**
* execute in each clock cycle
*/
const nextCycle = function(){
// calculate deltaTime
let _time_delta_ = new Date() - _time_lastCycle_;
_time_lastCycle_ = new Date();
_time_ellapsed_ += _time_delta_;
// if its a correction cicle (caused by a pause,
// destroy the temporary timeout and generate a definitive interval
if( _isCorrectionCycle_ ){
clearTimeout( _timer_clockRef_ );
clearInterval( _timer_clockRef_ );
_timer_clockRef_ = setInterval( nextCycle , _timer_freq_ );
_isCorrectionCycle_ = false;
}
// execute callback
_fn_callback_.apply( timer, [ timer ] );
};
// initialize timer
_time_ellapsed_ = 0;
_time_lastCycle_ = new Date();
_timer_statusCode_ = 1;
_timer_clockRef_ = setInterval( nextCycle , _timer_freq_ );
// timer public API
const timer = {
get statusCode(){ return _timer_statusCode_ },
get timestamp(){
let abstime;
if( _timer_statusCode_=== 1 ) abstime = _time_ellapsed_ + ( new Date() - _time_lastCycle_ );
else if( _timer_statusCode_=== 2 ) abstime = _time_ellapsed_ + ( _time_pause_ - _time_lastCycle_ );
return abstime || 0;
},
pause : function(){
if( _timer_statusCode_ !== 1 ) return this;
// stop timers
clearTimeout( _timer_clockRef_ );
clearInterval( _timer_clockRef_ );
// set new status and store current time, it will be used on
// resume to calculate how much time is left for next cycle
// to be triggered
_timer_statusCode_ = 2;
_time_pause_ = new Date();
return this;
},
resume: function(){
if( _timer_statusCode_ !== 2 ) return this;
_timer_statusCode_ = 1;
_isCorrectionCycle_ = true;
const delayEllapsedTime = _time_pause_ - _time_lastCycle_;
_time_lastCycle_ = new Date( new Date() - (_time_pause_ - _time_lastCycle_) );
_timer_clockRef_ = setTimeout( nextCycle , _timer_freq_ - delayEllapsedTime - RESUME_CORRECTION_RATE);
return this;
}
};
return timer;
};
let myTimer = Timer( x=> console.log(x.timestamp), 1000);
<input type="button" onclick="myTimer.pause()" value="pause">
<input type="button" onclick="myTimer.resume()" value="resume">
Code source :
This Timer is a modified and simplified version of advanced-timer, a js library created by myself, with many more functionalities.
The full library and documentation is available in NPM and GITHUB
let time = document.getElementById("time");
let stopButton = document.getElementById("stop");
let timeCount = 0,
currentTimeout;
function play() {
stopButton.hidden = false;
clearInterval(currentTimeout);
currentTimeout = setInterval(() => {
timeCount++;
const min = String(Math.trunc(timeCount / 60)).padStart(2, 0);
const sec = String(Math.trunc(timeCount % 60)).padStart(2, 0);
time.innerHTML = `${min} : ${sec}`;
}, 1000);
}
function pause() {
clearInterval(currentTimeout);
}
function stop() {
stopButton.hidden = true;
pause();
timeCount = 0;
time.innerHTML = `00 : 00`;
}
<div>
<h1 id="time">00 : 00</h1>
<br />
<div>
<button onclick="play()">play</button>
<button onclick="pause()">pause</button>
<button onclick="stop()" id="stop" hidden>Reset</button>
</div>
</div>

Wait until user is finished clicking | JavaScript

I want to count the clicks while the user keeps clicking.
After about half a second when there are no more clicks on a specific button, the function should return the accumulated clicks.
I've tried it with this but, doesn't really work:
HTML:
Next
JavaScipt:
cntNav(element){
let btn = element.target
let cnt = 0
let t = setTimeout(function(){
console.log(cnt)
}, 1000)
btn.addEventListener("click", function(){
cnt++
})
}
Console Output (after 5x clicking):
4
3
2
1
0
You could create a timeout to delay returning the clicks.
const main = () => {
new Clicker('#click-me', {
timeout: 500,
callback: (clicks) => console.log(`Clicks: ${clicks}`)
});
};
class Clicker {
constructor(selector, options) {
this.reference = typeof selector === 'string' ?
document.querySelector(selector) : selector;
let opts = Object.assign({}, Clicker.defaultOptions, options);
this.timeout = opts.timeout;
this.callback = opts.callback;
this.initialize();
}
initialize() {
this.__clickCount = 0;
this.__activeId = null;
this.reference.addEventListener('click', e => this.handleClick())
}
handleClick() {
this.__clickCount += 1;
clearTimeout(this.__activeId); // Reset the timeout
this.__activeId = setTimeout(() => {
this.callback(this.__clickCount);
this.__clickCount = 0; // Reset clicks
}, this.timeout);
}
}
Clicker.defaultOptions = {
timeout: 1000
};
main();
<button id="click-me">Click me!</button>
HTML:
<button onclick="cntNav();">Click Me!</button>
JS:
var cnt = 0;
var myTimeOut;
cntNav = function(){
clearTimeout(myTimeOut);
myTimeOut = setTimeout(function(){
console.log(cnt);cnt=0;
}, 1000)
cnt++;
}
This removes the timeout whenever someone clicks, so if someone clicks before the timeout has called, then it will be cleared. It will only call when someone leaves enough time in-between clicks. This then also sets the count back to zero.

How do I repeat a function while holding the mouse down with JavaScript?

Trying to run a function repeatedly while holding down the left mouse button with this code but it's not working. Any ideas to correct it will be appreciated.
var timer = 0;
document.getElementById('myButton').onmousedown = function() {
while (this.event) {
timer = setInterval(function() {c_3()}, 100);
}
clearInterval(timer);
}
you can solve this in multi way
check this https://codepen.io/hamidrezanikoonia/pen/bvarGL?editors=0011
var interval_;
document.getElementById('ele').onmousedown = function() {
interval_ = setInterval(function(){ console.log("Hello"); }, 300);;
}
document.getElementById('ele').onmouseup = function() {
clearInterval(interval_); wdsd
}
i use setInterval for doing this
Try adding mouseover and mouseup listeners when the button gets pressed down while over the button:
const button = document.querySelector('div');
button.addEventListener('mousedown', () => {
let mouseIsDown = true;
document.body.addEventListener('mouseup', () => clearTimeout(intervalLog));
document.body.addEventListener('mouseover', (e) => {
if (e.target !== button) clearTimeout(intervalLog);
});
const intervalLog = setInterval(() => console.log('mouse is down over button.'), 300);
});
<div>
button
</div>
<div>
div
</div>

Trigger different events based on how long mouse is held down

I want to trigger different events based on how long the mouse is held down. If the mouse is held less than a second trigger event 1. If it is held down for a second trigger event 2. If it is held down for two seconds trigger event 3, etc.
I have this JavaScript which displays messages showing how long the mouse is held down, but I am unsure of how to prevent the message shown after one second if the user continues to hold the mouse down for two seconds,
var mousedown = false;
var mousedown_timer = '';
$('#button').mousedown(function(e) {
mousedown = true;
$('#log').text('mousedown...');
mousedown_timer = setTimeout(function () {
if(mousedown) {
$('#log').text('1 second');
}
}, 1000);
mousedown_timer = setTimeout(function () {
if(mousedown) {
$('#log').text('2 second');
}
}, 2000);
}).mouseup(function(e) {
mousedown = false;
clearTimeout(mousedown_timer);
$('#log').text('aborted');
});
Is there maybe a way I could move my timer to detect the time elapsed in the mouseup function?
Here is a fiddle.
Here is how I would do it:
var mousedownTimestamp;
$('#button').mousedown(function(e) {
mousedownTimestamp = new Date();
}).mouseup(function(e) {
var mouseupTimestamp = new Date();
var difference = mouseupTimestamp - mousedownTimestamp;
if (difference < 1000) {
// event 1
} else if (difference >= 1000 && difference < 2000) {
// event 2
} else if (difference >= 2000) {
// event 3
}
});

Categories

Resources