preload asynchronously css images and sounds - javascript

All of the assets of the site are in an array of objects that will be shown after user interaction, something like a slider.
{"id":"1","icon":"icon-name-class","sound":"soud-name"},
{"id":"2","icon":"icon-2-name-class","sound":"soud-2-name"},
....
{"id":"100","icon":"icon-100-name-class","sound":"soud-100-name"}
I have about 150 small icons and around 100 small sounds that need to be preloaded, been looking and didn't find anything related to preload assets from a js array.
I'm using the images as a background and getting the class name from the object.
I thought that all images would be ready since they are coming from a css class, but i guess that i am wrong
.icon-class-1 { background-image: url(../img/icons/img-1.png); }
this link or something similar to this could do the trick but after reading the doc couldn't find how to apply it when the assets origin is in an array that will be managed with js.

You have to loop through the object array to load them.
EDIT
Since you have a lot images which doesn't load via CSS.
I suggest you remove all these backgroung-image:url('...'); and put these URLs in your json like this:
{"id":"1","icon":"icon-name-class", "icon_url":"http://domain/path/file.jpg", "sound":"sound-name","sound_url":"http://domain/path/file.mp3"},
And do the same for your sound urls.
PLUS! It will ease the maintenance in the long run... If you notice a broken URL someday.
Then, preloading can be made like this:
var object_array = [
{"id":"1","icon":"icon-name-class", "icon_url":"http://domain/path/file1.jpg", "sound":"sound-name","sound_url":"http://domain/path/file1.mp3"},
{"id":"2","icon":"icon-name-class", "icon_url":"http://domain/path/file2.jpg", "sound":"sound-name","sound_url":"http://domain/path/file2.mp3"},
{"id":"3","icon":"icon-name-class", "icon_url":"http://domain/path/file3.jpg", "sound":"sound-name","sound_url":"http://domain/path/file3.mp3"}
];
// Preloading arrays
var icon_url_arr = [];
var sound_url_arr = [];
// Load counter
var loaded_counter={icon:0,sound:0};
function increment_counter(x){
loaded_counter[x]++;
}
// Loop through the data array
for(i=0;i<object_array.length;i++){
if(typeof(object_array[i].icon_url)!="undefined"){
icon_url_arr[i] = $("<img>").attr("src",object_array[i].icon_url).on("load",function(){increment_counter("icon");});
}
if(typeof(object_array[i].sound_url)!="undefined"){
var audio_element = $("<audio>").attr("id","audio_"+i);
sound_url_arr[i] = $("<source>").attr("src",object_array[i].sound_url).attr("type","audio/mpeg");
audio_element.append(sound_url_arr[i]).on("loadeddata",increment_counter("sound"));
$("#main").append(audio_element);
}
}
// Interval to check load status
var check_all_loaded = setInterval(function(){
console.log("Loded icons: " +loaded_counter.icon+ " Loaded sounds: " +loaded_counter.sound );
$("#icon").html((loaded_counter.icon/icon_url_arr.length)*100+"%");
$("#sound").html((loaded_counter.sound/sound_url_arr.length)*100+"%");
// Stop the interval when all loaded
if( (icon_url_arr.length==loaded_counter.icon) && (sound_url_arr.length==loaded_counter.sound) ){
clearInterval(check_all_loaded);
console.log("Load check Interval stopped.");
// Now you can use the loaded icons and sounds
cycle_data();
}
},10);
// cycle through data on interval
function cycle_data(){
console.log("Display Interval started.");
// Background
var i=0;
setInterval(function(){
$("#main").css("background-image","url("+icon_url_arr[i].attr("src")+")");
// Audio
$(document).find("audio").get(0).pause();
$(document).find("#audio_"+i).get(0).play();
// Increment loop counter.
i++;
// Reset counter when the array end is reached
if(i==icon_url_arr.length){
i=0;
}
},2000);
}
So it won't be displayed or played anywhere...
But the browser will have it loaded.
You may have to hide the audio players via CSS:
audio{
display:none;
}
I made a CodePen demo to make sure it is working.
There is only 3 items in json...
And images and sounds are pretty small.
So you won't really notice the load delay in this demo.
;)
I suggest you place this script in a document.ready() wrapper...
And within a setTimeout() function to execute it something like 0.5 to 2 seconds after document is ready.
So the rest of your page won't lag.

