Frankenstein image swap JavaScript needs tidy and possible automation - javascript

I'm using the following JavaScript. It works fine, but it's a mess pieced together from various sources.
I have a series of images.
Each has a small version (1.gif) and a hidden, preloaded, large version (_1.gif).
Click the small version and the large version replaces it.
Click again and it swaps back:
var lastMove;
lastMove = new Date();
function preload(arr) {for (var i=0; i<arr.length; i++) (new Image()).src = arr[i];}
var index = 0;
var picsA = ["1.gif", "_1.gif"];
preload(picsA); picNumberA = 0;
function showNextPicA() {if (new Date() - lastMove < 200) return false; if (picNumberA == (picsA.length -1)) {picNumberA = 0;} else {picNumberA = picNumberA + 1;}document.getElementById('placeholderA').src = pics1[picNumberA];}
var picsB = ["2.gif", "_2.gif"];
preload(picsB); picNumberB = 0;
function showNextPicB() {if (new Date() - lastMove < 200) return false; if (picNumberB == (picsB.length -1)) {picNumberB = 0;} else {picNumberB = picNumberB + 1;}document.getElementById('placeholderB').src = picsB[picNumberB];}
etc. with each image on the page like this:
<img src="1.gif" id="placeholderA" onclick="return showNextPicA();"/>
So, first: is this mess dangerous or unecessary or is it fine?
And second: is there a way to automate so any image file will swap to a version with a standard prefix (say _) when clicked, then back again when clicked again?
Phew. Thanks for reading!

If you are able to use sth like jQuery, in the onClick for each image, put
showNextPic($(this))
Then
var prefix = "_";
showNextPic(imgelement) {
var src = imgelement.attr('src');
if(src.indexOf(prefix) == -1) {
src = prefix + src;
}
else {
// remove prefix from src
}
imgelement.attr('src', src);
}

Related

Supply more than one alternatives image source for img html tag?

I have two alternative images and one image as default in case the first two images are not found.
<img
src='image1.png'
onError="this.onerror=null;this.src='image2.png';"
onError="this.onerror=null;this.src='default.png';" />
Then I tested on three <img /> I found image1.png and image2.png works correctly but in case there are not image1.png and image2.png, the default image default.png does not display.
Any tips on how can I use more than one alternative images like my case above?
You may want to use addEventListener instead, keeping track of your position in an array of possible images.
<img src='image1.png'/>
<script>
function addFallbackSources(img, sources){
let idx = 0;
img.addEventListener("error", e=>{
if(idx >= sources.length) throw new Error("No images left to try");
img.src = sources[idx++];
});
}
addFallbackSources(document.querySelector('img'), ["image2.png", "default.png"]);
</script>
Something Like follows may work.
function setNextAvailableImage(element, image_list) {
const current_img = element.src
let next_img = 'default.png'
let found_index = -1
for (let i = 0; i < image_list.length; i ++) {
if (current_img.indexOf(image_list[i]) != -1) {
found_index = i
break
}
}
if (found_index == -1 && image_list.length > 0) {
element.src = image_list[0]
}
else if (found_index + 1 < image_list.length) {
next_img = image_list[found_index + 1]
element.src = next_img
} else {
element.src = next_img
}
}
<img src='image1.png' onError="setNextAvailableImage(this, ['image2.png', 'image3.png'])"/>
You could add a data-alt-src attribute that holds the values of the alternates, then have the onerror attribute call the loadAltImage function that simply loads the next alternate image index. This will essentially call itself recursively.
<img src="image1.png" data-alt-src="image2.png,default.png" onerror="loadAltImage(this)" />
function loadAltImage(element) {
const alternatives = element.dataset.altSrc.split(',');
const nextLoadIndex = parseInt(element.dataset.loadIndex || 0);
if(nextLoadIndex < alternatives.length) {
element.src = alternatives[nextLoadIndex].trim();
element.dataset.loadIndex = nextLoadIndex + 1;
}
}

