Links Are Showing Of Next Slide In A Slider. Why? - javascript

I am working on a slider and all things is working fine but the problem is that it is showing link on next slide in current slide. How to fix it? You can see live DEMO at http://jsfiddle.net/gwbqvqjs/
<script type='text/javascript'>
//<![CDATA[
/* general variables */
var galleryId = 'gallery'; /* change this to the ID of the gallery list */
var gallery; /* this will be the object reference to the list later on */
var galleryImages; /* array that will hold all child elements of the list */
var currentImage; /* keeps track of which image should currently be showing */
var previousImage;
var preInitTimer;
preInit();
/* functions */
function preInit() {
/* an inspired kludge that - in most cases - manages to initially hide the image gallery list
before even onload is triggered (at which point it's normally too late, and the whole list already
appeared to the user before being remolded) */
if ((document.getElementById)&&(gallery=document.getElementById(galleryId))) {
gallery.style.visibility = "hidden";
if (typeof preInitTimer != 'undefined') clearTimeout(preInitTimer); /* thanks to Steve Clay http://mrclay.org/ for this small Opera fix */
} else {
preInitTimer = setTimeout("preInit()",2);
}
}
function fader(imageNumber,opacity) {
/* helper function to deal specifically with images and the cross-browser differences in opacity handling */
var obj=galleryImages[imageNumber];
if (obj.style) {
if (obj.style.MozOpacity!=null) {
/* Mozilla's pre-CSS3 proprietary rule */
obj.style.MozOpacity = (opacity/100) - 0;
} else if (obj.style.opacity!=null) {
/* CSS3 compatible */
obj.style.opacity = (opacity/100) - 0;
} else if (obj.style.filter!=null) {
/* IE's proprietary filter */
obj.style.filter = "alpha(opacity="+opacity+")";
}
}
}
function fadeInit() {
if (document.getElementById) {
preInit(); /* shouldn't be necessary, but IE can sometimes get ahead of itself and trigger fadeInit first */
galleryImages = new Array;
var node = gallery.firstChild;
/* instead of using childNodes (which also gets empty nodes and messes up the script later)
we do it the old-fashioned way and loop through the first child and its siblings */
while (node) {
if (node.nodeType==1) {
galleryImages.push(node);
}
node = node.nextSibling;
}
for(i=0;i<galleryImages.length;i++) {
/* loop through all these child nodes and set up their styles */
galleryImages[i].style.position='absolute';
galleryImages[i].style.top=0;
galleryImages[i].style.zIndex=0;
/* set their opacity to transparent */
fader(i,0);
}
/* make the list visible again */
gallery.style.visibility = 'visible';
/* initialise a few parameters to get the cycle going */
currentImage=0;
previousImage=galleryImages.length-1;
opacity=100;
fader(currentImage,100);
/* start the whole crossfade process after a second's pause */
window.setTimeout("crossfade(100)", 1000);
}
}
function crossfade(opacity) {
if (opacity <= 100) {
/* current image not faded up fully yet...so increase its opacity */
fader(currentImage,opacity);
/* fader(previousImage,100-opacity); */
opacity += 5;
window.setTimeout("crossfade("+opacity+")", 10);
} else {
/* make the previous image - which is now covered by the current one fully - transparent */
fader(previousImage,0);
/* current image is now previous image, as we advance in the list of images */
previousImage=currentImage;
currentImage+=1;
if (currentImage>=galleryImages.length) {
/* start over from first image if we cycled through all images in the list */
currentImage=0;
}
/* make sure the current image is on top of the previous one */
galleryImages[previousImage].style.zIndex = 0;
galleryImages[currentImage].style.zIndex = 100;
/* and start the crossfade after a second's pause */
opacity=0;
window.setTimeout("crossfade("+opacity+")", 5000);
}
}
/* initialise fader by hiding image object first */
addEvent(window,'load',fadeInit)
/* 3rd party helper functions */
/* addEvent handler for IE and other browsers */
function addEvent(elm, evType, fn, useCapture)
// addEvent and removeEvent
// cross-browser event handling for IE5+, NS6 and Mozilla
// By Scott Andrew
{
if (elm.addEventListener){
elm.addEventListener(evType, fn, useCapture);
return true;
} else if (elm.attachEvent){
var r = elm.attachEvent("on"+evType, fn);
return r;
}
}
//]]>
</script>
<style type="text/css">
#slider {max-height:700px;background: url("https://lh6.googleusercontent.com/-LLFEz-EyGbk/UyV9SbGPuhI/AAAAAAAAMgY/JNqf8X11dbk/s220/slider-loader.gif") #2e2e2e no-repeat 50% 50%;}
#gallery {padding:0;position:relative;margin:0 auto;max-width:1920px;}
#gallery li {list-style-type:none;width:100%;display:block;}
.gallery_img img {max-width:100%;}
.gallery_text {width:1000px;margin:0 auto;text-align:center;position:absolute;top:50%;left:50%;margin-left:-500px;margin-top:-110px;}
.gallery_text h2 {padding:0;line-height:70px;font-size:50px;font-weight:inherit;color:#fff;}
.gallery_text p {margin:20px 0;line-height:24px;font-size:20px;color:#ffee66;}
.gallery_text a {background:#77aa00;display:inline-block;padding:20px 70px;font-size:18px;font-weight:700;text-transform:uppercase;color:#fff;text-decoration:none;}
.gallery_text a:hover {background:#fff;color:#000;}
</style>
<div class='clear'/>
<div id='slider'>
<ul id='gallery'>
<li style='position:relative!important;'>
<div class='gallery_img'><img alt='Google' src='https://lh4.googleusercontent.com/-Nh50j1-Bqws/UyV9Pv_wd3I/AAAAAAAAMf8/nsYUnwm35Gs/s1920/slide_1.jpg' title='Google'/></div>
<div class='gallery_text'><h2>Google</h2><p>Google is an American multinational corporation specializing in Internet-related services and products. These include online advertising technologies, search, cloud computing, and software. Most of its profits are derived from AdWords.</p><a href='http://www.google.com'>Open Google</a></div>
</li>
<li>
<div class='gallery_img'><img alt='Bing' src='https://lh4.googleusercontent.com/-eGrPYj9dz1c/UyV9QgDIh5I/AAAAAAAAMgM/mlcDdyufQJs/s1920/slide_2.jpg' title='Bing'/></div>
<div class='gallery_text'><h2>Bing</h2><p>Bing is a search engine that brings together the best of search and people in your social networks to help you spend less time searching and more time doing.</p><a href='http://www.bing.com'>Open Bing</a></div>
</li>
<li>
<div class='gallery_img'><img alt='Yahoo' src='https://lh6.googleusercontent.com/-L_s8vxgupPY/UyV9RKToZeI/AAAAAAAAMgQ/TWs-wy7lbrk/s1920/slide_3.jpg' title='Yahoo'/></div>
<div class='gallery_text'><h2>Yahoo</h2><p>Yahoo! Inc. is an American multinational Internet corporation headquartered in Sunnyvale, California.</p><a href='http://www.yahoo.com'>Open Yahoo</a></div>
</li>
</ul>
</div>
<div class='clear'/>
When you will move your mouse at link then you will see that the link is showing of next slide. Here I am also adding the codes to view it here too.

See http://jsfiddle.net/gwbqvqjs/2/
Changing these lines:
galleryImages[previousImage].style.zIndex = 0;
galleryImages[currentImage].style.zIndex = 100;
to this:
galleryImages[previousImage].style.zIndex = 100;
galleryImages[(currentImage + 1) % galleryImages.length].style.zIndex = 0;
and changing other code to:
opacity=0;
window.setTimeout(function() {
galleryImages[previousImage].style.zIndex = 0;
galleryImages[previousImage].style.opacity = 0;
crossfade(opacity);
}, 5000);
fixes it. Your code is more complicated than it needs to be, swapping currentImage with previousImage previousImage=currentImage; etc. make it hard to see what's going on. Try to simplify it.

use this.. :) <a>position will change but link jumping perfectlly.
<a style="position:absolute; margin-left:-50%; top:318px;" href='http://www.google.com'>Open Google</a>
<a style="position:absolute; margin-left:-15%; top:318px;" href='http://www.bing.com'>Open Bing</a>
<a style="position:absolute; margin-left:24%; top:318px;" href='http://www.yahoo.com'>Open Yahoo</a>
Good Luck!

Related

How can I have a slot machine effect using jQuery and CSS

I want to make a slot machine. I am taking random index from array and populating it inside my div. But the only issue is that I want to have a slot machine effect. I mean that the effect should be like numbers are dropping from top to bottom. This is my code so far.
var results = [
'PK12345',
'IN32983',
'IH87632',
'LK65858',
'ND82389',
'QE01233'
];
// Get a random symbol class
function getRandomIndex() {
return jQuery.rand(results);
}
(function($) {
$.rand = function(arg) {
if ($.isArray(arg)) {
return arg[$.rand(arg.length)];
} else if (typeof arg === "number") {
return Math.floor(Math.random() * arg);
} else {
return 4; // chosen by fair dice roll
}
};
})(jQuery);
// Listen for "hold"-button clicks
$(document).on("click", ".wheel button", function() {
var button = $(this);
button.toggleClass("active");
button.parent().toggleClass("hold");
button.blur(); // get rid of the focus
});
$(document).on("click", "#spin", function() {
// get a plain array of symbol elements
var symbols = $(".wheel").not(".hold").get();
if (symbols.length === 0) {
alert("All wheels are held; there's nothing to spin");
return; // stop here
}
var button = $(this);
// get rid of the focus, and disable the button
button.prop("disabled", true).blur();
// counter for the number of spins
var spins = 0;
// inner function to do the spinning
function update() {
for (var i = 0, l = symbols.length; i < l; i++) {
$('.wheel').html();
$('.wheel').append('<div style="display: none;" class="new-link" name="link[]"><input type="text" value="' + getRandomIndex() + '" /></div>');
$('.wheel').find(".new-link:last").slideDown("fast");
}
if (++spins < 50) {
// set a new, slightly longer interval for the next update. Makes it seem like the wheels are slowing down
setTimeout(update, 10 + spins * 2);
} else {
// re-enable the button
button.prop("disabled", false);
}
}
// Start spinning
setTimeout(update, 1);
});
// set the wheels to random symbols when the page loads
$(function() {
$(".wheel i").each(function() {
this.className = getRandomIndex(); // not using jQuery for this, since we don't need to
});
});
.wheel {
width: 25%;
float: left;
font-size: 20px;
text-align: center;
}
.wheel .fa {
display: block;
font-size: 4em;
margin-bottom: 0.5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<div id="wheels">
<div class="wheel clearfix">
</div>
<!-- add more wheels if you want; just remember to update the width in the CSS -->
</div>
<p class="text-center">
<button id="spin" type="button" class="btn btn-default">Spin</button>
</p>
I managed to create a similar effect by using prepend() rather than append(), and adding a set height and hiding the overflow of the wheel.
CSS:
.wheel {
...
height: 34.4px;
overflow: hidden;
}
JS:
$('.wheel').prepend('<div style="display: none;" class="new-link" name="link[]"><input type="text" value="' + getRandomIndex() + '" /></div>');
//Using "first-of-type" rather than "last"
$('.wheel').find(".new-link:first-of-type").slideDown("fast");
See it working here.
Like so many animations it's a lot easier to fake this animation by reversing what appears to be happening, rather than making it work "correctly".
Use the code you have now to generate a result. Then create an animation for a "spinning wheel", you could shuffle divs, or you could make a 3d wheel in css. While the faces are spinning, do some calculations to decide where the wheel should stop to match your results. Then work backwards from there: You'll want to trigger your "stopping" animation so that the face is showing. Your stopping animation would be a predetermined amount of rotation and speed so that a face can be reliably shown. Depending on how fast your wheel spins, the user may lose track, if this is acceptable it may not matter when you trigger as no one could see the wheel jump.
A simulation on the other hand would use a physics model...

Angular read-more button hiding (not truncating) div content

I have a div on which I have a directive that binds HTML content and compile it (sort of ng-bing-html directive, but that also compile html to allow insertion of custom directives). The HTML code looks like this :
<div ng-repeat="text in texts">
<div class="content-display"
bind-html-compile="text | filterThatOutputsHTMLCodeWithCustomDirectives | nl2br">
</div>
</div>
The problem is I need to display only a restricted portion of each of the content-display divs, and have a "read more..." button that would expand the corresponding div to its full size. But I CANNOT truncate the text bound in the div, since it's not only text, but can contain HTML tags/directives.
I found this JQuery code, that accomplish what I want visually : https://stackoverflow.com/a/7590517/2459955 (JSFiddle here : http://jsfiddle.net/rlemon/g8c8A/6/ )
The problem is that it's not Angular-compliant, and is pure JQuery. And since my div in which I bind the HTML content is inside an ng-repeat... this solution wouldn't work when the texts array gets refreshed asynchronously.
Do you see a way to have the same behavior as in the answer linked earlier, but being more "Angular compliant" and applying it automatically to each of the content-display divs added by the ng-repeat ?
Consider using a CSS approach like the one described here: https://css-tricks.com/text-fade-read-more/
CSS:
.sidebar-box {
max-height: 120px;
position: relative;
overflow: hidden;
}
.sidebar-box .read-more {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
text-align: center;
margin: 0; padding: 30px 0;
/* "transparent" only works here because == rgba(0,0,0,0) */
background-image: linear-gradient(to bottom, transparent, black);
}
Rather than use jQuery for the read more "reveal", you could create an AngularJS directive for the read more button.
Directive (untested):
angular.module('myApp')
.directive('readMore', readMoreDirective);
function readMoreDirective() {
return function(scope, iElement) {
scope.$on('click', function() {
var totalHeight = 0;
var parentElement = iElement.parent();
var grandparentElement = parentElement.parent();
var parentSiblings = grandparentElement.find("p:not('.read-more')");
// measure how tall inside should be by adding together heights
// of all inside paragraphs (except read-more paragraph)
angular.forEach(parentSiblings, function(ps) {
totalHeight += ps.outerHeight();
});
grandparentElement.css({
// Set height to prevent instant jumpdown when max height is removed
height: grandparentElement.height(),
'max-height': 9999
})
.animate({
height: totalHeight
});
});
};
}
One clean way would be using a class for truncated div, and remove it to display all the text :
Angular scope :
$scope.truncated = []; // make new array containing the state of the div (truncated or not)
for(var i; i < texts.length -1; i++){
$scope.truncated.push(0); // fill it with 0 (false by default)
}
$scope.textTruncate = function(index) {
$scope.truncated[index] = !$scope.truncated[index]; // toggle this value
}
Angular view :
<div ng-repeat="text in texts" ng-class="{truncated: truncated[$index]}">
<div class="content-display"
bind-html-compile="text | filterThatOutputsHTMLCodeWithCustomDirectives | nl2br">
</div>
<button ng-click="textTruncate($index)" >Read more</button>
</div>
CSS :
.content-display {
max-height: 1000px; /* should be your max text height */
overflow: hidden;
transition: max-height .3s ease;
}
.truncated .content-display {
max-height: 100px; /* or whatever max height you need */
}
That is what comes in my mind, not sure if it's the most efficient way.
Try using <p data-dd-collapse-text="100">{{veryLongText}}</p> inside the ng-repeat
Documentation Here
Finally, I ended up using the approach given in this answer with a slight modification : https://stackoverflow.com/a/7590517/2459955
Indeed, since I have a ng-repeat adding more divs into the DOM, the $elem.each() function wouldn't trigger for these additional divs. The solution is to use a JQuery plugin called jquery.initialize.
This plugin gives an $elem.initialize() function that has exactly the same syntax as $elem.each() but initialize() will call the callback again on new items matching the provided selector automatically when they will be added to the DOM. It uses MutationObserver.
The final code looks like this. I have some JQuery code in my module.run() entry (run once at module initialization):
var slideHeight = 400;
$(".content-collapse").initialize(function() {
var $this = $(this);
var $wrap = $this.children(".content-display");
var defHeight = $wrap.height();
if (defHeight >= slideHeight) {
var $readMore = $this.find(".read-more");
var $gradientContainer = $this.find(".gradient-container");
$gradientContainer.append('<div class="gradient"></div>');
$wrap.css("height", slideHeight + "px");
$readMore.append("<a href='#'>Read more</a>");
$readMore.children("a").bind("click", function(event) {
var curHeight = $wrap.height();
if (curHeight == slideHeight) {
$wrap.animate({
height: defHeight
}, "normal");
$(this).text("Read less");
$gradientContainer.children(".gradient").fadeOut();
} else {
$wrap.animate({
height: slideHeight
}, "normal");
$(this).text("Read more");
$gradientContainer.children(".gradient").fadeIn();
}
return false;
});
}
});
And the corresponding HTML (cleaned for demonstration purpose):
<div class="content-collapse" ng-repeat="text in texts">
<div class="content-display" bind-html-compile="::text"></div>
<div class="gradient-container"></div>
<div class="read-more"></div>
</div>
This solution allows for smooth expand/collapse animation that works fine without any CSS hack, it adds the "Read more" button only on answers that exceeds the desired size limit, and works even if the texts array is modified by asynchronous requests.
I had a similar issue. I had o implement this for a data table. I found following directive and it worked smoothly as per requirements:-
Ui Framework- Angular js
In Html
<tr data-ng-repeat="proj in errors">
<td dd-text-collapse dd-text-collapse-max-length="40"
dd-text-collapse-text="{{proj.description}}"></td>
in Javascript:-
app.directive('ddTextCollapse', ['$compile', function($compile) {
return {
restrict: 'A',
scope: true,
link: function(scope, element, attrs) {
/* start collapsed */
scope.collapsed = false;
/* create the function to toggle the collapse */
scope.toggle = function() {
scope.collapsed = !scope.collapsed;
};
/* wait for changes on the text */
attrs.$observe('ddTextCollapseText', function(text) {
/* get the length from the attributes */
var maxLength = scope.$eval(attrs.ddTextCollapseMaxLength);
if (text.length > maxLength) {
/* split the text in two parts, the first always showing */
var firstPart = String(text).substring(0, maxLength);
var secondPart = String(text).substring(maxLength, text.length);
/* create some new html elements to hold the separate info */
var firstSpan = $compile('<span>' + firstPart + '</span>')(scope);
var secondSpan = $compile('<span ng-if="collapsed">' + secondPart + '</span>')(scope);
var moreIndicatorSpan = $compile('<a ng-if="!collapsed">... </a>')(scope);
var lineBreak = $compile('<br ng-if="collapsed">')(scope);
var toggleButton = $compile('<a class="collapse-text-toggle" ng-click="toggle()">{{collapsed ? "(less)" : "(more)"}}</a>')(scope);
/* remove the current contents of the element
and add the new ones we created */
element.empty();
element.append(firstSpan);
element.append(secondSpan);
element.append(moreIndicatorSpan);
element.append(lineBreak);
element.append(toggleButton);
}
else {
element.empty();
element.append(text);
}
});
}
};
}]);

Make a Responsive Javascript Horizontal Navigation with Logo in Center

I found a question/post on this site that works great upon first looking at it, until I need it to do more, and I have played with it and have not found a solution yet as to get it to do what I need it to do.
I am building a site for a client so I need it to be easy to operate in terms of if the client wants to change the actual order of things, so building a ul/li list on the back end within the theme is not an option, unless there is an easy way for me to modify the functions.php and change the way the menu tab is set up.
Here is my javascript coding, the menu is an actual wordpress menu.
jQuery(document).ready(function() {
jQuery("ul#menu-primary-items").find("li:contains('Home')").hide(); // hides home from navigation
var position = jQuery("ul#menu-primary-items li").length-1;
var i = 0;
jQuery('ul#menu-primary-items li').each(function() {
if(i == position/2) {
jQuery(this).after('the img src code is in here');
}
i++;
});
});
On full page width I need it to look like
Link | Link | Link | LOGO IMG | Link | Link |Link
On media width (the themes #media max-width is 999px) I need it to be a drop down style wordpress box with
LOGO IMG
WP "MENU" button
Link
Link
Link
Link
Link
Link
Instead of it displaying as the above, it shows as
WP "MENU" button
Link
Link
Link
LOGO IMG
Link
Link
Link
Check media in JQuery code, to set LOGO position:
jQuery(document).ready(function() {
jQuery("ul#menu-primary-items").find("li:contains('Home')").hide(); // hides home from navigation
var position = jQuery("ul#menu-primary-items li").length-1;
var i = 0;
/* check media here */
var isMedia999=false;
isMedia999 = (window.width() < 1000); //true if max width is <=999px
/* chek is done */
if( ! isMedia999)
jQuery('ul#menu-primary-items li').each(function() {
if(i == position/2) {
jQuery(this).after('the img src code is in here');
}
i++;
});
else jQuery('ul#menu-primary-items li').each(function() {
if(i == 0) { // <== first position if max width 999px
jQuery(this).after('the img src code is in here');
}
i++;
});
});
Of course this wont be actualized.refreshed on resize, so you could do:
jQuery(document).ready(function() {
myfunc();
windows.resize(myfunc());
});
function myfunc(){
jQuery("ul#menu-primary-items").find("li:contains('Home')").hide();
var position = jQuery("ul#menu-primary-items li").length-1;
var i = 0;
/* check media here */
var isMedia999=false;
isMedia999 = (window.width() < 1000); //true if max width is <=999px
/* chek is done */
if( ! isMedia999)
jQuery('ul#menu-primary-items li').each(function() {
if(i == position/2) {
jQuery(this).after('the img src code is in here');
}
i++;
});
else jQuery('ul#menu-primary-items li').each(function() {
if(i == 0) { // <== first position if max width 999px
jQuery(this).after('the img src code is in here');
}
i++;
});
});
}
Quite better: Use CSS and 2 logos.
1 logo is hidden for a media width > 999px, the 2nd is hidden for media <= 999px width.
#media max-width is 999px {
.logo#wide { display:none; }
.logo#tiny { display:inline; }
}
#media min-width is 1000px {
.logo#wide { display:inline; }
.logo#tiny { display:none; }
}
EDIT: JQuery :
jQuery(document).ready(function() {
jQuery("ul#menu-primary-items").find("li:contains('Home')").hide(); // hides home from navigation
var position = jQuery("ul#menu-primary-items li").length-1;
var i = 0;
jQuery('ul#menu-primary-items li').each(function() {
if(i == 0) {
//put logo tiny here for media maxwidth 999px
}
if(i == position/2) {
// put logo wide here for media minwidth 1000px
}
i++;
});
});
Does something like this could work ?
#media(max-width:whateveryouwant px)
{
.logo{
float:right;
}
}
An other approach would be to move the element threw the DOM.
You can achieve this with jQuery :
if((window).width() <= sizeYouWant){
$('.logo').insertBefore('#FirstElement');
}

How to manipulate the screen width via js?

I'll try to explain my use case here. In my site I have a break point for desktop view, and break point for tablet view (which is more compact). I'm trying to add a function to allow seeing the tablet view when browsing from desktop, cause some members prefer the compact design in their desktop as well.
For doing that, I figured I would need to trick the '#media(max-width:X)' query. I'm looking for a JS code that can manipulate the screen width value, so when the browser calculates max-width, it would be against a value that I specified.
One thing to note, this is suppose to work on desktop browsers, so the meta viewport can't be used here.
One solution is to apply a specific class (e.g: .tablet) to the body.
<body class="tablet"></body>
In your CSS:
#media screen and (/* your query */) {
.tablet .my-class {
/* tablet specific stuff */
}
}
You could then remove the .tablet class and replace it with .desktop via JavaScript
var body = document.body;
var switchToDesktop = function() {
body.className = body.className.replace('tablet', 'desktop');
}
var switchToTablet = function() {
body.className = body.className.replace('desktop', 'tablet');
}
var toggleView = function() {
(body.className.indexOf("tablet") > -1) ?
switchToDesktop() :
switchToTablet();
}
If you are using SASS or LESS, you can nest the tablet-specific styles.
#media screen and (/* your query */) {
.tablet {
h1 {
/* tablet specific h1 */
}
.my-div {
color: red;
}
/* etc... */
}
}