Related

Iterate through multiple web pages in JS with sleep in between

I was checking some simple solutions for showing multiple web pages for some dashboard and currently fighting with simple HTML page with javascript inside to achieve what I want to see there.
var urls = new Array();
urls[0] = "https://stackoverflow.com/"
urls[1] = "https://www.google.com"
var arrayLength = urls.length;
for (var i = 0; i < arrayLength; i++) {
window.location.assign(urls[i]);
sleep(3000);
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds) {
break;
}
}
}
Currently this page opens only first page (after some time) and looks like it doesn't do iteration trough other pages. Maybe you could help me to make it work? I want to rotate those pages forever on screen (will add some infinite while loop after making this part working).
Currently this page opens only first page (after some time) and looks
like it doesn't do iteration trough other pages.
Once you change your window.location, and go to the first url from the array, you are losing all of your JS code (as it is not present in just opened url any more).
You can do this by installing a chrome plugin (which will not lose your JS after window.location change).
The plugin will run the added JS at DOMContentLoaded (no need to attach any event listener).
I needed also to do this, check things on the page, store some information and move on to the next page. I know, this can be done with Python and other stuff but by doing this it can be done on the FE side also.
I used the localStorage to store my information.
I pasted this into the browser console to prepare all the stuff and clean the localStorage:
// clear the localStorage
localStorage.clear();
// set an array that will keep all our pages to iterate into the localStorage
localStorage.setItem(
"pages",
JSON.stringify([
"https://my-page-1.html",
"https://my-page-2.html",
"https://my-page-3.html",
"https://my-page-4.html",
])
);
// set an array that will keep our findings
localStorage.setItem("resultArray", JSON.stringify([]));
// move to the first page of the iteration
window.location.href = "https://my-page-1.html";
After doing this, I opened the plugin interface and added the following code:
(function check() {
// array saved into the localStorage that contains all the pages to iterate
const pagesArray = JSON.parse(localStorage.getItem("pages"));
// array to store your stuff
const resultArray = JSON.parse(localStorage.getItem("resultArray"));
// whatever you want to check on that page
const myFancyCondition = true;
if (myFancyCondition) {
// push any data to the array so that you can check it later
resultArray.push({
page: pagesArray[0],
message: "I found what I was looking for!",
});
}
//remove the current page from the array
pagesArray.shift();
//reset the array value after the first page was already checked
localStorage.setItem("pages", JSON.stringify(pagesArray));
//store the array data
localStorage.setItem("resultArray", JSON.stringify(resultArray));
// quit if the iteration is over and there are no more pages to check
if(!pagesArray.length) return;
//go to the next page
window.location.href = pagesArray[0];
})();
Then, to check the results you just need to read the data from the localStorage like:
JSON.parse(localStorage.getItem('resultArray'))
I hope this helps :)!

how to load images in a javascript variable locally

