Changing "background-image:" on a timer using javascript not working - javascript

I was wondering if you would mind taking a look at the following code and tell me where I'm going wrong. I know close to nothing about javascript but I was able to some code that is supposed to do what I want. I've got a div ID makes a fullscreen image background. I want to change out what image is used every 5000 milliseconds. Here's the javascript:
<script type="text/javascript">
$(window).load(function() {
var i =0;
var images = ['cover1.jpg','cover2.jpg'];
var image = $('.cover_image');
image.css('background-image', 'url(/img/cover1.jpg)');
setInterval(function(){
image.fadeOut(1000, function () {
image.css('background-image', 'url(' + images [i++] +')');
image.fadeIn(1000);
});
if(i == images.length)
i = 0;
}, 5000);
});
</script>
Here's the CSS being used:
.cover_image {
background-repeat: no-repeat;
background-image: url("/img/cover1.jpg");
background-position: bottom center;
background-size: cover;
z-index: -3;
position: relative;
}
And here's the HTML:
<div class="slide cover_image"></div>

You have 2 problems here, when you use JQuery, and your "loop"
JQuery Loading
JQuery isn't always loaded at the same time as Javascript. So trying to detect when Javascript is loaded to use JQuery might let you use Javascript code, as soon as you run some JQuery selectors, it'll crash. And burn. So don't do that.
Why?
Most modern browsers excuse many Javascript files at once. This means JQuery starts when the document is ready, and your code tries to use the uninitialized JQuery library. This means you use something that's not there. It's like trying to read the end of th
If your only objective was to read the end of that sentence, you would crash, too.
Zero-Indexed Arrays
Also, I made a change to the way your loop works, because it was somewhat broken. Javascript has 0-indexed arrays, so trying to get the .length of an array with 2 elements will return 2, but the elements are at [0] and [1].
Why?
It was mainly because computers could started counting at zero, so in the old days, it made no sense to waste a bit (literally), and it was also much more processor intensive to do arithmetic, so starting at zero made sense. We could switch to 1-indexed arrays, like Lua does, but it's still a bit friendlier on computers to start at zero, plus many programmers were used to it, and changing an aspect like that will break older programs.
Code/TL;DR;
$(function(){
var i =0;
var images = ['cover1.jpg','cover2.jpg'];
var image = $('.cover_image');
image.css('background-image', 'url(/img/cover1.jpg)');
setInterval(function(){
image.fadeOut(1000, function () {
image.css('background-image', 'url(' + images[i] +')');
image.fadeIn(1000);
});
if(i == (images.length - 1)){
i = 0;
} else {
i++;
}
}, 5000);
})

Bootstrap has a "carousel" class that looks great and works without the need for extensive JS. If you don't know what Bootstrap is, I would advise looking it up because I use it on almost all of my webpages. Here's a link to a carousel example: http://www.w3schools.com/bootstrap/bootstrap_carousel.asp

Related

What is going on behind the scenes and is this the proper way to do this? (modifying the DOM via Javascript)

