I made a slideshow with php and javascript and it slides the images just fine , but i'm a bit stuck at the back and forward functionalities and i would be grateful if you could help me a bit here.This is what i've done so far:
PHP:
$dir = 'images/slideshow';
$images = scandir($dir);
$i = 0;
echo '<div id="slideshow-wrapper">';
echo '<div id="slideshow-beta">';
foreach($images as $img){
if ($img != '.' && $img != '..') {
$i++;
echo '<img src="../images/slideshow/'.$img.'" class="img_'.$i.'">';
}
}
echo '</div>';
echo '<div id="slideshow-controller">';
echo '<div class="left-arrow-div"><span class="left-arrow" onclick="SlideShow(-1);"></span></div>';
echo '<div class="right-arrow-div"><span class="right-arrow" onclick="SlideShow(1);"></span></div>';
echo '</div>';
echo '</div>';
Javascript:
var i=1;
var begin=true;
function SlideShow(x){
if(x==-1){
i--;
}else if(x==1){
i++;
}
var total=$('#slideshow-beta img').length;
for(var j=1;j<=total;j++){
if($('.img_'+j).css('display')!='none'){
begin=false;
break;
}else{
begin=true;
}
}
if(i>total){
i=1;
$('.img_'+total).fadeOut(1000,function(){
$('.img_'+i).fadeIn(1000);
});
}else if(begin){
$('.img_'+i).show();
}else if(!begin){
$('.img_'+(i-1)).fadeOut(1000,function(){
$('.img_'+i).fadeIn(1000);
});
}
setTimeout(function(){
i++;
SlideShow(x);
},5000);
}
HTML:
<body onload="SlideShow(false);">
As you can see i tried to make an onclick event to change the 'i' value on run , though the value is changed , the image is not . Maybe because pressing back/forward calls another instance of the function instead of overwriting it.I don't know for sure , i'm lost on this one.
Here's a fiddle
I've made a major overhaul, but the idea stays the same (fiddle):
Changes to CSS:
.left-arrow, .right-arrow {
cursor: pointer;
/** display: none **/
}
#slideshow-controller {
z-index: 2;
position: absolute;
/** added **/
opacity: 0;
transition: opacity 300ms ease-in;
/***********/
}
#slideshow-wrapper:hover > #slideshow-controller {
opacity: 1;
}
Changes to HTML (removed inline onClick):
<div class="left-arrow-div"><span class="left-arrow">Back</span>
</div>
<div class="right-arrow-div"><span class="right-arrow">Forward</span>
</div>
Javascript:
var i = 0;
var images = $('#slideshow-beta img'); // cache all images
var total = images.length;
var timeout;
/*** hide all images at the start ***/
images.each(function (index) {
$(this).css({
display: 'none'
});
});
/*** bind event handlers to arrows ***/
$('.left-arrow').click(function () {
SlideShow(-1);
});
$('.right-arrow').click(function () {
SlideShow(1);
});
/*** Start the slideshow on 1st image ***/
SlideShow(0);
function SlideShow(x) {
if (isNaN(x)) { // throw error if x is not a number
throw new Error("x must be a number");
}
clearTimeout(timeout); // clear previous timeout if any to prevent multiple timeouts running
var current = (total + i + x % total) % total; // get the current image index
$(images[i]).fadeOut(1000, function () { // fade out the previous
$(images[current]).fadeIn(1000); // fade in the current
});
i = current; // set i to be the current
timeout = setTimeout(function () { // cache the timeout identifier so we can clean it
SlideShow(1);
}, 5000);
}
I have fixed your problems - the main problem was that you call the function inline - but the function doesn't exist at this moment (the milliseconds in pageload). The other one was your if (now with 3 = that includes the type - because false, 0, -1 and so on are "the same".
The only problem now is that the interval runs infinitely and can call the next image instantly after a manual change.
In conclusion I recommend you to use a library like cycle2 or anything like this.
https://jsfiddle.net/Lroatbzg/15/
jQuery(window).on('load', function() {
$("#slideshow-wrapper").hover(function(){
$(".left-arrow,.right-arrow").fadeIn();
}, function(){
$(".left-arrow,.right-arrow").fadeOut();
});
var i=1;
var total = $('#slideshow-beta img').length;
function SlideShow(x) {
if(x === -1) {
i--;
} else if(x === 1) {
i++;
}
if(i > total) {
i = 1;
}
$('#slideshow-beta img').hide();
$('#slideshow-beta .img_' + i).fadeIn(1000);
}
setInterval(function() {
i++;
SlideShow(i);
}, 5000);
jQuery('.left-arrow-div').on('click', function() {
SlideShow(-1);
});
jQuery('.right-arrow-div').on('click', function() {
SlideShow(1);
});
SlideShow(false);
});
Your fiddle throws a ReferenceError: SlideShow is not defined (Firefox using Firebug).
Try replacing function SlideShow(x){...} with SlideShow = function (x) {...} (https://jsfiddle.net/Lroatbzg/12/).
Honestly I don't know why the latter works, as those two statements are equivalent to me (any explanation on that?).
Declaring your function the other way around gets rid of the error - at least in my browser.
use
if(x=='-1'){
i--;
}else if(x=='1'){
i++;
}
instead of
if(x==-1){
i--;
}else if(x==1){
i++;
}
The problem is that the setTimeOut will execute the function SlideShow delayed. However, when you click a button, this delayed execution is not stopped. To stop this execution, I made a small change to the code. Furthermore, I solved the ReferenceError in jsfiddle by launching the onClick-functionality through jQuery.
This result can be checked here: https://jsfiddle.net/Lroatbzg/13/
$("#slideshow-wrapper").hover(function(){
$(".left-arrow,.right-arrow").fadeIn();
}, function(){
$(".left-arrow,.right-arrow").fadeOut();
});
var i=1;
var direction=1;
var begin=true;
var latest=Math.random();
function SlideShow(parameter){
if(latest!=parameter)
return; //Return when this function is not called through the last click or timeout.
var total=$('#slideshow-beta img').length;
i=i+direction;
if(i>total)
i=1;
if(i<1)
i=total;
begin=true;
for(var j=1;j<=total;j++)
{
if($('.img_'+j).css('display')!='none')
{
begin=false;
$('.img_'+total).fadeOut(1000,function(){
$('.img_'+j).css('display','none');
$('.img_'+i).fadeIn(1000);
});
break;
}
}
if(begin)
$('.img_'+i).show();
setTimeout(function(){
SlideShow(parameter);
},5000);
}
SlideShow(latest);
$("#left").click(function(){ latest=Math.random(); direction=-1; SlideShow(latest); });
$("#right").click(function(){ latest=Math.random(); direction=1; SlideShow(latest); });
The HTML is changed as follows:
<div id="slideshow-controller">
<div class="left-arrow-div" id="left"><span class="left-arrow">Back</span></div>
<div class="right-arrow-div" id="right"><span class="right-arrow">Forward</span></div>
</div>
Related
I am using articulate.js(http://www.jqueryscript.net/demo/Lightweight-jQuery-Based-Text-To-Speech-Engine-Articulate-js/) to read content from page and speak it. It is working fine, just not works if it is speaking something and I have press tab then it stops but not reads tab selected content.
some pre-define functions
<script>
function speak(obj) {
$(obj).articulate('speak');
};
function pause() {
$().articulate('pause');
};
function resume() {
$().articulate('resume');
};
function stop() {
$().articulate('stop');
};
</script>
what I have tried
<script>
$(document).ready(function() {
var counter = 0;
setTimeout(function(){
counter +=1;
if (counter == 1){
explode();
}
},1000);
function explode(){
//$('body').articulate('speak'); // Default for play whole content
$('h1').articulate('speak');
}
$('body').keyup(function (e) {
$().articulate('stop');
if (e.which == 9) { // on tab press start speaking selected element
var i=document.activeElement.id;
$('#'+i).articulate('pause').articulate('stop').articulate('speak');
}
else{ // trying to speak what key has been pressed except tab, but not working
var i=document.activeElement.id;
$('#'+i).val().articulate('speak');
}
});
});
</script>
I am also trying to make it audible(to speak keypress) on text box, which is not working
I have make some changes now it is working, but it has certain limitation like it not reads backspace, ctrl, space etc but speak a to z,1 to 0, very well. please improve it
<script>
$(document).ready(function() {
var counter = 0;
setTimeout(function(){
counter +=1;
if (counter == 1){
explode();
}
},1000);
function explode(){
//$('body').articulate('speak'); // Default for play whole content
$('h1').articulate('speak');
}
$('body').keyup(function (e) {
var speaking = $().articulate('isSpeaking');
var paused = $().articulate('isPaused');
// $().articulate('stop');
if (e.which == 9) {
if (speaking) {
$().articulate('pause');
$().articulate('stop');
}
var check =0;
setTimeout(function(){
check +=1;
if (check == 1){
comeback();
}
},1000);
function comeback() {
var i=document.activeElement.id;
$('#'+i).articulate('speak');
}
}
else{
var i=document.activeElement.id;
var m=0;
setTimeout(function () {
m+=1;
if(m==1){
magic();
}
},500);
function magic() {
var tempval=$('#'+i).val();
var lastChar = tempval.substr(tempval.length - 1);
var ht ='<div>'+lastChar+'</div>';
$(ht).articulate('speak');
}
}
});
});
</script>
Here is a code that should open and close my site's menu. The menu is divided to divs and each one is timed to enter the screen after the other.
<script type="text/javascript">
var s=0;
function menuOpen() {
if (s==0){
document.getElementById("menu_icon").src = "x.png";
document.getElementById("nav_menu").style.zIndex = "3";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.remove('loading');
}, index * 100);
});
s++;
} else {
document.getElementById("menu_icon").src = "menu_icon.png";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.add('loading');
}, index * 100);
});
s=0;
// how to make this part run after the menu has finished folding?
setTimeout(function(){
document.getElementById("nav_menu").style.zIndex = "1";
}, 1500);
}
}
</script>
The content of the page is at z-index 2. The menu when folded is at 1 and when open at 3.
Is there a way to run the command moving the menu to z-index 1 after the menu has finished folding completely?
Currently what I did was to time the animation (1600ms) and use setTimeout. But this timing will change if I'll add more lines to my menu or if someone is clicking rapidly on the menu icon.
I'm rather new to JS and Jquery so go easy on me (:
Thanks of your help.
Below you can find the code and link to jsfiddle. Unfortunetly jsfiddle blocks the animate method for unknown reason so I don't debug, but even if it code will not work :))) I hope you will cathch the idea. And also some explanation.
Firstly our items are hidden. There are two functions displayMenu and hideMenu, they are similar, but display - run animations from the top invisible, and hide - start hide items from the bottom visible. To prevent mess I use two flags and two classes, first openFlag it is say what animations should be played now. Our hide and display functions are recursive and after they end current animation(hide or show) they check openFlag, and play next hide/show or start another chain of hide/show functions. It is the most difficult to understand part) But important that with it you can click as many times as you want and all would be fine and would be never broken by clicks.
Two classes we use as animation-chain can change behaviour and we need the way to choose items that alredy visible or hidden, so this why after each animation we set only one of this classes and remove another.
Now there is one problem if all animation are ended when we click button we should start new chain of animations, but if chain has been already started we need just to switch openFlag, and when current animation stops, it will change the behaviour. So this is the reason for btnFlag it is 1 if no active chain-animations at this moment.
After the last execution of element of animation-chain it will call callback arg, that you should pass, also at this moment will set btnFlag to 0, that means that animation-chain stopped. The openFlag as you remember changed at moment og click.
function end() {
console.log("here you can set zIndex");
}
var openFlag = 0; //become 1 after we start open elems
var btnFlag = 1;
$(document).ready(function() {
$('.toggleMenu').click(function() {
if (!$('.menuBlocks').hasClass('visible')) {
if (openFlag == 0) {
openFlag = 1;
if (btnFlag) {
var items = $('.invisibleItem');
var amount = items.length;
displayMenu(0, amount, items, end);
}
}
} else {
openFlag = 0;
if (btnFlag) {
var items = $('.visibleItem');
var amount = items.length;
hideMenu(amount - 1, items, end);
}
}
});
});
function displayMenu(i, amount, items, callback) {
if (i < amount && openFlag) {
items[i].animate({
"width": "100px"
}, 1000, function() {
items[i].removeClass('invisibleItem');
items[i].addClass('visibleItem');
displayMenu(i + 1, amount, items);
});
} else if (!openFlag) {
var items = $('.visibleItem');
var amount = items.length;
hideMenu(amount - 1, items, makeToggleVisible);
} else {
btnFlag = 1; //all aniimations ended
callback();
}
}
function hideMenu(i, items, callback) {
if (i < 0 && openFlag) {
items[i].animate({
"width": "0px"
}, 1000, function() {
items[i].removeClass('visibleItem');
items[i].addClass('invisibleItem');
hideMenu(i - 1, amount, items);
});
} else if (!openFlag) {
var items = $('.invisibleItem');
var amount = items.length;
displayMenu(0, amount, items, makeToggleVisible);
} else {
btnFlag = 1; //all animations are ended
callback();
}
}
https://jsfiddle.net/ShinShil/nrtyshv5/4/
Ok fixed it.
I moved everything to jquery. Used animate and promise.
This is what came out at the end. It is a side menu that will open it's li elements one-by-one.
var s=0;
var navMenu = document.getElementById("nav_menu");
var navBtn = document.getElementById("btn");
$(document).ready(function(){
$("button").click(function(){
if (s==0) {
navMenu.style.zIndex = "4";
navBtn.classList.add('close');
$('ul').each(function() {
$(this).children().each(function(i) {
$(this).delay(i * 100).animate({left:0});
});
});
$( "li" ).promise().done(function() {
navMenu.style.zIndex = "4";
});
s++;
}
else {
navBtn.classList.remove('close');
$('ul').each(function() {
$(this).children().each(function(i) {
$(this).delay(i * 100).animate({left:"100%"});
});
});
s=0;
$( "li" ).promise().done(function() {
navMenu.style.zIndex = "1";
});
}
});
});
and with CSS transitions.
var s=0;
function menuOpen() {
if (s==0){
document.getElementById("menu_icon").src = "x.png";
document.getElementById("nav_menu").style.zIndex = "3";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.remove('loading');
}, index * 100);
});
s++;
$("#last").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
document.getElementById("nav_menu").style.zIndex = "3";
});
} else {
document.getElementById("menu_icon").src = "menu_icon.png";
$('.box-wrapper').each(function(index, element) {
setTimeout(function(){
element.classList.add('loading');
}, index * 100);
});
s=0;
$("#last").bind("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){
document.getElementById("nav_menu").style.zIndex = "1";
$("#nav_menu").scrollTop(0);
});
}
}
so i've made a jquery carousel which you can see here: http://teste.boleiafacil.com/ (it's the one in the end of the page
this is the jquery:
//highlights slide animation
var prdlength = $(".rproducts").length;
var prdleft = 1;
var i = 0;
function swapC() {
i++;
prdleft++;
$(".rproducts").each(function(){
$(this).animate({"left":"-" + prdleft + "px"}, 10);
if (prdleft == 180){
$(this).appendTo(".rproductswrapper");
prdleft = 0;
}
});
if (i == prdlength) {
i = 0
}
window.setTimeout(function() { swapC() }, 10);
}
$(window).on("load", swapC);
the problem is when the divs get appended to the end of the wrapper it looks glitchy.
how can i fix this?
Try wrapping your function in a document ready rather than window load, the shorthand for it is:
$(function(){
//code here
});
This program randomly selects two employees from a json-object Employees array, winnerPos is already defined.
For better user experience I programmed these functions to change pictures one by one. The animation stops when the randomly selected person is shown on the screen.
The slideThrough function will be triggered when the start button is pressed.
function slideThrough() {
counter = 0;
start = true;
clearInterval(picInterval);
picInterval = setInterval(function () {
changePicture();
}, 500);
}
function changePicture() {
if (start) {
if (counter > winnerPos) {
setWinner();
start = false;
killInterval();
} else {
var employee = Employees[counter];
winnerPic.fadeOut(200, function () {
this.src = 'img/' + employee.image;
winnerName.html(employee.name);
$(this).fadeIn(300);
});
counter++;
}
}
}
The problem is the animation doesn't work smoothly. At first it works, but not perfect. The second time the transition happens in an irregular way, i.e. different speed and fadeIn/fadeOut differs from picture to picture.
Could anyone help me to fine-tune the transition?
I would avoid using setInterval() and add a function to the call to .fadeIn() that starts the animation of the next picture.
It would look like this:
function changePicture(pos) {
pos = pos || 0;
if (pos <= winnerPos) {
var employee = Employees[pos];
winnerPic.fadeOut(200, function() {
this.src = 'img/' + employee.image;
winnerName.html(employee.name);
$(this).fadeIn(300, function() {
changePicture(pos + 1);
});
});
} else {
setWinner();
}
}
To start the animation, you call changePicture() without any arguments, like this.
changePicture();
jsfiddle
I have this function which acts as a loading box using setInterval to change the background images which creates a flashing effect.
function loading() {
clearInterval(start);
var i = 0;
function boxes() {
in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
var start = setInterval(function() {
boxes();
}, 350);
}
But even with clearInterval if I click on it more than once the flashing goes out of order. I tried removing the boxes, hiding them but I can't seem to get the 'buffer' cleared? Any ideas?
The reason why it keeps flashing is because every time loading gets called it creates a new variable start, so clearInterval is actually doing nothing. You also shouldn't have the boxes function within loading because it is doing the same thing, creating a new boxes function every time loading is called. This will add a lot of lag the longer the script executes.
var i = 0;
var start;
function loading() {
clearInterval(start);
start = setInterval(function() {
boxes();
}, 350);
}
function boxes() {
var in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
Function declarations get "hoisted" to the top of their scope, this is what is messing the execution order. Check this: http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
The reason is every time you call loading it creates a new Interval or new var start. So if you click it twice, then you have two things manipulating the same data. So you need to have the var start outside of the function and the clearInterval inside. So every time you call loading it clears the interval and creates a new one.
var i = 0;
var start;
function loading() {
clearInterval(start);
start = setInterval(boxes, 350);
}
function boxes() {
in_loading = ".in_loading:eq(" + i + ")";
$(".in_loading").css("background", "url(images/load_bar_green.png) no-repeat");
$(in_loading).css("background", "url(images/load_bar_blue.png) no-repeat");
if(i == 3) {
i = 0;
} else {
i++;
}
}
maybe you should take a look at this Jquery Plugin , it seems to manage intervals very well .
Jquery Timers Plugin