File Size Validation on multiple upload with jquery

I have a multiple file upload input. I'm trying to validate the size for each file. It works kind of but depends on which order the files are selected. I hate javascript & I suck at it, please help.
http://jsfiddle.net/2u9kq7fe/1/
$('input[type="file"]').change(function(){
var imageSizeArr = 0;
var imageSize = document.getElementById('blah');
var imageCount = imageSize.files.length;
for (var i = 0; i < imageSize.files.length; i++)
{
var imageSize = imageSize.files[i].size;
if (imageSize > 5000000) {
$('#test').text('3');
var imageSizeArr = 1;
}
if (imageSizeArr == 1)
{
$('.element').text('files too big');
}
else if (imageSizeArr == 0)
{
$('.element').text('files not too big');
}
}
});
You are defining a reference to input field:
var imageSize = document.getElementById('blah');
and later in the for loop you redefine it again, because:
for (var i = 0; i < imageSize.files.length; i++) {
var imageSize = imageSize.files[i].size;
Remember that there is no block-scope in javascript, so var imageSize in the loop affects previously defined value.
This is your problem. Pick different name for size in the loop and it will work.
try like below example;
<input type="file" id="fileUpload" />
<input type="button" id="upload" value="Upload" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
$("#upload").bind("click", function () {
if (typeof ($("#fileUpload")[0].files) != "undefined") {
var size = parseFloat($("#fileUpload")[0].files[0].size / 1024).toFixed(2);
alert(size + " KB.");
} else {
alert("This browser does not support HTML5.");
}
});
});
</script>
All credits go to #dfsq but as a js beginner it took me some time to figure out the vague description of what he meant with "Pick different name for size" so for all the confused ones here is the working code:
html:
<input type=file name=img[] id=files accept=".jpg, .JPG, .jpeg, .JPEG" multiple=multiple>
js:
$('input#files').change(function(){
var imageSizeArr = 0;
var imageArr = document.getElementById('files');
var imageCount = imageArr.files.length;
var imageToBig = false;
for (var i = 0; i < imageArr.files.length; i++){
var imageSize = imageArr.files[i].size;
var imageName = imageArr.files[i].name;
if (imageSize > 5000000){
var imageSizeArr = 1;
}
if (imageSizeArr == 1){
console.log(imageName+': file too big\n');
imageToBig = true;
}
else if (imageSizeArr == 0){
console.log(imageName+': file ok\n');
}
}
if(imageToBig){
//give an alert that at least one image is to big
window.alert("At least one of your images is too large to process, see the console for exact file details.");
}
});

Javascript decrement -- not working in my script

var backgroundImages = new Array(); // create an array holding the links of each image
backgroundImages[0] = "style/images/bg0.png";
backgroundImages[1] = "style/images/bg1.png";
backgroundImages[2] = "style/images/bg2.png";
backgroundImages[3] = "style/images/bg3.png";
backgroundImages[4] = "style/images/bg4.png";
backgroundImages[5] = "style/images/bg5.png";
backgroundImages[6] = "style/images/bg6.png";
var ImageCnt = 0;
function nextImage(direction) // this should take into account the current value (starts at 3) and determines whether a higher or lower value should be returned based on the direction
{
if(direction == "left")
{
ImageCnt-- ;
}
if(direction == "right")
{
ImageCnt++ ;
}
document.getElementById("body-1").style.background = 'url(' + backgroundImages[ImageCnt] + ')'; //put's the new background together for rendering by using the returned value from nextImage()
if(ImageCnt == 6)
{
ImageCnt = -1;
}
}
In this script, ImageCnt ++ is working fine, on the function "nextImage('right')" but on nextImage('left') which triggers ImageCnt-- , the function breaks. What am I doing wrong? (Newbie with js)
Well, your "wrap" code says to make it -1, but what if I then go left? It will try to access -2, which doesn't exist.
Try this instead:
ImageCnt = (ImageCnt + (direction == "left" ? backgroundImages.length-1 : 1)) % backgroundImages.length;
document.getElementById("body-1").style.background = "url('"+backgroundImages[ImageCnt]+"')";
Note also that it is very inefficient to build an array piece by piece like that. Try this:
var backgroundImages = [
"style/images/bg0.png",
"style/images/bg1.png",
"style/images/bg2.png",
"style/images/bg3.png",
"style/images/bg4.png",
"style/images/bg5.png",
"style/images/bg6.png",
];