Not knowing the proper way, after much research on the web I found so many different ways to do something its confusing. The way I tried, and kinda worked is the following...
My CSS
#Content {
left:0px;
top:1px;
width:988px;
z-index:1;
background-color: #FFFFFE;
}
My JS
function Gradients(id) //<- this id not used during testing, i hard coded it below
{
var getit = document.getElementById("Content");
getit.style.backgroundColor="#CCCCCC";
//alert(origcolor);
//var value = document.getElementById("Content").style.backgroundColor;
//var value = document.styleSheets[0].cssRules[0].style.backgroundColor;
}
My HTML (just a test)
<div onClick="Gradients("Content");">Gradients Test:<span>#XXXXXX</span></div>
Firebug Results - bad?
<div id="Content" style="background-color: rgb(204, 204, 204);">
WHAT I'M TRYING TO ACCOMPLISH
My goal was to read the background of an input field (each has an id) and slowly change it to red FROM the DEFAULT color in the CSS to let them know the field was incorrect.
Right now my website just slams it to red and I thought - how hard can it be to gradient a color. So, my mainpage has less clutter so I thought I would try to gradient the background of something. As with all web stuff it's messier than I thought.
I even spent a couple of hours reading up on jQuery but I don't want to pull in a whole library for this 1 tiny thing I will be doing.
Other Info
It's kinda like how THIS stackoverflow website fades from yellow to white the DIV of my question when I come here. Except mine will be in input fields. I have some commented out stuff in my JS because I was trying different things. I removed some of the things that were ugly. It works as is BUT I don't know if it's a good way to do it because firebug shows it added something to the DIV inline.
I like clean code... and my code up there seems ugly because I added something to the DIV. Can't I change the CSS value or is this the proper way to do it?
A couple of questions...
1) Proper way to do it?
2) If thats the proper way to do it how do I delete that change and have it revert back to the CSS style? Or an ugly method would be to just stick the original value I stored before performing the gradient.
3) YOUR much better clean way of doing it :)
4) Is there an elegant way to READ the value in the CSS style sheet?
The reason I didn't go with the document.stylesheets is to me....it seemed ugly... what if it's not [0]. How do I know it will always be [0]. What if it's different in different browsers? sigh. I don't fully understand the DOM. I understand what child nodes and parent nodes are but when looking through firebug it's a huge mess all over the place and I have no clue where to find things, how to insert things and I don't like modifying the DOM much anyways - i would love a simple thing like this (and yes, I am guessing on the code below - if only it could be that easy) lol...
I wish it was this easy in javascript...
$original_color = getElementById("Content").style.backgroundColor;
// loop through starting AT the original_color and gradient to red somehow
//start loop here
getElementById("Content").style.backgroundColor = newcolor;
// end loop here
Awaiting an infusion of wisdom please :)
WHAT I TRIED RECENTLY AFTER POSTING and Reading examples on here -- My JS
var RGradient = 0;
var GGradient = 0;
var GStop = 0;
var BGradient = 0;
var BStop = 100;
var idGradient;
function Gradients(id)
{
var startcolor = "#FFFFFE";
RGradient = hexToR(startcolor);
GGradient = hexToG(startcolor);
BGradient = hexToB(startcolor);
idGradient = document.getElementById(id);
window.setTimeout("GradientIt()", 10);
}
function GradientIt()
{
if (GGradient == GStop && BGradient == BStop) return;
if (GGradient > GStop) GGradient--;
if (BGradient > BStop) BGradient--;
idGradient.style.backgroundColor="#"+(RGradient).toString(16)+(GGradient).toString(16)+(BGradient).toString(16);
document.getElementById('gtest').innerHTML = "#"+(RGradient).toString(16)+(GGradient).toString(16)+(BGradient).toString(16);
window.setTimeout("GradientIt()", 5);
}
function hexToR(h) { return parseInt((cutHex(h)).substring(0,2),16) }
function hexToG(h) { return parseInt((cutHex(h)).substring(2,4),16) }
function hexToB(h) { return parseInt((cutHex(h)).substring(4,6),16) }
function cutHex(h) { return (h.charAt(0)=="#") ? h.substring(1,7) : h}
ERROR in IE
I'm getting an error in IE AFTER it turns the background to red... - Invalid Property in Line 29 which is the line with all the toString(16)'s in it above.
Can someone explain why it's giving an error in IE please? I am checking if I'm above 0 so the numbers should stay 0 or higher. The other browsers don't give an error that I can see. Once it's working I will be changing it - this is just a "hacked together" test - I'll make it more efficient later on when it's on the page I want.
I spent about an hour trying to pass variables to setTimeout before I realized I can't. UGH! lol. Globals :( Can't wait for CSS3 full compatibility in ALL browsers.
I would suggest achieving this using either css3 or jquery (a javascript library)
To do it with css3 is rather simple, this article should have all the necessary information
http://net.tutsplus.com/tutorials/html-css-techniques/css-fundametals-css-3-transitions/
To do it with jQuery you will need to download jquery and preferably have a little bit of experience with javascript although it is not generally required to pick up jQuery for simple things like this. This is the jQuery function you would want to use:
http://api.jquery.com/animate/
#content {
left:0px;
top:1px;
width:988px;
z-index:1;
background-color: #FFFFFE;
transition: 0.3s;
-moz-transition: 0.3s;
-webkit-transition: 0.3s;
}
#content:focus {
background-color: #f00;
transition: 0.3s;
-moz-transition: 0.3s;
-webkit-transition: 0.3s;
}
The above is CSS3 and works in many browsers. However IE support is (as always) lacking.
via javascript/jquery....
function animate_bg(ele, from, to) {
from += from > to ? -1 : 1;
if(!$.support.opacity){
if(from != to){
var opStr = (Math.round(from * 25.5)).toString(16);
//alert(opStr)
ele.css({background:'transparent',filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#" + opStr + "fffff0, endColorstr=#" + opStr + "f00000)"});
}else{
ele.css({background:'transparent',filter:"none"});
}
}else{
ele.css("backgroundColor", "rgba(255, 0, 0, " + (from) / 10 + ")");
}
if(from != to)
setTimeout(function() { animate_bg(ele, from, to) }, 60);
}
and usage....
animate_bg($('...'), 8, 0);

jQuery image crossfade with pre-loader

I want a simple image crossfade, similar to http://malsup.com/jquery/cycle/, but with a pre-loader. Is there a good jQuery plugin that does both? Also, I'm not looking for a load bar.
This question is close, but not the same => jQuery Crossfade Plugin
It would be great if it was a solution that defaulted to CSS3, but would otherwise fall back to JS to keep the processing native as possible.
Looking for something that..
will autoplay
without controls
will go to the next image based on time setting, ie. 5 seconds, unless the next image isn't loaded in which case it finishes loading the image and then displays it.
crossfade transition, not fade to black or white, but cross-fade. from the start it would fadein.
no thumbnails or galleries, etc. just the image
If images could be CSS background images, that would be best, so users can't drag out the image simply
Each panel needs to be clickable so a user could click the image and go to a part of the website.
Well, here's my poke at it. The preloader is in vanilla js and the slideshow loop is in jQuery. It's very simple to implement and the concept is even simpler.
Demo
a very simple Demo that illustrates the DOM manipulation approach
HTML
<!-- not much here... just a container -->
<div id="content"></div>
CSS
/* just the important stuff here. The demo has example styling. */
#content
{
position:relative;
}
#content img
{
position:absolute;
}
javascript/jQuery
// simple array
var images = [
"http://imaging.nikon.com/lineup/dslr/d90/img/sample/pic_003t.jpg",
"http://imaging.nikon.com/lineup/dslr/d90/img/sample/pic_005t.jpg",
"http://imaging.nikon.com/lineup/dslr/d90/img/sample/pic_001t.jpg"
];
// some adjustable variables
var delay = 2000;
var transition = 1000;
// the preloader
for(var i in images)
{
var img = document.createElement("img");
img.src = images[i];
img.onload = function(){
var parent = document.getElementById("content");
parent.insertBefore(this,parent.childNodes[0]);
if(i == images.length - 1)
{
i = 0;
startSlides();
}
}
}
// and the actual loop
function startSlides()
{
$("#content img:last").delay(delay).fadeTo(transition,0,function(){
$(this).insertBefore($(this).siblings(":first")).fadeTo(0,1);
startSlides();
});
}
The concept in brief is to fade the first image in a container, once complete change it's position in the DOM (effectively hiding it behind equal tree level siblings), and call the function again. The reason why this works is because it only fades the first child of the container, but on callback it changes what node that is constantly looping the nodes. This makes for a very small source file that is quite effective.
EDIT 1:
and 32 minutes tweaking later...
Demo 2
EDIT 2:
My oh so simple script is now very complicated :P I added in some scaling features that only work on modern browsers but are there if needed. This one also has a loading bar as it preloads the images (may or may not be desirable :P)
small images demo
large images demo
I think you can still do this with the jQuery cycle plugin; other than image preloading, even the jQuery cycle lite version does everything you want by default out-of-the-box.
And if you look here, you'll see that it's pretty simple to add a little Javascript that will add images (after the first two) as they load. You would need to modify the code a little (instead of stack.push(this), you'd want something like stack.push("<div style="background-image:url("+img.src+")"></div>"), for example) but I think it's totally doable.
Edit: here's a link to a SO question about how to make a div into a clickable link.
Edit 2: I liked Joseph's idea to just move the elements to a hidden DIV, so I updated my code a bit. It now also preserves the links each div points to as well: http://jsfiddle.net/g4Hmh/9/
Edit 3: Last update! http://jsfiddle.net/g4Hmh/12/
UPDATE Added the ability to load everything asynchronously.
A wrapper for the jQuery cycle plugin should suffice. You really just need something that monitors if the images loaded and then calls $(elem).cycle(/* options */). Here's my take:
$.fn.cycleWhenLoaded = function(options) {
var target = this,
images = options.images,
loaded = 0,
total = 0,
i;
if(images) {
for(i = 0; i < images.length; i ++) {
$('<img/>').attr('src', images[i]).appendTo(target);
}
}
this.find('> img').each(function(index) {
var img = new Image(),
source = this;
total ++;
if(index > 1)
$(this).hide();
img.onload = function() {
loaded ++;
if(loaded == total) {
target.trigger('preloadcomplete');
target.cycle(options);
}
};
setTimeout(function() {img.src = source.src}, 1);
});
return this;
};
This allows you to either do a simple delay load:
$('.slideshow').cycleWhenLoaded({
fx: 'fade'
});
Or you can do something more complicated and load your images in the script and capture the preload complete event:
$('.slideshow2').hide().cycleWhenLoaded({
fx: 'fade',
images: [
"http://cloud.github.com/downloads/malsup/cycle/beach1.jpg",
"http://cloud.github.com/downloads/malsup/cycle/beach2.jpg",
"http://cloud.github.com/downloads/malsup/cycle/beach3.jpg",
"http://cloud.github.com/downloads/malsup/cycle/beach4.jpg",
"http://cloud.github.com/downloads/malsup/cycle/beach5.jpg"
]
}).bind('preloadcomplete', function() { $(this).show(); });
You can see it in action here: http://fiddle.jshell.net/vmAEW/1/
I don't know how close this is to what you are looking for, but I figured since no one else did I would at least try to help. http://galleria.aino.se/
It at least has a preloader and a fade transition.

Custom Animation With JavaScript

I'm trying to do very basic, custom animation with JavaScript. I'm using a library called Modernizr to detect HTML5 support, and if a browser doesn't support CSS3 Transitions, I'd like to have my own custom (non jQuery) script that recreates the same effect of CSS3 Transitions.
My idea for this code is this:
JS:
function slide() {
var cur = 0;
while (cur <= 50) {
setInterval("document.getElementById('slider').style.marginLeft=cur + 'px'",100);
cur = cur++;
}
}
HTML (for hovering):
<div id="slider" onmouseover="slide()">
This should slide left.
</div>
This doesn't work (I know it doesn't loop, that's one of the issues that I can't figure out). I'm pretty new with JS so I don't know some pretty basic stuff.
The main reason that I don't want to use jQuery is for educational purposese. I want to know basic JS before I learn jQuery, just so I know how to do the things I want to do.
I'd like this to work for two different cases, one being automatically, one being only on hover (and the hover version doesn't have to loop). I had something kind of working on hover, but the more you hovered over it, the faster it would move.
Thanks!
function slide() {
var cur = 0;
while (cur >= 50) {
setInterval("document.getElementById('slider').style.marginLeft=cur + 'px'",100);
cur = cur++;
}
}
Your code sets cur to 0, and then the while condition is cur >= 50 (*while cur variable is larger or equal to 50) which will never be true because it is 0.
Also, animating with a loop is not a good idea, as the browser likely won't render the results in a manner that is pleasant to look at (or at all). Use setInterval() without the loop.
If I was tasked with writing this, it may look like...
function slide(element, newHeight) {
var currentHeight = element.offsetHeight;
var increaseHeight = function() {
currentHeight += 10;
element.style.height = currentHeight + 'px';
}
var interval = setInterval(function() {
if (currentHeight >= newHeight) {
clearInterval(interval);
}
increaseHeight();
}, 100);
}
jsFiddle.
There are many examples of doing sliding in javascript.
Here is one of them.
http://www.harrymaugans.com/2007/03/06/how-to-create-an-animated-sliding-collapsible-div-with-javascript-and-css/
In your example, if you use setInterval you will also want to call clearInterval. For a description of both you can look at: https://developer.mozilla.org/en/window.setInterval
Hopefully you aren't actually using the onmouseover function in the element, as shown, but are instead checking if you need this, then setting it after the page has loaded.
You may want to look at unobtrusive javascript to get an idea how this can be done well.
There are various articles on this, but you could start with:
http://labs.adobe.com/technologies/spry/articles/best_practices/separating_behavior.html

Fx on JavaScript: How to fade stuff, etc without frameworks?

I would like to learn how to do fade, and similar effects on JavaScript. I often get answers, like why not use jQuery, Mootools, etc ? Well, I want to learn how stuff works, then I won't mind using any of these frameworks.
I'm currently learning about making changes on the DOM, so, I've read a lot of stuff on this theme. Also, I've read about Reflow, still, I didn't find any cool stuff on Repaint, but, I'll keep searching.
From seeing source files etc, I see a few methods, that I don't know if they've created or are Core methods of JS.
My question is, is there any resource where I can learn all this neat stuff like smooth position change, fading elements trough opacity or whatever, etc?
Take a look at emile.js. It's brand-spanking new. Great way to learn how to do your own.
Introduced at the recent jsconf conference. Written by Thomas Fuchs (script.aculo.us).
http://github.com/madrobby/emile
Émile Stand-alone CSS animation
JavaScript mini-framework
Doesn't need
a JavaScript framework
Full set of CSS
properties for animation (length-based
and colors)
Easing and callbacks
Less
than 50 lines of code
Get updates on
Twitter: http://twitter.com/emilejs
here's an example that works in firefox and chrome. ie doesn't respect the opacity style.
var ELEMENT;
var STEPS;
var INTERVAL;
var COUNT;
var TIMERID;
// 5 * 200ms = 1 second
STEPS = 5;
INTERVAL = 200;
function Button1_onclick() {
ELEMENT = document.getElementById("foo");
COUNT = STEPS - 1;
TIMERID = setInterval(Fade, INTERVAL);
}
function Fade() {
ELEMENT.style.opacity = String(COUNT / STEPS);
COUNT--;
if (COUNT < 0) {
clearInterval(TIMERID);
TIMERID = 0;
}
}
setInterval and clearInterval are standard js functions. they will execute the given function every x milliseconds. in our case we kill it when we've hit 0 opacity.
sliding a window is a similar process. you'd set the left/right/top/bottom style instead of opacity.
Fading using javascript is basically modifying opacity of an element programmatically. The "smoothness" is done by using timers. Same for position/size changes. You need to read up on css to understand what style properties of an element you have to control using javascript for the effect you want.
If you are really curious, you can dive into the source of yui in github: http://github.com/yui

How do I pre-cache images for quick viewing with javascript?

I have a webpage where I want the user to see a new image when they put thier mouse over a certain part of the image. I used an image map.
<img src="pic.jpg" usemap="#picmap" />
<map id="picmap" name="picmap"><area shape="rect" coords ="10,20,30,40"
onMouseOver="mouse_on_write('mouse is on spot')"
onMouseOut="mouse_off('mouse is off spot')"
href="http://www....html" target="_blank" />
</map>
<p id="desc"></p>
Where in the header I defined these functions:
<script type="text/javascript">
function mouse_off(txt)
{
document.getElementById("desc").innerHTML=txt;
document.p1.src="pic.jpg";
}
function mouse_on_write(txt)
{
document.getElementById("desc").innerHTML=txt;
document.p1.src="pic2.jpg";
</script>
It works, but it is slow. When the mouse is put over the second image it takes some few seconds to appear; my temporary solution was to drastically reduce the size of the images because they were huge (at 2.5mb they switch fast now, but still not seamless). How can I make the image switching more seamless without reduction in picture quality?
On second thought I realize that I could also just have both images displayed, at a small and a large scale, and on mouse over they would switch places; How would I do this? Would this reduce lag?
You don't need to create any page elements, it can all be preloaded using JavaScript:
tempImg = new Image()
tempImg.src="pic2.jpg"
EDIT:
If you have a lot of images, you can use the poor-man's multi-preloader:
preloads = "red.gif,green.gif,blue.gif".split(",")
var tempImg = []
for(var x=0;x<preloads.length;x++) {
tempImg[x] = new Image()
tempImg[x].src = preloads[x]
}
Doing this with sprites is a good solution, because you don't have to wait to load the new image. Sprites work by combining the two images into one, and changing the background offset on mouseover.
You can even do with with CSS instead, for much faster results. There's a good tutorial on this here.
As of Javascript 1.6 this can be accomplished without any named variables:
imageList.forEach( function(path) { new Image().src=path } );
You can also put both images in same file and offset it up and down. If it should affect element you are crossing over with mouse it could look like
a {
background-image: url(back.png);
background-repeat: no-repeat;
background-attachment:fixed;
background-position: 0 0;
}
a:hover {
background-image: url(back.png);
background-repeat: no-repeat;
background-attachment:fixed;
background-position: 0 20px;
}
This way it can work without javascript.
If I understand your case correctly you still need javascript, but you can "preload" image this way nevertheless.
What you want todo is preload the images behind the scenes.
Then, when moused over, the browser will already have that image in its cache and will switch it over very fast.
function preloadImage(imagePath)
{
var img = document.createElement('IMG');
img.src = imagePath;
}
preloadImage('BigImage');
Clever solution from Diodeus. However, unless there's a good reason NOT TO, you should really consider using sprites. It's a bit of work to get them setup, but the net efficiency is really worth it.
This approach is the number one rule in Steve Souder's High Performance Web Sites.
"Rule 1 - Make Fewer HTTP Requests"
Good luck and have fun. - D.
I've noticed that 'preloading' into .src to this day doesn't work consistently across all browsers - IE7 still can't figure out how to cache / use preloaded images - you can clearly see there's a server request made every time you mouse over.
What I do is load in all images via standard HTML placement and just toggle style.display on and off.
Use display: none;, then have the Javascript change it to display: inline when you want to display it. This has the added advantage of being able to put the image exactly where you want in the page's source, rather than having to add it with Javascript later.
Here's how I do it, in pure JavaScript:
var myImgs = ['path/to/img1.jpg', 'path/to/img2.gif'];
function preload(imgs) {
var img;
for (var i = 0, len = imgs.length; i < len; ++i) {
img = new Image();
img.src = imgs[i];
}
}
preload(myImgs);
That said, ALassek's suggestion of using CSS sprites is an excellent one, if you have scope to do it. The advantages of sprites are many: fewer HTTP requests, smaller download size (usually), works without JavaScript enabled.
http://www.filamentgroup.com/lab/update_automatically_preload_images_from_css_with_jquery/
When we first launched the lab, we released a jQuery plugin that automatically preloads all images referenced in CSS files. We've found the script to be incredibly helpful in developing snappy applications where images are always ready when we need them. This post describes a significant update to the script which will make it even easier to integrate in existing projects.

Categories

Resources