toggle body background

I hope someone can help me with this, I have this javascript code that toggles my body background
function changeDivImage() {
imgPath = document.body.style.backgroundImage;
if (imgPath == "url(images/bg.jpg)" || imgPath == "") {
document.body.style.backgroundImage = "url(images/bg_2.jpg)";
} else {
document.body.style.backgroundImage = "url(images/bg.jpg)";
}
}
I activate it with this link:
change
my problem is that it works fine in IE and firefox, but in chrome, the links work twice then stop working, it basically switches to bg_2.jpg then once clicked again switches back to bg.jpg then it never works again :/
also, is there an easier way to accomplish this? css only maybe? basically i have two body background pictures and i want to be able to click on the link to toggle 1, then click again to toggle 2 instead, then back to 1, etc...
lastly, how can i make the two backgrounds fade in and out? instead of just switch between the two?
Use CSS classes!
CSS Rules
body { background-image: url(images/bg.jpg); }
body.on { background-image: url(images/bg_2.jpg); }
JavaScript:
function changeDivImage() {
$("body").toggleClass("on");
}
If you want to fade, you will end up having to fade the entire page. Use can use jQuery's fadeIn and fadeOut.
Here is your solution:
(This also supports additional images).
var m = 0, imgs = ["images/bg.jpg", "images/bg_2.jpg"];
function changeDivImage()
{
document.body.style.backgroundImage = "url(" + imgs[m] + ")";
m = (m + 1) % imgs.length;
}
Here is the working code on jsFiddle.
Here is the jQuery version on jsFiddle.
UPDATE: CROSS-FADING Version
Here is the cross-fading jQuery version on jsFiddle.
You wouldn't want the whole page (with all elements) to fade in/out. Only the bg should fade. So, this version has a div to be used as the background container. Its z-depth is arranged so that it will keep itself the bottom-most element on the page; and switch between its two children to create the cross-fade effect.
HTML:
<div id="bg">
<div id="bg-top"></div>
<div id="bg-bottom"></div>
</div>
<a id="bg-changer" href="#">change</a>
CSS:
div#bg, div#bg-top, div#bg-bottom
{
display: block;
position: fixed;
width: 100%;
/*height: 500px;*/ /* height is set by javascript on every window resize */
overflow: hidden;
}
div#bg
{
z-index: -99;
}
Javascript (jQuery):
var m = 0,
/* Array of background images. You can add more to it. */
imgs = ["images/bg.jpg", "images/bg_2.jpg"];
/* Toggles the background images with cross-fade effect. */
function changeDivImage()
{
setBgHeight();
var imgTop = imgs[m];
m = (m + 1) % imgs.length;
var imgBottom = imgs[m];
$('div#bg')
.children('#bg-top').show()
.css('background-image', 'url(' + imgTop + ')')
.fadeOut('slow')
.end()
.children('#bg-bottom').hide()
.css('background-image', 'url(' + imgBottom + ')')
.fadeIn('slow');
}
/* Sets the background div height to (fit the) window height. */
function setBgHeight()
{
var h = $(window).height();
$('div#bg').height(h).children().height(h);
}
/* DOM ready event handler. */
$(document).ready(function(event)
{
$('a#bg-changer').click(function(event) { changeDivImage(); });
changeDivImage(); //fade in the first image when the DOM is ready.
});
/* Window resize event handler. */
$(window).resize(function(event)
{
setBgHeight(); //set the background height everytime.
});
This could be improved more but it should give you an idea.
There's a cleaner way to do this. As a demo, see:
<button id="toggle" type="button">Toggle Background Color</button>
var togglebg = (function(){
var bgs = ['black','blue','red','green'];
return function(){
document.body.style.backgroundColor = bgs[0];
bgs.push(bgs.shift());
}
})();
document.getElementById('toggle').onclick = togglebg;
http://jsfiddle.net/userdude/KYDKG/
Obviously, you would replace the Color with Image, but all this does is iterate through a list that's local to the togglebg function, always using the first available. This would also need to run window.onload, preferably as a window.addEventListener/window.attachEvent on the button or elements that will trigger it to run.
Or with jQuery (as I notice the tag now):
jQuery(document).ready(function ($) {
var togglebg = (function () {
var bgs = ['black', 'blue', 'red', 'green'];
return function () {
document.body.style.backgroundColor = bgs[0];
bgs.push(bgs.shift());
}
})();
$('#toggle').on('click', togglebg);
});
http://jsfiddle.net/userdude/KYDKG/1/
And here is a DummyImage version using real images:
jQuery(document).ready(function ($) {
var togglebg = (function () {
var bgs = [
'000/ffffff&text=Black and White',
'0000ff/ffffff&text=Blue and White',
'ffff00/000&text=Yellow and Black',
'ff0000/00ff00&text=Red and Green'
],
url = "url('http://dummyimage.com/600x400/{img}')";
return function () {
document.body.style.backgroundImage = url.replace('{img}', bgs[0]);
bgs.push(bgs.shift());
}
})();
$('#toggle').on('click', togglebg);
});
http://jsfiddle.net/userdude/KYDKG/2/

Categories