How can I detect when a button is held in js? - javascript

I am trying to detect when a button is being held down by a finger for an unspecified amount of time. However I can't figure out how to do that.
I tried doing this like the sample online showed
const b = document.getElementById("hold-me");
b.onclick = function() {
setTimeout(alert, 2000, "you held me down for 2 second");
}
<body>
<button id="hold-me">Hold me</button>
</body>
However it doesn't correspond to what I want to do as I want to be able to have the event to fire as long as the button is pressed.
Edit:
To add some clarification, the set timeout function is here because it's roughly what the example I found online did. Here is the example: https://codepen.io/thetallweeks/pen/uAEGr?editors=0010
The example I found online didn't helped because I want to query if the button is press continuously to know wether I should a action of moving my rc car or not.

1'st variant, event fire after "unspecified amount of time";
const b = document.getElementById("hold-me");
let time;
b.onpointerdown = function() {
time = Date.now();
}
b.onpointerup = function() {
console.log(`you held me down for ${Date.now() - time} milliseconds`);
}
<body>
<button id="hold-me">Hold me</button>
</body>
2'nd variant, event fire during "unspecified amount of time":
const b = document.getElementById("hold-me");
let timer;
b.onpointerdown = function() {
timer = setTimeout(alert, 2000, "you held me down for 2 second");
}
b.onpointerup = function() {
clearTimeout(timer);
}
<body>
<button id="hold-me">Hold me</button>
</body>

Use the mousedown event and get the current time every time the button is pressed. Then, in the timer function, see if it's at least however many seconds the user has determined past that start time. When the button is released, reset the time.
Also, you should use the modern API for event binding of .addEventListener(), rather than setting event properties.
let start = null;
const elapsedTime = +prompt("How many seconds should we wait?");
const button = document.getElementById("hold-me");
button.textContent += " for at least " + elapsedTime + " seconds.";
button.addEventListener("mousedown", function() {
start = new Date(); // Record the start time
setTimeout(function(){
// If there is a start time and its now at least 2 seconds past that...
if(start && (new Date() > start.setSeconds(start.getSeconds() + elapsedTime))){
alert("You held me down for " + elapsedTime + " seconds.");
}
}, elapsedTime * 1000);
});
document.getElementById("hold-me").addEventListener("mouseup", function() {
start = null; // Cancel the time
});
<button id="hold-me">Hold me</button>