I had help with this background carousel made with jquery for a website and it works just great.. except that i find that the page can take a while to load initially.. i thought that if i actually downloaded the pictures that i'm using for the background instead of loading them via 'http://www.whatever.jpg', that the page might load faster.. but i'm kind of a noob still.. and haven't been able to figure out why this isn't working.. Here is my code:
var images = [
//even though I downloaded the picture and its in the same folder as this file.js, the background just loads a black page, then the other 2 load fine.
"bg1-orig.jpg",
"http://www.desktopaper.com/wp-content/uploads/Cool-Hd-Wallpapers-2.jpg",
"http://wallpaperscraft.com/image/restaurant_table_interior_modern_style_39288_1920x1080.jpg"
];
var $body = $("body"),
$bg = $("#bg"),
n = images.length,
c = 0; // Loop Counter
num = 200;
// Preload Array of images...
for(var i=0; i<n; i++){
var tImg = new Image();
tImg.src = images[i];
}
$body.css({backgroundImage : "url("+images[c]+")"});
(function loopBg(){
$bg.hide().css({backgroundImage : "url("+images[++c%n]+")"}).delay(7000).fadeTo(2200, 1, function(){
$body.css({backgroundImage : "url("+images[c%n]+")"});
loopBg();
});
}());
i've searched around for a while now... thanks for the help!
You do yourself no favors trying to pre-load the images right before they are loaded for display in your CSS. In either case, the images have to be loaded first before you can see them, so there is going to be a delay regardless.
If the only thing that you want to change is the src attribute of the imgs to be a local folder, then I assume the only change to otherwise working code is the strings in your images array point to local files.
If that's the case, and if you want to resolve the location correctly without adding some sort of directory changes (../, img/ or the like), then you will need those images to be in the same directory as the html file, not the file.js file.

Iterate over cue method with popcorn.js

I am attempting to set multiple cue points in a video. Instead of writing each cue out, I would like to iterate over an object that has the data I need, such as the time of the cue and some info about what to do with the call back.
The problem is when I try to iterate over the object it overwrites all the cues except for the last one.
var products = myVideo.products;
var video = Popcorn('#mainVideo');
for (product in products){
var obj = products[product],
start = obj.start,
img = obj.image,
$targetDiv = $("#"+obj.targetDiv);
video.cue( start, function(){
$('<img>', {
class : "isImage",
src : 'images/' + img
}).prependTo( $targetDiv );
})
}
Any help would be greatly appreciated.
In this code, every cue has its own callback function, but every function refers to the same variable img and the same $targetDiv. By the time they run, those variables will be set to their respective values for the last item in products.
If you've ever run code through jslint and seen the warning, don't make functions in a loop, this is why. A good way to do what you're trying to do is to put those variables inside of a function that gets called immediately and returns another function, which is your callback. Like this:
function makeCallback(obj) {
return function() {
$('<img>', {
class : "isImage",
src : 'images/' + obj.img
}).prependTo( $("#"+obj.targetDiv) );
};
}
for (var product in products) {
var obj = products[product];
video.cue( obj.start, makeCallback( obj ) );
}
Alternatively, you can use forEach, which does the same thing under the hood. (Popcorn provides its own version, which handles both arrays and objects.)
Popcorn.forEach(products, function(obj) {
video.cue( start, function(){
$('<img>', {
class : "isImage",
src : 'images/' + obj.img
}).prependTo( $("#"+obj.targetDiv) );
});
});
I should note that you have another problem in this code, which is that you have Popcorn creating a new image every time you pass through the cue point. So, if the user ever skips back to replay some of the video, the images will start to pile up. Also, the images don't start loading until right when they become visible, so if there's a slow-ish network connection, the images may not show up until it's too late.
The best way to handle these is usually to create your images ahead of time but make them invisible with CSS, and then have the Popcorn events make them visible at the right time. You might consider using the image plugin, which will do most of your heavy lifting for you.

pdf 3d with JavaScript : simple example

