First, some visualization of the code.
I have the following images that are dynamically generated from jquery. They're made upon user request:
<img id="i13133" src="someimage.jpg" />
<img id="i13232" src="someimage1.jpg" />
<img id="i14432" src="someimage2.jpg" />
<img id="i16432" src="someimage3.jpg" />
<img id="i18422" src="someimage4.jpg" />
I have an AJAX loop that repeats every 15 seconds using jQuery and it contains the following code:
Note: The if statement is inside the Ajax loop.
Where imgId is the requested ID from the Ajax call.
//Passes the IDs retrieved from Ajax, if the IDs exist on the page the animation is triggered.
if ( $('#i' + imgId ).length )
{
var pickimage = '#i' + imgId;
var stop = false;
function highlight(pickimage) {
$(pickimage).animate({color: "yellow"}, 1000, function () {
$(pickimage ).animate({color: "black"}, 1000, function () {
if (!stop) highlight(pickimage);
});
});
}
// Start the loop
highlight(pickimage);
}
It works great, even with multiple images. But I had originally used this with one image.
The problem is I need an interrupt. Something like:
$(img).click(function () {
stop = true;
});
There's two problems:
1.)This obviously stops all animations. I can't wrap my head around how I could write something that only stops the animation of the image that's clicked.
2.)The Ajax retrieves IDs, sometimes those IDs appear more than once every few minutes, which means it would repeat the animations on top of each other if the image exists. I could use some help figuring out how to detect if an animation is already running on an image, and do nothing if the animation is already triggered on an image.
You can hit two birds with one stone ;)
1) Don't use the stop variable. Add a class to each img:
// Instead of: var stop = false;
$(pickimage).addClass("animating");
// Instead of: if (!stop) highlight(pickimage);
if ($(pickimage).hasClass("animating")) highlight(pickimage);
// Instead of: $(img).click(function () { stop = true; });
$(img).click(function () { $(this).removeClass("animating"); });
2) Same thing, check the class!
if ($(pickimage).hasClass("animating")) return;
Related
enter image description here
I'm trying to create an animation where if you click the button the circles animate around the path and changes size. I'm not sure how i would cycle the classes on the next click ?
http://bluemoontesting.co.uk/bluemoon2016/people.html
I'm using an svg and have targeted the elements with this so far:
<script>
$(".animate-slider").click(function() {
$('.st7').toggleClass("top-left");
$('#XMLID_292_').toggleClass("left");
$('#XMLID_293_').toggleClass("center-right");
$('#XMLID_297_').toggleClass("top-right");
$('#XMLID_301_').toggleClass("top");
$('#XMLID_283_').toggleClass("top-center");
});
</script>
If anyone could help me i'd be very grateful :)
Thanks
I would take a little different approach. Instead of toggling classes, to get it to move to more than two positions, you will need to cycle the classes assigned to each element instead. Storing the class names in an array would allow you to move them in the array to cycle the position that each element moves to next. I created a simplified example.
$(document).ready(function () {
var steps = ['right', 'bottom-right', 'bottom-left', 'left', 'top'],
allClasses = steps.join(' ');
$('#go').click(function() {
$('#a').removeClass(allClasses).addClass(steps[0]);
$('#b').removeClass(allClasses).addClass(steps[1]);
$('#c').removeClass(allClasses).addClass(steps[2]);
$('#d').removeClass(allClasses).addClass(steps[3]);
$('#e').removeClass(allClasses).addClass(steps[4]);
steps.push(steps.shift()); // move first element to the end
// to cycle in the other direction you would pop and unshift instead
// steps.unshift(steps.pop()); // move last element to the beginning
});
});
You could just use setInterval like so:
var $st7 = $('.st7'); //class selectors can be expensive, so cache them
function rotate() {
$st7.toggleClass("top-left");
$('#XMLID_292_').toggleClass("left");
$('#XMLID_293_').toggleClass("center-right");
$('#XMLID_297_').toggleClass("top-right");
$('#XMLID_301_').toggleClass("top");
$('#XMLID_283_').toggleClass("top-center");
}
//2000 is milliseconds, so that's two seconds
var rotateIntervalId = setInterval(rotate, 2000);
//optionally consider stopping/starting the effect on mouse hover/exit
$('#Layer_1').on('hover', function() {
clearInterval(rotateIntervalId);
}).on('blur', function() {
rotateIntervalId = setInterval(rotate, 2000);
});
Sorry for the question isn't very clear, basically
I have got the php code to search for photos in the directory based on the userId given in the url. So if the userId = 1, it will go to Photos/1 and get all the photos in that directory and output it into an array that I can use in Javascript. It works.
I have an external javascript to my php/html code.
I am changing the attr of the div's to display the photos. I have 5 "photo containers" in the array called photodisplay:
var photodisplay =
[
$("#photo1"),
$("#photo2"),
$("#photo3"),
$("#photo4"),
$("#photo5"),
];
Then I have a loop to change the attribute/img src:
function preloadingPhotos() {
for (var x=0; x<galleryarray.length; x++)
{
photodisplay[x].attr("src", "Photos/" + userid + "/" + galleryarray[x]);
console.log("preloaded photos");
}
displayPhoto();
}
It works. Providing no more than 5 photos because that is how many photocontainers I have. But what if I had photos? The question is: Would I be able to do a loop to keep changing the photos in the photodisplay array?
I also have code for the photocontainers to fade in and out:
function displayPhoto(){
photodisplay[0].fadeIn(3000);
photodisplay[0].delay(3000).fadeOut(3000, function() { //first callback func
photodisplay[1].fadeIn(3000);
photodisplay[1].delay(3000).fadeOut(3000, function() { //second callback func
photodisplay[2].fadeIn(3000);
photodisplay[2].delay(3000).fadeOut(3000, function() { //third callback func
photodisplay[3].fadeIn(3000);
photodisplay[3].delay(3000).fadeOut(3000, function() { // fourth callback func
photodisplay[4].fadeIn(3000);
photodisplay[4].delay(3000).fadeOut(3000, function() {
setTimeout(displayPhoto(), 3000);
});
});
});
});
});
}// end of function displayPhoto
Which requires me to manually enter the number of the array of the photodisplay.
I would thinking of adding more to the array with duplications of the photocontainers. But I don't think that would work since I would have to manually enter the number of the array in the code above to make it fade in and out.
Sorry if this is confusing. I tried my best to explain my problem. I hope someone can help. Don't worry about the retrieving images in the directory part, because it works. It increases the array of photos accordingly, I just don't know how to adjust this change with my javascript.
The method you are using, does not scale as you have a callback function for every element in your slideshow.
What you should do, is put all images in a list (or a list of div's) and hide them all / change the z-index so that only the active one shows. The you can loop through your elements using .next() on the list items to get the next one (or the first one if .next().length is 0).
This will clean up your code and is pretty easy to do yourself but there are also loads of jQuery plugins that do it for you.
You need a little bit of abstraction here. So instead of manually code numbers, try another approach. For this example I've used jQuery; since you've tagged your question with it, I assume it's okay:
// Set a default value and store the current photo in it.
var currentPhoto = 0;
// Calculate the total number of photos
var photoTotal = photodisplay.length;
var photoTimeout = false;
// Create a function to go to the next photo
var nextPhoto = function () {
// Keep track of the new current
currentPhoto = (currentPhoto + 1) % photoTotal;
// Just to be sure clearTimeout
clearTimeout(photoTimeout);
// Fadein each photo; you might want to do something to reset the style
photodisplay[0].fadeIn({
duration: 3000,
complete: function () {
photoTimeout = setTimeout(nextPhoto, 3000);
}
});
}
nextPhoto();
You don't want to define JS from the backend like that; just have PHP render the markup, then use JS to query and parse the markup for the presentational layer.
Let's assume your markup looks like this:
<div id="photocontainers">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<!-- A hidden array of images. -->
<div id="images">
<img src="http://placehold.it/100x100&text=1" />
<img src="http://placehold.it/100x100&text=2" />
<img src="http://placehold.it/100x100&text=3" />
<img src="http://placehold.it/100x100&text=4" />
<img src="http://placehold.it/100x100&text=5" />
<img src="http://placehold.it/100x100&text=6" />
<img src="http://placehold.it/100x100&text=7" />
<img src="http://placehold.it/100x100&text=8" />
<img src="http://placehold.it/100x100&text=9" />
<img src="http://placehold.it/100x100&text=10" />
<img src="http://placehold.it/100x100&text=11" />
</div>
So your server renders this; #images is just a hidden container, that basically preloads all the image assets you'll cycle between in #photocontainers.
var cycleImages = function() {
// Cache selectors that we'll need.
var $photoContainers = $('#photocontainers').children(),
$images = $('#images img'),
// Use `.data()` to get the starting point, or set to 0
// (if this is the first time the function ran).
startImage = $images.data('nextImage') || 0;
// Loop from the starting point, filling up the number of
// photocontainers in the DOM.
for (var i = startImage; i < startImage + $photoContainers.length; i++) {
var $targetImage = $images.eq(i % $images.length),
$targetPhotoContainer = $photoContainers.eq(i - startImage);
// Get rid of the current contents.
$targetPhotoContainer.empty();
// Clone the desired image, and append it into place.
$targetImage.clone().appendTo($targetPhotoContainer).fadeOut(0).fadeIn();
}
// Let's figure out which starting image is next up, and store that
// with `.data()`.
var nextImage = startImage + $photoContainers.length;
if (nextImage >= $images.length) {
nextImage -= $images.length;
}
$images.data('nextImage', nextImage);
}
// When the DOM is ready, call the method, then
// call it again however often you'd like.
$(document).ready(function() {
cycleImages();
setInterval(function() {
cycleImages();
}, 3000);
});
Here's a plunkr showing that in action: http://plnkr.co/SumqkXYpRXcOqEhAPOHm
In my wordpress site, I am using social buttons gathered in a bar.
These buttons are dynamically updated when the content is updated via jquery-ajax.
function update_social(str)
{
$(".dd_outer").fadeOut("slow");
UpdateLikeButton(str);
UpdateTweetButton(str);
UpdatePlus1Button(str);
$(".dd_outer").fadeIn('slow')
}
where the str parameter is the ID of the post. and dd_outer is the wrapper div of the floating bar. I am calling update_social when I call the function responsible of dynamically loading post contents via AJAX.
Everything works like a charm, but the problem is that, sometimes the bar fades in before the social buttons are completely loaded. How can I make the total bar do not appear till all buttons are loaded?
I thought FadeIn and FadeOut are enough. Appreciated is your help.
Edit:
function UpdateLikeButton(str)
{
var elem = $(document.createElement("fb:like"));
elem.attr("href", "http://www.bag.com/Arabic/Arra2issia/"+str+"/");
elem.attr("send", "false");
elem.attr("layout", "box_count");
elem.attr("show_faces", "false");
$("#zzzz").empty().append(elem);
FB.XFBML.parse($("#zzzz").get(0));
}
function UpdateTweetButton(str)
{
var elem3 = $(document.createElement("a"));
elem3.attr("class", "twitter-share-button");
elem3.attr("href","http://twitter.com/share");
elem3.attr("data-url","http://www.bagh.com/"+str+"/");
elem3.attr("data-counturl","http://www.bagh.com/"+str+"/");
elem3.attr("data-count", "vertical");
elem3.attr("data-via", "#");
elem3.attr("data-text",str);
elem3.attr("data-lang","en");
$("#tweet").empty().append(elem3);
$.getScript("http://platform.twitter.com/widgets.js",function(){
twttr.widgets.load();
});
}
function UpdatePlus1Button(str)
{
var elem4 = $(document.createElement("g:plusone"));
elem4.attr("href","http://www.bagh.com/"+str+"/");
elem4.attr("size", "tall");
$("#plus1").empty().append(elem4);
$.getScript("https://apis.google.com/js/plusone.js");
}
Original buttons :
<div id="zzzz" ><fb:like href="<?php the_permalink();?>" send="false" show_faces="false" layout="box_count"></fb:like></div>
<div id="plus1"><g:plusone size='tall' href='<?php the_permalink();?>'></g:plusone></div>
<div id="tweet"></div>
Add return in your functions like this :
function UpdateTweetButton(str)
{
var elem3 = $(document.createElement("a"));
elem3.attr("class", "twitter-share-button");
elem3.attr("href","http://twitter.com/share");
elem3.attr("data-url","http://website/"+str+"/");
elem3.attr("data-counturl","http://website/"+str+"/");
elem3.attr("data-count", "vertical");
elem3.attr("data-via", "#");
elem3.attr("data-text",str);
elem3.attr("data-lang","en");
$("#tweet").empty().append(elem3);
return $.getScript("http://platform.twitter.com/widgets.js",function(){
twttr.widgets.load();
});
}
function UpdatePlus1Button(str)
{
var elem4 = $(document.createElement("g:plusone"));
elem4.attr("href","http://website/"+str+"/");
elem4.attr("size", "tall");
$("#plus1").empty().append(elem4);
return $.getScript("https://apis.google.com/js/plusone.js");
}
Call them like this :
function update_social(str)
{
$(".dd_outer").fadeOut("slow");
UpdateLikeButton(str);
$.when(UpdateTweetButton(str), UpdatePlus1Button(str)).done(function(){
$(".dd_outer").fadeIn('slow');
});
}
I think you might need to call the code in a callback from the fadeOut function, so that it doesn't run until the bar has faded out... Try
function update_social(str)
{
$(".dd_outer").fadeOut("slow");
UpdateLikeButton(str);
UpdateTweetButton(str);
UpdatePlus1Button(str);
//Make fadeIn wait 1 second before running to allow button functions to complete
setTimeout(function(){
$(".dd_outer").fadeIn('slow');
},1000);
};
I'm loading in separate .html documents inside divs with this code:
JS
$('.thumbnail').click(function() {
var idStr = ("project/"+$(this).attr('id')) + " #projectcontainer";
$('#projectcontainer').animate({opacity:0});
$('#projectcontainer').hide().load(idStr,function(){
$(this).slideDown(500).animate({opacity:1}, function() {
$.scrollTo('#gohere',800);
$('#close').fadeIn(500).css({'display': 'block', 'height': '25px'});
});
});
});
HTML
<div class="thumbnail" id="atmotype.html">
<img src="image.whatever">
</div>
It all works as intended but I also wanna append an ID when you open a project, and also be able to link directly to said content (already expanded in the div). I've been trying around and can't come up with a solution, and that being said I'm pretty awful with JS in general.
Would really appreciate if someone could enlighten me on how this works.
Right now when you click your .thumbnail element, it is firing your click() event and using $(this).attr('id') for the hash/scroll. To make this run when the page load, you should probably break it out to a separate function that takes the ID as a parameter, and then call this function from your click() event as well as a generic page load using a parameter in location.hash.
$(document).ready(function(){
if (location.hash.length>0){
/* this assumes the page to load is the only thing in the
hash, for example /page.php#project.html */
var hash = location.hash.substring(1); // get hash and remove #
addHashAndScroll(hash); // call function with page name
}
$('.thumbnail').click(function() {
addHashAndScroll($(this).attr('id')); // pass ID value to function
});
}
// this function contains most of your original script
function addHashAndScroll(id){
var idStr = "project/"+ id + "#projectcontainer";
// rest of your code
}
UPDATE:
This is the thing about js it all makes sense when explained but executing it is a bitch. Anyways thanks alot for helping out. Based on your explanation what I get is:
$(document).ready(function() {
if (location.hash.length > 0) {
/* this assumes the page to load is the only thing in the
hash, for example /page.php#project.html */
var hash = location.hash.substring(1); // get hash and remove #
addHashAndScroll(hash); // call function with page name
}
$('.thumbnail').click(function() {
addHashAndScroll($(this).attr('id')); // pass ID value to function
});
}
// this function contains most of your original script
function addHashAndScroll(id) {
var idStr = "project/" + id + "#projectcontainer";
$('#projectcontainer').animate({
opacity: 0
});
$('#projectcontainer').hide().load(idStr, function() {
$(this).slideDown(500).animate({
opacity: 1
}, function() {
$.scrollTo('#gohere', 800);
$('#close').fadeIn(500).css({
'display': 'block',
'height': '25px'
});
});
});
}
I've tried to fiddle around with the closures and whatever minimal experience i have in bug testing js but i keep getting errors originating from this line:
function addHashAndScroll(id) {
I have the following jQuery code:
var id_atual
var temp_id
var tempo_flash = 50
var $slide_atual = $('#slider .atual')
var $slide_prox = $('#slider .ocultar')
setInterval(function(){
id_atual = $slide_atual.attr('alt')
$.post('get_banner.php', {atual: id_atual}, function(proximo){
temp_id = proximo.split(';;')
$slide_prox.attr('src', temp_id[0]).load(function(){
$slide_atual.hide('fade', tempo_flash, function(){
$slide_atual.attr('alt', temp_id[1]).attr('src', temp_id[0]).load(function(){
$slide_atual.show('fade', tempo_flash)
})
})
})
})
}, 4000)
And the following HTML code:
<div id="slider">
<img src="imagens/slider/imagen-slider.jpg" alt="1" class="atual"/>
<img src="" alt="" class="ocultar" />
</div>
Where the class .ocultar have a
display: none;
The vars tempo_flash is only the animation time, and the file get_banner.php is only for getting the next banner from the mysql database. It is tested and working fine.
The problem I have is that after a little (4 or 5 banner changing) the browser stops answering (for Firefox Chrome and Opera) and on IE I get an alert Stack overflow at line: 3 and the javascript of the whole page stops working.
Any help appreciated!
Inside each iteration of the setInterval()ed function, you assign a .load() event to an image place holder. Assigning an event to an object does not remove existing ones!
So on second iteration, the image place holder will have two .load() event handlers, then three and so on; and every time the image is loaded, it will fire all event handlers attached to .load() event. You probably need to re-factor your code, perhaps by assigning the .load() event handler only once (and use semicolons).
you shouldn't use setInterval, you should use a setTimeout inside a function, and execute it on the callback of the $.post, something like:
var id_atual
var temp_id
var tempo_flash = 50
var $slide_atual = $('#slider .atual')
var $slide_prox = $('#slider .ocultar')
function tictac(){
setTimeout(function(){
id_atual = $slide_atual.attr('alt')
$.post('get_banner.php', {atual: id_atual}, function(proximo){
temp_id = proximo.split(';;')
$slide_prox.attr('src', temp_id[0]).load(function(){
$slide_atual.hide('fade', tempo_flash, function(){
$slide_atual.attr('alt', temp_id[1]).attr('src', temp_id[0]).load(function(){
$slide_atual.show('fade', tempo_flash)
})
})
})
})
ticktac();
}, 4000);
}
this way, the 4 seconds only start counting if and when the response from the server is complete, you will not have your overflow problems