It depends upon how much time you consider that the user is holding. You can say, for example, that a time of less than 1 second is click and greater a button being hold down.
Furthermore, it's good to point that holding is the combination of two Javascript events: mouseup and mousedown. The first gets track of wheter the click pushes down the button and the second when user left the mouse click button.
let startTime, clickTime = 2000 // in milliseconds
$("#btn").mousedown(()=>{
startTime = new Date()
console.log("Holding")
// Your logic goes here (while holding)
})
$("#btn").mouseup(()=>{
var elapsedTime = new Date() - startTime
elapsedTime <= clickTime ? console.log("It's a click") : console.log(`It was held by ${elapsedTime} ms`)
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id='btn'>Hold! :)</button>
Finally: you are able to detect whether a button is being held down or not based on the time you set to be considered a button holding, then you can implement your logic.

Related

Play random sound on button that is spammable

I have a problem that i want to have a button, that plays random sound after I press it, but the other thing is that i want to spam the button and so does the sound. What I mean is that i dont want to wait for the sound to finish to play it again and like have 5 sounds or more playing depending on your click speed.
for(var i=0;i<1;i++)
{
document.getElementById("MyAudio.mp3")[i].addEventListener("click",function(){});
}
function playAudio()
{
var audio = new Audio("MyAudio.mp3");
audio.play();
}
<button onlick="playAudio()"></button>
That sounds fun and there's many ways to do it. I think the easiest way would be to pre-load the songs ahead of time and randomize it.
// Your sounds
let sounds = [new Audio('https://download.samplelib.com/mp3/sample-3s.mp3'), new Audio('https://download.samplelib.com/mp3/sample-6s.mp3'), new Audio('https://www.soundjay.com/human/fart-01.mp3')];
let lastSound = 0; // Not necessary but we don't want overlapping tracks.
// Listen for click on button (ID soundmachine)
// pointerdown is more suitable so adjusted it.
document.querySelector("#soundmachine1").addEventListener("pointerdown", () => {
// This is a small fix to allow the sound to be spammable and clear last track.
sounds[lastSound].pause();
sounds[lastSound].currentTime = 0;
let random = Math.floor(Math.random() * sounds.length);
sounds[random].play();
lastSound = random; // For the next click we want to cancel this sound if it's playing.
console.log(lastSound); // Just so you can see it count/play
});
document.querySelector("#soundmachine2").addEventListener("pointerdown", () => {
// Play till completed
let random = Math.floor(Math.random() * sounds.length);
sounds[random].play();
});
<button id="soundmachine1">click me ver1</div>
<button id="soundmachine2">click me ver2</div>
Something like this!
There's some odd things going on with this code, so let's rethink it from the beginning. First of all, you want to create an onclick handler on your button that plays your mp3 file. Let's do that first:
let audio = new Audio("MyAudio.mp3");
document.querySelector("button").addEventListener("click", () => {
audio.play()
});
Now, it sounds like you want it to play from the beginning every time when clicked, and not wait till it completes (which is the default behavior). So we need to reset the playback every time you click.
let audio = new Audio("MyAudio.mp3");
document.querySelector("button").addEventListener("click", () => {
audio.currentTime = 0;
audio.play();
});
🎉 🎶
And your HTML can just look like this:
<button>Play</button>

How to trigger a function which is inside another function

I have function running every second (for clock) .
I wanted to add sound to every tick tick....(second) but as function is running automatic (means no triggering is taking place) and when sound added produces an error
Error showing is :
Uncaught DOMException: play() failed because the user didn't interact with the document first.
Know that it is not possible to play audio automatic .
So tried to create a start sound btn which play the audio but as second time (of clock) and don't match with audio . So there is a mismatch
I am trying to add that function(audio play) inside second(clock time) calculator .
Is this possible or not
Link to similar question but not able to find the solution
The code is as follows
setInterval(clockRunner, 1000);
function clockRunner() {
//Clock code goes here
function trigger() {
var audioElement = document.getElementById('audiotag1');
audioElement.play();
}
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata" controls></audio>
<button onclick="trigger()">Start</button>
Update
Added event listener inside the outer function but this way sound is playing once not every second .
One solution here can be adding another setInterval but this will again create problem of playing sound at different timing of clock's second
Also it shows the same error in the console(mentioned above) until user clicks the btn
setInterval(clockRunner, 1000);
function clockRunner() {
//Clock code goes here
document.getElementById('demo').innerHTML = new Date();
setInterval(trigger, 1000);
document.getElementById("triggerSnd").addEventListener('click', trigger)
function trigger() {
var audioElement = document.getElementById('audiotag1');
audioElement.play();
}
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata" controls></audio>
<button id="triggerSnd">Start</button>
<div id="demo"></div>
Thanks for help in advance
If you make use of some variables, you can control your code to perform like a clock. It's worth noting that there are two possibilities, either the clock has started or it has stopped.
The interval will run when you clicked to start and it will be cleared in stopping it. Here I can't notice any mismatch between the sound and the timer.
var start = document.getElementById("triggerSnd")
var audioElement = document.getElementById('audiotag1')
var demo = document.getElementById('demo')
var interval, isMuted = true
// The second argument of addEventListener should be a function
// that receives an argument 'event'
clockRunner();
clock(); // call firstly
setInterval(() => clock(), 1000)
start.addEventListener('click', clockRunner)
function clock(isMuted){
//Clock code goes here
demo.innerText = new Date();
audioElement.play();
}
function clockRunner() {
audioElement.muted = isMuted
start.innerText = isMuted ? "Start" : "Stop"
isMuted = !isMuted
}
<audio id="audiotag1" src="https://soundbible.com/mp3/Tick-DeepFrozenApps-397275646.mp3" preload="metadata"></audio>
<button id="triggerSnd">Start</button>
<div id="demo"></div>
I've changed my answer completely. Now I didn't need to use an event listener, just the proper API of HTMLMediaElement that audio uses. Note that I've add loop attribute to tick's audio.
var blast = document.getElementById("blast");
var tick = document.getElementById("tick");
var tickDuration, timeDiff, lastTime
tick.onloadedmetadata = () => tickDuration = tick.duration
timeDiff = 0.3 // max difference between sync, dont lower it or it will bug (can explain if u want)
lastTime = 0
blast.addEventListener("timeupdate", () => {
let bct = blast.currentTime
let tct = tick.currentTime
let syncBlastTime = tickDuration - (tickDuration - bct%tickDuration)
let diff = Math.abs(syncBlastTime - tct)
lastTime = bct
console.log(`Blast: ${bct} Tick: ${tct}\nSynced time difference (seconds): ${diff.toFixed(6)}`)
if(diff > timeDiff) { // add this or it will bug the tick audio
tick.currentTime = syncBlastTime
}
})
blast.addEventListener("pause", () => {
tick.pause()
})
blast.addEventListener("playing", () => {
tick.play()
})
<audio id="blast" src="http://stream.arrowcaz.nl/caz64kmp3" controls="loop"></audio>
<audio id="tick" src="https://soundbible.com/mp3/A-Z_Vocalized-Mike_Koenig-197996831.mp3" loop controls='loop'></audio>
<br />

disable button with PHP and JavaScript when time is gone

I try to disable Apply button when application deadline is over. I used php and I successfully got time on each button. Now different time is print on different button.
<td><input type='submit' value='Apply' id='button' name='button' date-time='$closedate' /></td>
I used jquery/ javascript to disable button after expired time (after deadline of application), it cannot disable and it always enable.
In the code below code I used for disable button but it not works.
<script>
$(document).ready(function() {
var timer = setInterval(function() {
var current = $("#button").data('time');
// get the current value of the time in seconds
var newtime = current - 1;
if (newtime <= 0) {
// time is less than or equal to 0
// so disable the button and stop the interval function
$("#button").prop('disabled', true);
clearInterval(timer);
} else {
// timer is still above 0 seconds so decrease it
$("#button").data('time', newtime);
}
}, 1000);
});
</script>
based on what you have put down, it seems there are a few simple errors that need to be looked at
1) looks like a simple typo -- date-time should be data-time
2) you are not actually outputting the value of $closedate try changing it to
without knowing what the value of $closedate is, we won't be able to help further than that
Here is a fiddle that replicates an example...https://jsfiddle.net/o2gxgz9r/6656/
Your main issue is that you are mispelling the data-time attribute in your code as date-time. Your html should be as follows...
<input type='submit' value='Apply' id='button' name='button' data-time='$closedate' />
After fixing that, you should be able to reference the data value. Moreover, you are not updating the data value, so every time setInterval is called, the variable $closedate remains the same, and so the if statement if (newtime <= 0) is never reached...
var timer = setInterval(function() {
// get the current value of the time in seconds
var current = $("#button").data('time');
// decrement the time
var newtime = current - 1;
// update $closedate
$("#button").data('time', newtime);
if (newtime <= 0) {
// time is less than or equal to 0
// so disable the button and stop the interval function
$("#button").prop('disabled', true);
clearInterval(timer);
} else {
// timer is still above 0 seconds so decrease it
$("#button").data('time', newtime);
}
}, 1000);
I am not sure what the value of $closedate is but I made an assumption in my fiddle.
A few of issues...
First, in your HTML, you have date-time instead of data-time, so when you go to get the attribute later with: $("#button").data('time'), you won't get anything.
Second, you must remember to convert HTML data (which is always a string) to numbers to do math with them.
Third, you need to verify that $closedate is a string that can be converted into a valid number. You indicated in a comment below that $closedate will be something like: 2017-03-17. But that is not a value that you can subtract from.
Lastly, updating the HTML is costly in terms of performance. You are modifying the data-time attribute upon each iteration of your setInterval(), which is roughly every second. This can and should be avoided. It can be done by keeping the time left in a variable instead of writing it back to the document.
Here's a working version:
$(document).ready(function() {
// Always cache references to elements you will use more than once:
var $btn = $("#button");
// When gettting data from HTML, you get strings. You must convert
// them to numbers to do math with them. Also, we are using 5 seconds
// here instead of $closedate for testing purposes.
var current = parseInt($btn.data('time'), 10);
// Initialize the newtime for comparison
var newtime = current;
var timer = setInterval(function() {
newtime--; // Decrease the time left
// Just testing the variables:
console.log(current, newtime);
if (newtime <= 0) {
// time is less than or equal to 0
// so disable the button and stop the interval function
$btn.prop('disabled', true);
clearInterval(timer);
}
current--; // Decrease the counter
}, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type='submit' value='Apply' id='button' name='button' data-time='5'>

Multiple instances of Setinterval

I have a little problem with my code.
I have it setup so that by default, a rotating fadeIn fadeOut slider is auto playing, and when a user clicks on a li, it will jump to that 'slide' and pause the slider for x amount of time.
The problem i have is that if the user clicks on multiple li's very fast, then it will run color1() multiple times with will start colorInterval multiple times. This gives a undesired effect.
So what i need help with, is figuring out how to reset my code each time a li is clicked, so whenever ColorClick is clicked, i want to make sure that there are no other instances of colorInterval before i start a new one.
Thanks in advance!
=================================
edit:
I now have another problem, i believe that i fixed the clearInterval problem, but now if you look at var reset, you'll see that it runs color1() each time a li is clicked, which runs multiple intervals, so i need to delete the previous instance of color1() each time it is called, to make sure that it doesnt repeat any code inside multiple times. So when a li is clicked delete any instances of color1()
or
i need that instead of running color1 in var reset, i will go straight to colorInterval instead of running color1() for each li clicked,
so run colorInterval after x amount of time in var reset.
function color1() {
var pass = 0;
var counter = 2;
var animationSpeed = 500;
var $colorContent = '.color-container-1 .color-content-container'
var $li = '.color-container-1 .main-color-container li'
$($li).on('click', function() {
colorClick($(this));
});
function colorClick($this) {
var $getClass = $this.attr("class").split(' ');
var $whichNumber = $getClass[0].substr(-1);
var $Parent = '.color-container-1 ';
pass = 1;
$($colorContent).fadeOut(0);
$($colorContent + '-' + $whichNumber).fadeIn(animationSpeed);
var reset = setTimeout(function() {
clearTimeout(reset);
pass = 0;
color1();
}, 10000);
}
var colorInterval = setInterval(function() {
if (pass > 0) {
clearInterval(colorInterval);
return; //stop here so that it doesn't continue to execute below code
}
$($colorContent).fadeOut(0);
$(($colorContent + '-' + counter)).fadeIn(animationSpeed);
++counter
if (counter === $($colorContent).length + 1) {
counter = 1;
}
}, 7000);
}
You could just clear the interval inside of the click event.
var colorInterval;
$($li).on('click', function() {
clearInterval(colorInterval);
colorClick($(this));
});
//Your other code
colorInterval = setInterval(function() {
//Rest of your code
});
One thing play with is jQuery animations have a pseudo class selector :animated when animation is in progress
if(!$('.your-slide-class:animated').length){
// do next animation
}

Converting a JavaScript Countdown to a jQuery Countdown and adding an Interval

I found this JS-Countdown Script at JSFiddle.
EDIT:
I'm using the code of rafaelcastrocouto now, which is nearly perfect. I wanted a 10-seconds JQuery Countdown-Script with an interval that resets the countdown timer at 5 seconds and starts over again and again, but only for a specific class with a specific id on the whole HTML page. If it drops to 0, the countdown should stop. Also I want to reset specific counters to 10.
It's about a WebSocket that refreshes every second and depending on the data I get for specific counters I want to reset them or they should count down to zero.
New JSFiddle: http://jsfiddle.net/alexiovay/azkdry0w/4/
This is how I solved with jquery and native setInterval...
var setup = function(){
$('.count').each(eachSetup);
};
var eachSetup = function(){
var count = $(this);
var sec = count.data('seconds') ;
count.data('count', sec);
};
var everySecond = function(){
$('.count').each(eachCount);
};
var eachCount = function(){
var count = $(this);
var s = count.data('count');
count.text(s);
s--;
if(s < 0) {
s = count.data('seconds');
}
count.data('count', s);
};
setup();
setInterval(everySecond, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<p class="count" data-seconds="5"></p>
<p class="count" data-seconds="10"></p>
<p class="count" data-seconds="15"></p>
You have sever errors in code, e.g.
setTimeout(cd_go(id), 1000); - should point to function reference not to function execution. setTimeout also returns the timeout id. You must past that id to clearTimeout
clearTimeout(this); it should take id instead of global object (window) or undefined if you are working in strict mode
loop = setInterval(function(id) { … } - id points to undefinded as you are not passing any value for it

Categories

Resources