I need to do a simple pdf with some 3D objects for an oral presentation. I made several views, each one with a camera viewpoint, an object and a display mode.
To avoid the need to manually switch between the different viewpoints with the context menu, I would like the viewpoints to switch automatically with a Timer (each viewpoint staying for a few seconds). And I would like to not have to touch the mouse at all (nor the keyboard), so I would like to have the playback started as soon as the page appears.
I found the javascript command runtime.setView(N,x) to switch to the x'th view among N, but I don't know where to put it (I don't want to define a function which will be called when I press a button, since I want everything to be automated). Also, I don't know how to pause for a few seconds.
Any help ? Thanks !
I believe you're looking for setInterval(fn, time) which will call a function periodically at a time interval that you set. I'm not familiar with the setView() method you mentioned, but here's some pseudo code that you would put in tags at the end of the document body.
function startSwitcher()
var viewNum = 0;
var maxViews = 5; // you set this to how many views there are
setInterval(function() {
++viewNum;
if (viewNum >= maxViews) {
viewNum = 0;
}
runtime.setView(N, viewNum); // you will have to figure out this line
}, 2000);
}
startSwitcher();
The 2000 is 2000 milliseconds and is the time interval between executing the function. You can put any number of milliseconds there.
The runtime.setView(N, viewNum) line is something you will have to figure out as I am not familiar with whatever library you're trying to use there. The operative part of this code is the viewNum variable which configures which view in rotation should be next.
I think the runtime.SetView(..) Methods works with the name of the view as a string instead of the viewnumber. I have this function in a Dokument-level script and it works for me:
// view is the name of the view for example "TopView"
function setView(view){
console.println("Navigating to view: "+view);
var pageIndex = this.pageNum;
var annotIndex = 0;
var c3d = this.getAnnots3D( pageIndex )[ annotIndex ].context3D;
c3d.runtime.setView(view, true);
}
Combine this with the setInterval(..) from jfriend00´s answer und you should get what you need.
Best regards

Rotating images, AJAX-like, in Ruby on Rails

I'm working on a site where I'd like to cycle images, similar to a slideshow, while the user is on the page. I've searched around and haven't been able to find a lead.
Has anyone done this with Rails and the Javascript frameworks it supports?
you could possible use the jquery cycle plugin, here's the link: http://malsup.com/jquery/cycle/ . It looks like it would do what you want.
FYI, Rails isn't particularly tied to any JS framework, even though it comes with prototype out of the box.
I assume that when you say AJAX, you don't mean AJAX. If you were to rotate the image using AJAX, you would have the rotated image being generated server side and sent to the client, as AJAX = performing requests with javascript. </pedantic>
With that said, you can use pretty much any JS image rotator you can find on google.
EDIT: Oh, you meant cycling through images, not rotating it e.g. 90º clockwise etc. (?)
I've been using this very simple function. It doesn't use any framework and it doesn't fade between slides, but it should get you started.
function SlideShow( elem_id, hold_time )
{
this.elem = document.getElementById( elem_id );
this.slides = [];
this.num_slides = 0;
this.cur_slide = 1;
this.add_slide = function( image )
{
this.slides[ this.num_slides++ ] = image;
}
var self = this;
this.next_slide = function()
{
if ( self.num_slides > 1 )
{
self.elem.src = self.slides[ self.cur_slide++ ].src;
if ( self.cur_slide == self.num_slides )
self.cur_slide = 0;
}
}
setInterval( self.next_slide, hold_time )
}
the parameters are the element_id of an img tag and the number of mS to display each slide.
the add_slide function takes a JavaScript Image object.
The reason cur_slide is initialised to 1 is because I pre load the img tag with the first image.
In my application I create the slideshow in the window.onload method and arrange for each Image to add itself to the slide show as it is loaded.
Example (untested):
window.onload = function() {
var slide_show = new SlideShow( "slide_image", 4000 )
{ var img = new Image();
img.onload = function(){ slide_show.add_slide(img); };
img.src="/images/slide1.jpg"; }
...
/* Repeated for each image */
}
This approach is only valid if you don't care about the order of the slides.
I assume you want to make persistent changes on images. I'm working on a Rails app where we implemented resize, crop and rotate similar to features in snipshot.com
On technical side we used YUI for resize and crop in user interface and RMagick on server to process the images and send the results back to UI. YUI provides imagecrop widget out-of-the box.
We also considered doing a series of actions in UI and then submit the last result for server-side processing but that would have been lead to inadequate results.

Categories