Hey im having trouble with my javascript rollover. The image does not change. Ive had a look at some tutorials and i cant see where im going wrong.
Here is my code:
Home.xhtml
<img src="images/Weights.png" width="900" height="300" border="0" alt="Gym Equipment" name="gym"
onMouseOver="swapImage('gym','treadmill');" onmouseout="swapImage('gym','weights');"/>
newjs.js
// Pre load images for rollover
if (document.images)
{
treadmill = new Image
weights = new Image
treadmill.src = "images/Treadmill.png"
weights.src = "images/Weights.png"
}
function swapImage(thisImage,newImage)
{
if (document.images)
{
document[thisImage].src = eval(newImage + ".src")
}
}
How i tell the app where the js is:
document[thisImage].src = eval(newImage + ".src")
should be
document[thisImage].src = eval(newImage ).src
Please avoid using eval() as it is generally the slowest way to evaluate code and there are some circumstances where it introduces security risks depending upon where the data comes from that you're calling eval on.
You should be able to make this work:
HTML:
<img src="images/Weights.png" width="900" height="300" border="0" alt="Gym Equipment" name="gym"
onMouseOver="swapImage(this,'treadmill');" onmouseout="swapImage(this,'weights');"/>
Javascript:
// Pre load images for rollover
window.treadmill = new Image();
window.weights = new Image();
treadmill.src = "images/Treadmill.png"
weights.src = "images/Weights.png"
// this function must be defined globally
// (e.g. not defined inside any other function)
function swapImage(thisImage,newImageName) {
thisImage.src = window[newImageName].src;
}
Working demo here: http://jsfiddle.net/jfriend00/cv8tT/
Changes I made:
Removed the use of eval() and use window[name] to access global variables.
Changed the way swapImage() is called in the HTML to pass this so you can directly access the desired image.
Remove the if (document.images) checks since it is no longer used by the code.
FYI, all this could be done with CSS and background images with no javascript at all.
I would take a slightly different approach by taking the mouseover and mouseout attributes out of your image tag. This will help keep your code more maintainable.
I made a DEMO jsfiddle here
Note that I am using 3 images from Flickr, the default, one on mouseover, and one on mouseout. I hope this helps.
** Also note that the img tag now has an ID which is referenced in the bindings.
// Pre Load Images
var img1 = new Image();
var img2 = new Image();
img1.src = "http://farm4.staticflickr.com/3230/2953035318_b54956e7df_q.jpg";
img2.src = "http://farm4.staticflickr.com/3026/2992860864_aa9e8b0818_q.jpg";
// Event binding function
var bindEvent = function (el, eventName, eventHandler) {
if (el.addEventListener != null) {
return el.addEventListener(eventName, eventHandler, false);
} else if (el.attachEvent != null) {
return el.attachEvent('on' + eventName, eventHandler);
}
}
// Mouseover binding
bindEvent(document.getElementById('surfer'), "mouseover", function (e) {
this.setAttribute("src", img1.src);
});
// Mouseout Binding
bindEvent(document.getElementById('surfer'), "mouseout", function (e) {
this.setAttribute("src", img2.src);
});
Related
I have a div
<div id='cards'>
Which I want to fill with images based on some logic. But only when images are first loaded into memory. Otherwise, through onerror I wanna fill in some text..
function pasteCard(card, to){
if (typeof(card) == 'string')
card = [card];
var image = [];
for (var i = 0; i < card.length; i++) {
image[i] = new Image();
image[i].src = '/sprites/open/' + card[i] + '.png';
image[i].onload = function() {
pasteImage(to, image[i]);
}
image[i].onerror = function() {
pasteText(to, card[i]);
}
// alert(card[i]) #1
}
function pasteImage(to, image) {
to.append(image);
}
function pasteText(to, text) {
// alert(card[i]) #2
to.append(text);
}
}
pasteCard(['ABC123', 'DEF456', 'GHI789'], $('#cards'));
But this isn't working.
Problem/weirdness: If only #2 alert is active it returns nothing. But strangely if #1 alert is also active it does kinda work... (but still doesn't load my images, and mostly fails too when other code is involved)
Question: Why is it not working without #1 alert (at least in that jsfiddle)
suggestions?: what should I do?
Onload and onerror events are fired (executed) outside the scope of your function so your variables will be undefined. In the event method you have access to this which is the image object. You can set a data attribute to each image and access that in your error event.
Here is an example:
http://jsfiddle.net/7CfEu/4/
The callbacks are not in the same scope as your image array is - therefor you need to declare a variable then will "connect the scopes" and use it inside the callbacks
also the i variable probably changes until the callback is fired - so by using it inside the callback you will get undefined behavior
for (var i = 0; i < card.length; i++) {
var current_card = card[i];
var current_image = new Image();
current_image.onload = function() {
pasteImage(to, current_image);
}
current_image.onerror = function() {
pasteText(to, current_card);
}
current_image.src = '/sprites/open/' + current_card + '.png';
image[i] = current_image;
}
Fiddle: http://jsfiddle.net/7CfEu/6/
(Also - closing the div tag is never a bad idea)
Just in case anyone ends up here for same reason I did.
Was going crazy because onload and onerror were not firing in the page I was building. Tried copy pasting
var myimage = new Image();
myimage.onload = function() { alert("Success"); };
myimage.onerror = function() { alert("Fail"); };
myimage.src = "mog.gif" //Doesn't exist.
Which was working within codepen and random otherwise blank pages.
Turns out the problem I was having was that I was doing AJAX requests earlier in the page. This involved authorization which in turn involved a call to
setRequestHeader();
This was resulting in a net::ERR_FILE_NOT_FOUND error instead of the expected GET mog.gif 404 (Not Found)
This seemed to prevent proper triggering of events.
Revert with
xhr.setRequestHeader("Authorization", "");
Can images be preemptively loaded into the page with javascript so that they can be used at any time as a CSS background image without any request/upload delay?
If so, how?
You don't even need to use JS for this (with the downside of delaying the page load event). Include something like this:
<img src="/path/to/image.jpg.png.gif.bmp" style="display: none" />
This will trigger a request for the image, and add it to the local cache. When you set the CSS background-image property, the image will already be in the local cache, eliminating the delay of another request.
Alternatively, you can accomplish the same thing without delaying the page load by creating the images in JavaScript (this solution allows for multiple images):
function preload(list, callback, imageCallback) {
var at, len;
at = len = list.length;
for (var i = 0; i < len; i++ ) {
var img = new Image();
img.onload = function() {
if( imageCallback ) {
imageCallback.call(this, this, len-at, len);
}
if( !--at ) {
callback(list);
}
};
img.src = list[i];
list[i] = img;
}
}
You'd call this with:
var list = preload(["1.png","2.png","3.png" ... ], function complete(list) {
console.log('images all loaded!');
}, function loaded(image, index, listCount) {
console.log('image ' + index + ' of + 'listCount + 'is loaded');
});
(Thanks to #rlemon for the preload code)
I don't think that using an hidden img tag is the correct way, i'd rather use an "new Img(url)" and attaching to it an onload event where you can set the image as background-image to the element you want.
img = new Image();
img.onload = function(){
// set background-image
};
img.src = image_url;
be sure to put img.src after attaching onload, or you risk that the image is loaded before the event is attached.
Maybe a more complete base to build on:
function preload(list, callback, imageCallback, errorCallback) {
if (typeof(list) === "undefined"
|| list.length === 0) {
return;
}
var len = list.length;
var timers = {};
var checkLen0 = function() {
if (len === 0) {
if (typeof(callback) === "function") {
callback();
}
delete(timers)
}
}
var onload = function() {
clearTimeout(timers[img]);
if (typeof(imageCallback) === "function") {
imageCallback.call(img);
}
len--;
checkLen0();
}
var onerror = function() {
clearTimeout(timers[img]);
if (typeof(errorCallback) === "function") {
errorCallback.call(img);
}
len--;
checkLen0();
}
for (var i = 0; i < list.length; i++ ) {
var img = new Image();
img.onload = onload;
timers[img] = window.setTimeout(5000, onerror);
img.src = list[i];
}
}
While SomeKittens answer is valid, it'll delay the page load as commented by Jimmy. If you are using jquery, I'd go with something like this instead to keep your style, structure and logic separated:
<style>
.preload-img { display: none; }
</style>
...
<div class = "preload-img">/path/to/image.jpg.png.gif.bmp</div>
...
<script>
$(document).ready(function(){
$(".preload-img").each(function(){
preloadImage = new Image();
preloadImage.src = $(this).html();
});
});
</script>
Of course, from there on you can optimize/change it. The advantadge of this is that you can create the <div> dynamically with PHP and you can have all your javascript cached properly as a separated file.
There is an excellent framework for this job called Emerge.js
http://ilyabirman.net/projects/emerge/
Quote from project page:
Emerge.js is a framework for coordinated page loading. Normally, when a complex web page is loading, images appear in random order, causing unpleasant flashing. To replace it with nice and coordinated animations, programming is required. Emerge.js simplifies the task by removing the need to write any Javascript code. The framework uses a declarative approach, where you specify a desired behavior for each element and do not think about the implementation. Emerge.js uses jQuery.
Just as a caveat to SomeKittens' answer above, a particularly large background image should probably be added as a hidden background / via JavaScript after page load, as content images delay the firing of window.onload and may therefore create the perception of a slow loading page.
Given that it sounds like you're using dynamic content anyway, this may be an acceptable solution. It also allows you to do preloading programmatically as required, which may be better for maintenance.
I know how to do this in jquery but i am trying to do the below in pure old school javascript. Can someone help:
$(".thumbnail").click(function() {
$("#mainImage").attr("src", $(this).attr("src"));
});
My ultimate goal is to click on a thumbnail and have the main image change but I need to do it in javascript (no jquery). I know this sounds pretty simple but I cannot figure it out. thank you.
There are so many things that jQuery gives you automatically that it's difficult to give you an answer that will do everything that your jQuery code does. Here is a simple example that will find every image with a class of thumbnail and set its onclick property to an event handler that performs an image swap.
onload = function () {
var bigImg = document.getElementById("mainImage");
for (var i = 0; i < document.images.length; i++) {
var img = document.images[i];
if (/\bthumbnail\b/.test(img.className) {
img.onclick = thumbnailHandler;
}
}
function thumbnailHandler(e) {
bigImg.src = this.src;
}
};
If you don't have to support IE7, you can simplify it slightly by using document.querySelectorAll():
onload = function () {
var bigImg = document.getElementById("mainImage");
var thumbs = document.querySelectorAll(".thumbnail");
for (var i = 0; i < thumbs.length; i++) {
thumbs[i].onclick = thumbnailHandler;
}
function thumbnailHandler(e) {
bigImg.src = this.src;
}
};
As an aside, I don't understand why you are setting the source of the main image to be the source of the thumbnail. Are you loading the full image into the thumbnail? That can be a lot to download and can quickly increase the memory footprint of your page.
Event delegation is probably the easiest way:
function expandThumbnail(e) {
if(~(' ' + e.target.className + ' ').indexOf(' thumbnail ')) {
document.getElementById('mainImage').src = e.target.src;
}
}
if(document.addEventListener) {
document.addEventListener('click', expandThumbnail, false);
} else {
document.attachEvent('onclick', function() {
expandThumbnail({
target: event.srcElement
});
});
}
If I understand right, you have a thumbnail image displayed, let's say '1thumb.png', of an associated image, let's say '1.png', and when you click this thumbnail image you want to change the src attribute of a main image, let's say with id='mainimg', to show the '1.png' image associated to the thumbnail instead of whatever it's showing. I tried this and it works:
Inside your <header>:
<script type='text/javascript'>
function myHandler(source){
document.getElementById('mainimg').src=source;
}
</script>
...
Your thumbnail code:
<img src='1thumb.png' onclick="myHandler('1.png')"/>
or, for rollover triggering:
<img src='1thumb.png' onmouseover="myHandler('1.png')"/>
Check it out: http://jsfiddle.net/d7Q27/7/
I'm trying to create a lightbox and I'm having trouble.
I think the problem is either because I have 2 window.onloads or because I'm trying to reference a newly created DOM element. I added some comments in the code below that explain what I'm trying to do.
//open lightbox
window.onload = showLargeImage;
function showLargeImage() {
var enlargeButton = document.getElementById("thumb1"); // thumb1 is a thumbnail you click to get the lightbox
enlargeButton.onclick = handleClick;
}
function handleClick() {
var lightboxContainerId = document.getElementById("lightboxContainer");
lightboxContainerId.innerHTML = '<div class="lightbox"><a class="reduceButton" href="#" ><img id="imageButton" class="largeImage" src="2012/images/web/web1.jpg" width="500" height="500" alt="Web Thumb 1"></a></div>';
} // the inner HTML creates the lightbox.
//close lightbox
window.onload = reduceImage; // i'm pretty sure that this windo.onload is the problem... or, that I'm referencing "imageButton" which is new to the DOM
function reduceImage() {
var reduceButton = document.getElementById("imageButton"); // you're supposed to click the big image in the lightbox to get close it.
reduceButton.onclick = handleReduceClick;
}
function handleReduceClick() {
var shadeId = document.getElementById("lightboxContainer");
shadeId.innerHTML = "say what"; // closing the lightbox simply strips everything out of the lightboxContainer
alert("oh yeah");
}
Here are a few reasons why your code is not working:
showLargeImage and reduceImage are missing invocation parentheses in the places where they are being assigned to window.onload. Without parentheses, window.onload is being assigned a function, but that function is not getting called. You should, for instance, have window.onload = showLargeImage();
As you suspected, the second window.onload is overwriting the first.
reduceButton is (as you also suspected) being assigned before it exists, causing an error.
Here is one solution that may work for you.
HTML:
<!DOCTYPE html>
<html><head><title></title>
</head><body>
View
<div id="lightboxcontainer"></div>
</body></html>
JavaScript:
window.onload = function() {
// click link to show
var enlargeButton = document.getElementById('thumb');
enlargeButton.onclick = function() {
var lightboxContainerId = document.getElementById('lightboxcontainer');
lightboxContainerId.innerHTML = '<img src="http://placehold.it/350x150"' +
'width="350" height="150 alt="Thumb 1">' +
'<p>Click image to hide.</p>';
};
// click image to hide
var reduceButton = document.getElementById('lightboxcontainer');
reduceButton.onclick = function() {
reduceButton.innerHTML = ''; // removes lightbox contents
};
};
Live demo: http://jsfiddle.net/ericmathison/BxwYY/7/
If the code is placed at the end of the <body> (or anywhere after your lightbox elements), just use this:
document.getElementById("thumb1").onclick = function () {
document.getElementById("lightboxContainer").innerHTML = '<div class="lightbox"><a class="reduceButton" href="#" ><img id="imageButton" class="largeImage" src="2012/images/web/web1.jpg" width="500" height="500" alt="Web Thumb 1"></a></div>';
document.getElementById("imageButton").onclick = function () {
document.getElementById("lightboxContainer").innerHTML = "say what";
alert("oh yeah");
};
}
This will do everything you want.
I've written a script to test for SVG support in the IMG tag:
function SVGinIMG() {
var SVGdata = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'
var i = document.createElement('img');
i.setAttribute('src',SVGdata);
return i.complete;
}
window.onload = function() {
var hasSVG = SVGinIMG();
alert(hasSVG);
}
This does what I want, except that when I run the script in WebKit browsers the complete property doesn't trigger the first time I load the page; when I refresh the page, it works as it should. The return function is running before the img has finished loading; what's the best method to delay this?
I was complicating things a little; all I really needed was the load event:
function SVGDetect() {
var testImg = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D';
var img = document.createElement('img')
img.setAttribute('src',testImg);
img.addEventListener('load',setCSS,true);
}
This runs another function when the image loads, which is never in the case of browsers that don't support SVG in images.