With only one button to scroll through images, how do I make a permutation?

I am writing this in JavaScript, and the issue is that I can't seem to figure out how to make a permutation. Ideally, I want to click the button and image would change to next, from a1.jpg to a2.jpg to a3.jpg to a4.jpg to a1.jpg and so on... But when I wrote this code, it would skip a2 and a3. I also did rearrange the conditionals since I realized that it reads from the top to bottom, but it would always skip one of the four pictures.
function changeImage() {
if (document.images) {
if (document["buttonOne"].src == a3.src){
document["buttonOne"].src = a4.src}
}
if (document.images) {
if (document["buttonOne"].src == a2.src){
document["buttonOne"].src = a3.src
}
if (document.images) {
if (document["buttonOne"].src == a1.src){
document["buttonOne"].src = a2.src}
}
if (document.images) {
if (document["buttonOne"].src == a4.src){
document["buttonOne"].src = a1.src}
}
}
Try it in a more simple way
var imgs = ['a1.jpg', 'a2.jpg', 'a3.jpg', 'a4.jpg'];
function changeImage() {
var img = document["buttonOne"];
if (!img._index) img._index = 0;
img.src = imgs[img._index++];
if (img._index >= imgs.length) img._index = 0;
}
img._index replaces the global variable with index of the shown image. Good to use when you want to change a few images, each of them will keep its own counter.
ps: if the only thing that changes is the number in the filename then the code can be even shorter without an array:
function changeImage(max) {
var img = document["buttonOne"];
if (!img._index) img._index = 0;
img.src = 'a' + img._index + '.jpg';
if (img._index >= max) img._index = 0;
}

Trouble with onclick attribute for img when used in combination with setInterval

I am trying to make images that move around the screen that do something when they are clicked. I am using setInterval to call a function to move the images. Each image has the onclick attribute set. The problem is that the clicks are not registering.
If I take out the setInterval and just keep the images still, then the clicks do register.
My code is here (html, css, JavaScript): https://jsfiddle.net/contini/nLc404x7/4/
The JavaScript is copied here:
var smiley_screen_params = {
smiley_size : 100, // needs to agree with width/height from css file
num_smilies: 20
}
var smiley = {
top_position : 0,
left_position : 0,
jump_speed : 2,
h_direction : 1,
v_direction : 1,
intvl_speed : 10, // advance smiley every x milliseconds
id : "smiley"
}
function randomise_direction(s) {
var hd = parseInt(Math.random()*2);
var vd = parseInt(Math.random()*2);
if (hd === 0)
s.h_direction = -1;
if (vd === 0)
s.v_direction = -1;
}
function plotSmiley(sp /* sp = smiley params */) {
var existing_smiley = document.getElementById(sp.id);
if (existing_smiley !== null)
// delete existing smiley so we can move it
document.getElementById("smileybox").removeChild(existing_smiley);
var smiley_to_plot = document.createElement('img');
smiley_to_plot.setAttribute('src', "http://i.imgur.com/C0BiXJx.png");
smiley_to_plot.setAttribute('id', sp.id);
smiley_to_plot.setAttribute('onclick', "my_click_count()");
smiley_to_plot.style.position = 'absolute';
smiley_to_plot.style.top = sp.top_position + "px";
smiley_to_plot.style.left = sp.left_position + "px";
document.getElementById("smileybox").appendChild(smiley_to_plot);
}
function random_direction_change() {
var r = parseInt(Math.random()*200);
if (r===0)
return true;
else
return false;
}
function moveFace(sp_array /* sp_array = smiley params array */) {
var i;
var sp;
for (i=0; i < sp_array.length; ++i) {
// move ith element
sp = sp_array[i];
if (
(sp.h_direction > 0 && sp.left_position >= smiley_screen_params.width - smiley_screen_params.smiley_size) ||
(sp.h_direction < 0 && sp.left_position <= 0) ||
(random_direction_change())
) {
sp.h_direction = -sp.h_direction; // hit left/right, bounce off (or random direction change)
}
if (
(sp.v_direction > 0 && sp.top_position >= smiley_screen_params.height - smiley_screen_params.smiley_size) ||
(sp.v_direction < 0 && sp.top_position <= 0) ||
(random_direction_change())
) {
sp.v_direction = -sp.v_direction; // hit top/bottom, bounce off (or random direction change)
}
sp.top_position += sp.v_direction * sp.jump_speed;
sp.left_position += sp.h_direction * sp.jump_speed;
plotSmiley(sp);
}
}
if (typeof Object.create !== 'function') {
Object.create = function(o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
function generateFaces() {
var smilies = new Array();
var s;
var i;
var css_smileybox=document.getElementById("smileybox");
var sb_style = getComputedStyle(css_smileybox, null);
// add info to the screen params
smiley_screen_params.width = parseInt(sb_style.width);
smiley_screen_params.height = parseInt(sb_style.height);
// create the smileys
for (i=0; i < smiley_screen_params.num_smilies; ++i) {
s = Object.create(smiley);
s.id = "smiley" + i;
s.top_position = parseInt(Math.random() * (smiley_screen_params.height - smiley_screen_params.smiley_size)),
s.left_position = parseInt(Math.random() * (smiley_screen_params.width - smiley_screen_params.smiley_size)),
randomise_direction(s);
smilies.push(s);
}
setInterval( function(){ moveFace(smilies) }, smiley.intvl_speed );
}
var click_count=0;
function my_click_count() {
++click_count;
document.getElementById("mg").innerHTML = "Number of clicks: " + click_count;
}
generateFaces();
The generateFaces() will generate parameters (for example, coordinates of where they are placed) for a bunch of smiley face images. The setInterval is within this function, and calls the moveFace function to make the smiley faces move at a fixed interval of time. moveFace computes the new coordinates of each smiley face image and then calls plotSmiley to plot each one on the screen in its new location (removing it from the old location). The plotSmiley sets the onclick attribute of each image to call a dummy function just to see if the clicks are registering.
Thanks in advance.
This is not a complete answer but it could give you some perspective to improve your code.
First of all, your idea of deleting the existing img so wrong. If it does exist, all you need is to just change its position so instead of this
if (existing_smiley !== null)
// delete existing smiley so we can move it
document.getElementById("smileybox").removeChild(existing_smiley);
you should do something like this:
if (existing_smiley !== null)
var smiley_to_plot = existing_smiley;
else {
var smiley_to_plot = document.createElement('img');
smiley_to_plot.setAttribute('src', "http://i.imgur.com/C0BiXJx.png");
smiley_to_plot.setAttribute('id', sp.id);
smiley_to_plot.style.position = 'absolute';
document.getElementById("smileybox").appendChild(smiley_to_plot);
smiley_to_plot.addEventListener('click', my_click_count);
}
smiley_to_plot.style.top = sp.top_position + "px";
smiley_to_plot.style.left = sp.left_position + "px";
As you can see new image is only being added if it's not already there. Also notice that adding events by using .setAttribute('onclick', "my_click_count()"); is not a good way to do. You should use .addEventListener('click', my_click_count); like I did.
Like I said this is not a complete answer but at least this way they response to the click events now.
FIDDLE UPDATE
Good luck!

Categories