I tried to implement a basic slider function to this example
var slider = d3.slider()
.axis(false).min(minDate).max(maxDate).step(secondsInDay)
.on("slide", function(evt, value) {
temp = moment(value,"x").utc().format("MM");
console.log(temp);
//tempVal = moment(temp).unix()*1000;
dataChoro = countries.properties.filter(function(d){
return d.properties[attributeArray[temp]]
});
});
d3.select('#slider3').call(slider);
But I can't read countries. What do I have to change to make it running? I try to use the play function of this example but instead of the button playing I'd like to use the slider to trigger the events
function animateMap() {
var timer; // create timer object
d3.select('#play')
.on('click', function() { // when user clicks the play button
if(playing == false) { // if the map is currently playing
timer = setInterval(function(){ // set a JS interval
if(currentAttribute < attributeArray.length-1) {
currentAttribute +=1; // increment the current attribute counter
} else {
currentAttribute = 0; // or reset it to zero
}
sequenceMap(); // update the representation of the map
d3.select('#clock').html(attributeArray[currentAttribute]); // update the clock
}, 2000);
d3.select(this).html('stop'); // change the button label to stop
playing = true; // change the status of the animation
} else { // else if is currently playing
clearInterval(timer); // stop the animation by clearing the interval
d3.select(this).html('play'); // change the button label to play
playing = false; // change the status again
}
});
}
Gist Any tips?
When you want to use the same code of your clock you can try this
var slider = d3.slider()
.axis(false).min(minDate).max(maxDate).step(secondsInDay)
.on("slide", function(evt, value) {
temp = moment(value,"x").utc().format("MM");
if(currentAttribute < attributeArray.length-1) {
console.log(currentAttribute);
currentAttribute = temp-1; // increment the current attribute counter
} else {
currentAttribute = 0; // or reset it to zero
}
sequenceMap(); // update the representation of the map
d3.select('#clock').html(attributeArray[currentAttribute]); // update the clock
});
d3.select('#slider3').call(slider);
Related
I was able to get the space bar to activate the simple button I made, but I am having problems with having it be looped with setInterval(). Is it because of the eventFire mechanism I utilized? Any help or constructive criticism is welcomed as I am trying to learn. Thanks for your time.
Edit: I was able to find a solution as I apparently was using the setInterval function incorrectly. However I still have an issue with stopping the setInterval loop with clearInterval(timer) E hotkey. Here is the updated code.
"use strict";
// used for Tracking Mouse Position which I will implement later
let mousex;
let mousey;
// Simple Button that logs the amount of times pressed and triggers an animation
function button() {
const button = document.querySelector(".button");
function buttonClassRemove() {
button.classList.remove("active");
}
function delay(time, inputFunction) {
let milliseconds = time;
setTimeout(function () {
inputFunction();
}, milliseconds);
}
let i = 0;
button.addEventListener("click", function () {
i = i + 1;
console.log(`Button pressed ${i} times`);
button.classList.add("active");
delay(100, buttonClassRemove);
});
}
// Simulates event
function eventFire(el, etype) {
if (el.fireEvent) {
el.fireEvent("on" + etype);
} else {
var evObj = document.createEvent("Events");
evObj.initEvent(etype, true, false);
el.dispatchEvent(evObj);
}
}
function autoClicker() {
document.addEventListener("mousemove", () => {
// Tracking Mouse Position
mousex = event.clientX; // Gets Mouse X
mousey = event.clientY; // Gets Mouse Y
// console.log([mousex, mousey]); // Prints data
});
document.body.onkeydown = function (e) {
// Simulates click mouse event
// and then loop that functionality with the setInterval function
let timer = setInterval(function () {
eventFire(document.getElementById("button1"), "click");
}, 100);
if (e.keyCode == 32) {
timer;
console.log("Space pressed");
} else if (e.keyCode == 69) {
// Cancels autoclicker setInterval function
clearInterval(timer);
console.log("E pressed");
}
};
}
autoClicker();
button();
Your issue is that timer is a local variable. You should define it with var at the start of your program alongside mousex and mousey. As it currently stands, every time you run onkeydown it creates a new instance of the interval, checks whether to cancel it, and then throws away the reference. If you make it a global variable, then you can keep the reference so that you can cancel it at any time.
With this, you should also consider when you are running the interval. If you keep it as-is, your old interval will be overwritten with the new one before you can check to cancel. What you should do instead is something like this:
var timer = null;
document.body.onkeydown = function(e) {
if (/* start timer */ && timer == null) {
timer = setInterval(/* ... */);
} else if (/* end timer */) {
clearInterval(timer);
timer = null;
}
}
Hi im trying to make a slideshow that run automatically and with this code it's working but i need to add a Play/Pause button to that code. Someone care to help ?
I would need the html/css also
var indexDiaporama=1;
afficherDiapo(indexDiaporama);
function ajoutDiapo(n){
afficherDiapo(indexDiaporama+=n);
}
function diapoActuelle(n){
afficherDiapo(indexDiaporama=n);
}
function afficherDiapo(n){
var i;
var slides=document.getElementByClassName("diapo");
var dots=document.getElementByClassName("dot");
if(n>slides.length){indexDiaporama=1;}
if(n<1){indexDiaporama=slides.length;}
for(i=0; i<slides.length; i++){
slides[i].style.display="none";
}
for(i=0; i<dots.length; i++){
dots[i].className=dots[i].className.replace("active", "");
}
slides[indexDiaporama-1].style.display="block";
dots[indexDiaporama-1].className+="active";
}
var timer = setInterval(function(){
indexDiaporama++;
afficherDiapo(indexDiaporama);
},3000);
Start by setting a variable, we will call it pause, to false and then run a conditional inside your setTimeout() that checks if it is false => if(!paused){ //run code }.
Handle the paused variable due to what state your button is in when it is pressed ==> e.target
You create a function that passes in your event target of a pause/play button when it is clicked. In that function you check the value of your pause/play button, you can use a dataset to toggle 0 or 1 / on or off / true or false on click and change the value of your pause variable due to what that dataset is set to on click.
In my example I use 0 and 1 in the data-id attribute => dataset.id in JS, with a conditional that checks that value => if (e.target.dataset.id === '0'){ //set paused to true }else{ // set paused to false }. Within the conditional I also set the textContent of the button and the dataset.id value as well.
Then each time you press the pause button the setInteral freezes as it is looking for paused to not be set to false => if (!paused){ // run code for setInterval }.
Below is a simply JS setInterval that increments a number by one every millisecond. We can pause and play it using the function and event listener as described above.
const display = document.getElementById('display')
const btn = document.querySelector('.btn')
let paused = false;
let i = 1;
function checkBool(e) {
if (e.target.dataset.id === '0') {
e.target.dataset.id = '1'
btn.textContent = 'Play'
paused = true;
}else{
e.target.dataset.id = '0'
btn.textContent = 'Pause'
paused = false;
}
}
btn.addEventListener('click', checkBool)
const timer = setInterval(function() {
if (!paused) { //<-- paused is not false
//<-- run the code your interval handles
display.textContent = i;
i++;
}
}, 100);
<div id="display"></div>
<button class="btn" data-id="0">Pause</button>
I have 31 images and I want to display them one after another as the background of a div. I only want it to change when the user hovers over the div. My problem right now is that it just flips through all the images really fast. I am attempting to use setTimeout, but it isn't working. How can I make the delay work?
The name of the div is About_Me_Block and the images are called frame1.gif,frame2.gif ...etc
Here is my code:
function changeImg(counter) {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
}
$(document).ready(function() {
var hoverAnimate = []
"use strict";
$('#About_Me_Block').mouseenter(function() {
hoverAnimate[0] = true;
var counter = 0;
while (hoverAnimate[0]) {
console.log(counter);
setTimeout(changeImg(counter), 1000);
counter++;
if (counter === 32)
hoverAnimate[0] = false;
}
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate[0] = false;
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
setTimeout doesn't wait for the function to end, it works lile threading in other languages.
To achieve a what you want, you need to call setTimeout from the changeImg function.
var counter = 0;
$(document).ready(function() {
var hoverAnimate = []
"use strict";
$('#About_Me_Block').mouseenter(function() {
hoverAnimate[0] = true;
counter = 0;
changeImg();
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate[0] = false;
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
function changeImg() {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
counter++;
if (counter < 32 && hoverAnimate[0]) {
setTimeout(changeImg, 1000);
} else {
hoverAnimate[0] = false;
}
}
the reason they happen all at once is because while statement doesn't have delay, so all setTimeout will be set up at the same time, thus, calling changeImg all at once.
To solve this problem, you can replace setTimeout with setInterval. Instead of using while, you can just call setInterval like
var counter = 0;
var myTimer = setInterval(changeImg, 1000);
and update counter inside changeImg every time it gets called. After looping, don't forget to
clearInterval(myTimer)
It seems you need to read up on how setTimeout works. It essentially places a reminder to run a function after a given amount of milliseconds have passed. So, when you do setTimeout(changImg(counter), 1000) you are calling changImg(counter) which returns undefined. Therein producing this setTimeout(undefined, 1000) which is why it flips really fast.
So, you can use bind to allow the function to be called later with that parameter built in. Also, make sure you remove the reminders once done with clearTimeout.
function changeImg(counter) {
$('#About_Me_Block').attr("style", "background-image: url(playGif/frame" + counter + ".gif);");
}
$(document).ready(function() {
var hoverAnimate = false, id;
function loop(counter) {
if(hoverAnimate || counter < 32) {
changeImg(counter);
id = setTimeout(loop.bind(this, counter++), 1000);
}
}
$('#About_Me_Block').mouseenter(function() {
hoverAnimate = true;
id = setTimeout(loop.bind(this, 0), 1000);
});
$('#About_Me_Block').mouseleave(function() {
hoverAnimate = false;
// Don't want a reminder for a random counter to wake up.
clearTimeout(id);
$(this).attr("style", "background-image: url(play.jpeg);");
});
});
Two methods for timers - setTimeout and SetInterval (single / repeating)
// setInterval is also in milliseconds
var intervalHandle = setInterval(<yourFuncToChangeImage>,5000);
//this handle loop and make example loop stop
yourelement.yourEvent = function() {
clearInterval(intervalHandle);
};
I have an input which controls the state of an element changing very rapidly. This causes that element to flicker as parts of it change.
I am trying to store these state changes and then providing nothing has changed for a set amount of time (an arbitrary 500ms) change the state.
I have tried to solve this using timeouts as demonstrated in the code below (the same code as in the fiddle.):
var changingToHappy = false;
// Original no attempts to fix functions.
//var ifHappy = function () {
// $("#face").text(':)');
//};
//
//var ifNotHappy = function () {
// $("#face").text(':(');
//};
var ifHappy = function () {
changingToHappy = true;
setTimeout(function () {
if (changingToHappy) {
$("#face").text(':)');
}
}, 500);
};
var ifNotHappy = function () {
changingToHappy = false;
setTimeout(function () {
if (!changingToHappy) {
$("#face").text(':(');
}
}, 500);
};
$("#textBox").keypress(
function (event) {
if (event.which == 49) {
ifHappy();
$("#flickerFace").text(':)');
}
if (event.which == 50) {
ifNotHappy();
$("#flickerFace").text(':(');
}
}
);
If you rapidly press 1, 2, 1, 2 and so on in the fiddle the face will remain not flickery for a moment and then the timeouts will catchup and it will begin to change state.
This fiddle http://jsfiddle.net/9w70wxgz/4/ simulates the problem.
To clarify I only want the face to change if nothing has tried to change its state for a set amount of time.
What you're looking for is called a debounced function, here is an example with a piece of your code (you're almost there):
//storage for timer
var notHappyTimer;
var ifNotHappy = function () {
changingToHappy = false;
//removes timer if event fires in less than 500ms
clearTimeout(notHappyTimer);
//resets it to attempt again in 500ms
notHappyTimer = setTimeout(function () {
if (!changingToHappy) {
$("#face").text(':(');
}
}, 500);
};
As you can see, you just assign the timeout to a variable that clears itself every time the function is fired, then starts the timer again. This ensures that the text change only happens if the function hasn't been fired in 500ms.
I'm having issues with my JavaScript code. I need to make code that does the following:
Click an image twice within 3 seconds to make the image disappear
Click it once to reappear
I've got it close to working...I'm just having issues with the date. I don't know how to keep the date from the first click. My code right now is just creating a new start date each click which is what I don't want.
Code thus far:
var imgNext = -1;
var start = new Date ( );
function disappear ()
{
var end = new Date ();
imgNext++;
if (imgNext == 2)
{
document.getElementById("myPicture").style.visibility="visible";
imgNext = -1;
}
if (imgNext == 1 && (end-start <3000))
{
document.getElementById("myPicture").style.visibility="hidden";
}
start = new Date ();
}
In the code the image changes even if the clicks are over 3 seconds apart because I'm creating a new START date every time the function is triggered. How do I resolve this?
Here is answer, with a working example: http://jsfiddle.net/yS5bs/2/
document.getElementById("disappear").onclick = function() {
var lastClick = this.attributes["click-time"],
click = new Date().getTime(),
timeout = parseInt(this.attributes["data-timeout"].value);
if(lastClick && (click - lastClick) < timeout && this.style.opacity == 1) {
this.style.opacity = 0;
this.attributes["click-time"].value = null;
return;
}
else {
this.attributes["click-time"] = click;
}
if(this.style.opacity == 0) {
this.style.opacity = 1;
this.attributes["click-time"] = null;
return;
}
};
basically I am assigning the onclick, and getting the click times, if within the set timeout (milliseconds) then it hides, otherwise, it shows again, as per spec