This is my first time attempting Lazy Loading, and I wanted to use IntersectionObserver. Got started by following along with this website. I honestly just want the content of the page to wait to load until it is less than 50% of the viewport's width below the viewport. I'm not sure how to observe all content, so I just selected the classes for the widgets that are being displayed, as they are the main content. Unfortunately my code doesn't seem to be doing much. I added a console.log at the beginning to make sure the file was linked correctly, and I tried to add more console.logs to log when the widget moves in and out of the capture area. The first console.log works, but nothing else happens.
Here is what I have:
console.log('file loaded');
const widgets = document.querySelectorAll('.widget');
const config = {
root: null,
rootMargin: '-50px 0px -55% 0px',
threshold: .5
};
let isLeaving = false;
let observer = new IntersectionObserver(function(entries, self) {
entries.forEach(entry => {
if (entry.isIntersecting) {
// we are ENTERING the "capturing frame". Set the flag.
isLeaving = true;
// Do something with entering entry
console.log("Widget loaded.");
self.unobserve(entry.target);
} else if (isLeaving) {
// we are EXITING the "capturing frame"
isLeaving = false;
// Do something with exiting entry
console.log("Widget is exiting.")
}
});
}, config);
widgets.forEach(widget => {
observer.observe(widget);
});
This code is in it's own js file. Where should I be linking it in the HTML file?
I'd appreciate any help I can get! Let me know if I need to provide more information.
Related
I'm trying to modify Google's Picture in Picture Extension so I can resize the pip window without maintaining the fixed aspect ratio (stretch the sides individually). However, I'm not very familiar with Javascript.
Looking at the code, I expect the changes to be situated in these functions
async function requestPictureInPicture(video) {
await video.requestPictureInPicture();
video.setAttribute('__pip__', true);
video.addEventListener('leavepictureinpicture', event => {
video.removeAttribute('__pip__');
}, { once: true });
new ResizeObserver(maybeUpdatePictureInPictureVideo).observe(video);
}
function maybeUpdatePictureInPictureVideo(entries, observer) {
const observedVideo = entries[0].target;
if (!document.querySelector('[__pip__]')) {
observer.unobserve(observedVideo);
return;
}
const video = findLargestPlayingVideo();
if (video && !video.hasAttribute('__pip__')) {
observer.unobserve(observedVideo);
requestPictureInPicture(video);
}
}
Perhaps by tweaking the ResizeObserver?
the entirety of the source code can be found here. Is there a way to do this?
So basically I have a page with a few sections. Each sections contains 5-30 image icons that are fairly small in size but large enough that I want to manipulate the load order of them.
I'm using a library called collagePlus which allows me to give it a list of elements which it will collage into a nice image grid. The idea here is to start at the first section of images, load the images, display the grid, then move on to the next section of images all the way to the end. Once we reach the end I pass a callback which initializes a gallery library I am using called fancybox which simply makes all the images interactive when clicked(but does not modify the icons state/styles).
var fancyCollage = new function() { /* A mixed usage of fancybox.js and collagePlus.js */
var collageOpts = {
'targetHeight': 200,
'fadeSpeed': 2000,
'allowPartialLastRow': true
};
// This is just for the case that the browser window is resized
var resizeTimer = null;
$(window).bind('resize', function() {
resetCollage(); // resize all collages
});
// Here we apply the actual CollagePlus plugin
var collage = function(elems) {
if (!elems)
elems = $('.Collage');
elems.removeWhitespace().collagePlus(collageOpts);
};
var resetCollage = function(elems) {
// hide all the images until we resize them
$('.Collage .Image_Wrapper').css("opacity", 0);
// set a timer to re-apply the plugin
if (resizeTimer) clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
collage(elems);
}, 200);
};
var setFancyBox = function() {
$(".covers").fancybox({/*options*/});
};
this.init = function(opts) {
if (opts != null) {
if (opts.height) {
collageOpts.targetHeight = opts.height;
}
}
$(document).ready(function() {
// some recursive functional funk
// basically goes through each section then each image in each section and loads the image and recurses onto the next image or section
function loadImage(images, imgIndex, sections, sectIndex, callback) {
if (sectIndex == sections.length) {
return callback();
}
if (imgIndex == images.length) {
var c = sections.eq(sectIndex);
collage(c);
images = sections.eq(sectIndex + 1).find("img.preload");
return loadImage(images, 0, sections, sectIndex + 1, callback);
}
var src = images.eq(imgIndex).data("src");
var img = new Image();
img.onload = img.onerror = function() {
images[imgIndex].src = src; // once the image is loaded set the UI element's source
loadImage(images, imgIndex + 1, sections, sectIndex, callback)
};
img.src = src; // load the image in the background
}
var firstImgList = $(".Collage").eq(0).find("img.preload");
loadImage(firstImgList, 0, $(".Collage"), 0, setFancyBox);
});
}
}
From my galleries I then call the init function.
It seems like my recursive chain being triggered by img.onload or img.onerror is not working properly if the images take a while to load(on slow networks or mobile). I'm not sure what I'm missing here so if anyone can chip in that would be great!
If it isn't clear what is going wrong from the code I posted you can see a live example here: https://www.yuvalboss.com/albums/olympic-traverse-august-2017
It works quite well on my desktop, but on my Nexus 5x it does not work and seems like the finally few collage calls are not happening. I've spent too long on this now so opening this up to see if I can get some help. Thanks everyone!
Whooooo I figured it out!
Was getting this issue which I'm still unsure about what it means
[Violation] Forced reflow while executing JavaScript took 43ms
Moved this into the callback that happens only once all images are loaded
$(window).bind('resize', function() {
resetCollage(); // resize all collages
});
For some reason it was getting called early even if the browser never resized causing collage to get called when no elements existed yet.
If anyone has any informative input as to why I was getting this js violation would be great to know so I can make a better fix but for now this works :):):)
I am using QRTEngine in qualtrics. I have a problem with hiding the Init and the Exit part, here is what I have tried to do so far:
Init:
QRTE.Init({
// should correspond with Embedded Data field names
blockData: ‘${e://Field/QRTE_blockData}’,
idData: ‘${e://Field/QRTE_idData}’,
columnData: ‘${e://Field/QRTE_columns}’,
exitQuestions: ‘${e://Field/QRTE_exitQuestions}’,
exitItemTag: ‘ExitQ’, // DO NOT FORGET TO CHANGE FOR NEW BLOCKS
blockId: ‘Deafult Question Block’, // DO NOT FORGET TO CHANGE FOR NEW BLOCKS
onLoadFn: function() {
// set trial configuration for the screens
QRTE.setConfig(‘Smiley’, ‘duration’, 2000);
QRTE.setConfig(‘StroopItem’, ‘duration’, 6000);
QRTE.setConfig(‘StroopItem’, ‘allowable’, ‘xm’);
QRTE.setConfig(‘StroopItem’, ‘EndAction’, ‘TERMINATE’);
// save trial configurations for later analysis
QRTE.setTrialData(‘StimulusSimely’, ‘${lm://Field/1}’);
QRTE.setTrialData(‘Piconright’, ‘${lm://Field/2}’);
QRTE.setTrialData(‘Piconleft’, ‘${lm://Field/3}’);
this.questionContainer.style.display = ‘none';
},
interTrialDelay: [1000] // set interTrialDelay
});
onLoadFn: (function()
{
this.questionContainer.style.display = ‘none';
});
Exit:
QRTE.Exit();
Qualtrics.SurveyEngine.addOnload(function()
{
this.questionContainer.style.display = ‘none';
});
My goal would be to prevent the engine from displaying these questions.
I have tried to set the intertrialdelay to 0, but in that case the whole experiment became a mess.
I am new to Famo.us, can anybody explain me what does rootmodifers do in famo.us, here is its example
function SlideshowView () {
Views.apply(this, arguments);
this.rootModifier = new StateModifier({
size:this.options.size
});
this.mainNode = this.add(this.rootModifier);
_createLightBox.call(this);
_createSlides.call(this);
}
this.rootMidifier just allows you to have a way to control the entire slideShow's position, opacity, origin, or alignment later in the applications. More importantly this.rootModifier is added to the render node like this this.mainNode = this.add(this.rootModifier); This code places the modifier at the top of the render tree for the slideshow branch and exposes access to the modifier for later use in the all. For example later in the app you could have a function that changes the opacity.
SlideShow.prototype.hide = function() {
this.rootModifier.setOpacity(0, {duration: 3000});
}
I've been looking around a lot of JavaScript answers but I haven't found one that really answers my problem yet. What I'm trying to do is load an image, grab the pixel data, perform an analysis, and then load another image to repeat the process.
My problem is that I can't preload all of the images because this script has to be able to work on large amounts of images and preloading could be too resource heavy. So I'm stuck trying to load a new image each time through a loop, but I'm stuck with a race condition between the image loading and the script drawing it to the canvas's context. At least I'm pretty sure that's what is happening because the script will work fine with the images precached (for example if I refresh after loading the page previously).
As you'll see there are several lines of code commented out because I'm incredibly new to JavaScript and they weren't working the way I thought they would, but I didn't want to forget about them if I needed the functionality later.
This is the snippet of code that I believe is giving rise to the problem:
EDIT: So I got my function to work after following a suggestion
function myFunction(imageURLarray) {
var canvas = document.getElementById('imagecanvas');
console.log("Canvas Grabbed");
if (!canvas || !canvas.getContext) {
return;
}
var context = canvas.getContext('2d');
if (!context || !context.putImageData) {
return;
}
window.loadedImageCount = 0;
loadImages(context, canvas.width, canvas.height, imageURLarray, 0);
}
function loadImages(context, width, height, imageURLarray, currentIndex) {
if (imageURLarray.length == 0 || imageURLarray.length == currentIndex) {
return false;
}
if (typeof currentIndex == 'undefined') {
currentIndex = 0;
}
var currentimage = new Image();
currentimage.src = imageURLarray[currentIndex];
var tempindex = currentIndex;
currentimage.onload = function(e) {
// Function code here
window.loadedImageCount++;
if (loadedImageCount == imageURLarray.length) {
// Function that happens after all images are loaded here
}
}
currentIndex++;
loadImages(context, width, height, imageURLarray, currentIndex);
return;
}
Maybe this will help:
currentimage.onload = function(e){
// code, run after image load
}
If it is necessary to wait for the image to load, the following code will load the next image (currentIndex is your "img" variable):
var loadImages = function(imageURLarray, currentIndex){
if (imageURLarray.length == 0 || imageURLarray.length == currentIndex) return false;
if (typeof currentIndex == 'undefined'){
currentIndex = 0;
}
// your top code
currentimage.onload = function(e){
// code, run after image load
loadImages(imageURLArray, currentIndex++);
}
}
Instead of a "for" loop, use for example this function:
loadImages(imageURLarray);
Maybe try this:
http://jsfiddle.net/jnt9f/
Setting onload handler before setting img src will make sure the onload event be fired even the image is cached
var $imgs = $(),i=0;
for (var img = 0; img < imageURLarray.length; img++) {
$imgs = $imgs.add('<img/>');
}
var fctn = (function fctn(i){
$imgs.eq(i).on('load',function(){
//do some stuff
//...
fctn(++i);
}).attr('src',imageURLarray[i]);
})(0);
Actually...a lot of developers are pointing here to detect when images are done loading after a jQuery event..
https://github.com/desandro/imagesloaded
If you can determine when the event triggers your images to load (for example, adding an Id or class onto the page right before your images begin to load), then you should be able to blend that in with this plug-in on github.
Good Luck!