Jump to content

Oliver's Responsive Images Plugin: Some Questions


bytesource
 Share

Recommended Posts

Hi,

I am currently evaluating the Responsive Images plugin that dynamically provides adaptive images and that was introduced in this forum by Oliver, its creator, some time ago.

I will probably have some more questions while exploring the features, but for now I just wanted to ask if it was OK to place the javascript portion of the plugin at the end of the body tag instead of in the head section as mentioned on Github.

On the site bildbau.net that uses the plugin, the javascript is located at the end.

I, too, prefer placing my javascript in one minified file at the end of a page, but I am not sure if then all images would load as usual before the plugin could do its work.

Cheers,

Stefan

Link to comment
Share on other sites

I have been trying to make the Responsive Images (RI) plugin work with the Magnific Popup (MP) image gallery.

The basic markup of MP is as follows:

echo "<a href='{$image->url}'><img src='{$thumb->url}' /></a>";

The url of the thumbnail is modified by RI as usual, but the url to the larger image is not detected, as it is not the value of an image's src attribute.

The idea is to call the MP's  elementParse function, then call RI on the url to the large image, and replace the current value of the href attribute with the new modified url.

In the documentation, elementParse is described as follows.

If you want to modify how the source is parsed, you may hook into the elementParse callback. For example:

$('.image-link').magnificPopup({  type:'image',  callbacks: {    elementParse: function(item) {      // Function will fire for each target element      // "item.el" is a target DOM element (if present)      // "item.src" is a source that you may modify      console.log(item); // Do whatever you want with "item" object    }  }});
The following code does not work. It returns 'undefined' for container and a 404 error for the url:

This is the code I have come up with (elementParse is the important part):

$('.product-gallery').magnificPopup({
    delegate: 'a', // child items selector, by clicking on it popup will open
      type: 'image',

    gallery: {
        enabled: true, // set to true to enable gallery

        preload: [1,2], // read about this option in next Lazy-loading section

        navigateByImgClick: true,

        arrowMarkup: '<button title="%title%" type="button" class="mfp-arrow mfp-arrow-%dir%"></button>', // markup of an arrow button

        tPrev: 'Previous (Left arrow key)', // title for left button
        tNext: 'Next (Right arrow key)', // title for right button
        // tCounter: '<span class="mfp-counter">%curr% of %total%</span>' // markup of counter
      },

    callbacks: {
        elementParse: function(item) {

            var container = $(item).parent();

            // test element
            alert(container.attr('name'));

            item.src = container.responsiveImages('getURL', item.src, { swidth: screen.width, pwidth: screen.width, pxratio: window.devicePixelRatio || 1 });

        }
    }

});

Unfortunately, I have almost no JQuery skills, and cannot even say for sure if the above code is syntactically correct.

Therefore, I would be very grateful if someone could take a quick look at the code and point me to the most obvious errors.

Cheers,

Stefan

Link to comment
Share on other sites

I inspected the item object that is passed to elementParse when clicking on a thumbnail, and this is the result:

 container: undefined

  1. item: Object
    1. el: x.fn.x.init[1]
    2. index: 0
    3. parsed: true
    4. src: "/sovonex/site/assets/files/1037/top_drive_services_in_nigeria_2_186.jpg"
    5. type: "image"
    6. __proto__: Object
  2. this: MagnificPopup
    1. bgOverlay: x.fn.x.init[1]
    2. container: x.fn.x.init[1]
    3. contentContainer: x.fn.x.init[1]
    4. currTemplate: Object
    5. direction: true
    6. ev: x.fn.x.init[1]
    7. fixedContentPos: true
    8. index: 0
    9. isAndroid: false
    10. isIE7: false
    11. isIE8: false
    12. isIOS: false
    13. isLowIE: false
    14. items: Array[6]
    15. popupsCache: Object
    16. preloader: x.fn.x.init[1]
    17. probablyMobile: false
    18. scrollbarSize: 15
    19. st: Object
    20. supportsTransition: true
    21. types: Array[4]
    22. wH: 146
    23. wrap: x.fn.x.init[1]
    24. __proto__: Object

 

 

So I guess there is not much I could do with this object. Makes me wonder were to bind the responsiveImages function to.

 

Cheers,

 

Stefan

Link to comment
Share on other sites

On taking a closer look at the Magnific Popup API I realized that in order to get hold on the current item, I probably should use the change callback.

Also, as the large gallery images will be displayed at near full-screen size, I decided to call responsiveImages directly and simply set pwidth to equal the width of the screen.

Unfortunately, the following code results in the image url of the large image being set to

http://localhost/sovonex/top-drive-services/undefined

So I guess I am still not calling resonsiveImages correctly.

$('.product-gallery').magnificPopup({
    
    // ...

    callbacks: {
        change: function() {

            var pathname = window.location.pathname;
            var target   = this.currItem;

            var $tempImage = $('<img />');

            $tempImage.attr('src', $tempImage.responsiveImages(
                pathname,
                target.src,
                { swidth: screen.width,
                  pwidth: screen.width, // **
                  pxratio: window.devicePixelRatio || 1
                }));

            // **
            // For simplicity, pwidth equals screen width,
            // as we are dealing with images displayed full-screen.

            target.src = $tempImage.attr('src');
        }
    }

});

Any suggestions from anyone familiar with the Responsive Images plugin are highly welcome!

Cheers,

Stefan

Link to comment
Share on other sites

Try something like this:

$('.product-gallery').magnificPopup({
    
    // ...

    callbacks: {
        change: function() {

            var $container = $(this.contentContainer);

            $container.responsiveImages({
              respondToResize: true,
              respondToUpscaleOnly: true,
              reset: true
            });
        }
    }

});

As far as I can see, you can access the content container created by Magnific Popup via this.contentContainer within its callbacks. That’s all you need. Responsive Images will find all img tags within and process them.

If you want to just get a responsive image url for the current screen width from a normal image url, you can do it like:

// As you need an instance of responsiveImages (you can use any you already have instanciated before)
$('body').responsiveImages({...});

... 

// get responsive image url from any image path 
var respImgUrl = $('body').responsivesImage('getURL', 'my/image/path.jpg', { swidth: screen.width, pwidth: screen.width, pxratio: window.devicePixelRatio || 1 }); // pxratio is optional here
Link to comment
Share on other sites

Oliver,

Thanks for your suggestions.

Unfortunately, I had not that much luck with the examples.

The first example that uses $(this.contentContainer) freezed my computer so that I could not even inspect the problem.

The second example, as shown below, made all images on the page disappear (the image url was not modified by the plugin, either):

$('.product-gallery').magnificPopup({

// ...

callbacks: {
        change: function() {

            var pathname = window.location.pathname;
            var target   = this.currItem;

            target.src = $('body').responsiveImages(
                pathname,
                target.src,
                { swidth: screen.width,
                  pwidth: $(window).width(),
                  pxratio: window.devicePixelRatio || 1
                }));

        }
    }
});

I probably just made a silly mistake, I just can't find it.

Cheers,

Stefan

Link to comment
Share on other sites

The way you call responsiveImages is invalid. On init the plugin only expects an object containing option settings. There is no path or target object to be set for responsiveImages. You just call it on an element of the DOM and the plugin takes care of all images contained in the element.

If you want to keep going the way of assining an responsive image url to the current item, it should work like this:

$('.product-gallery')
.magnificPopup({

// ...

callbacks: {
        change: function() {

            var pathname = this.currItem.src; // here you have to get the original image url, not window.location.pathname. You have to find out where it is stored. This is just a guess.
            var target   = this.currItem;

            target.src = $('body').responsiveImages( // asuming you initiated responsiveImages on $('body') before
                'getURL',
                pathname,
                { swidth: screen.width,
                  pwidth: $(window).width(),
                  pxratio: window.devicePixelRatio || 1
                }));

        }
    }
});

Because, if there is an instance set up, you can access some methods via $(element).responsiveImages(methodName, arg1, arg2, ...); like 'getURL'.

Link to comment
Share on other sites

Oliver,

Thanks for your explanations that helped clear up a lot of questions.

There already is an instance of Responsive Images, so I went with the following solution, adapted from the code in your last comment:

$('.product-gallery').magnificPopup({

    // ...    

    callbacks: {
        change: function() {

            var target   = this.currItem;
            var pathname = target.src;

            var newPath = $('body').responsiveImages(
                'getURL',
                pathname,
                { swidth: screen.width,
                  pwidth: $(window).width(),
                  pxratio: window.devicePixelRatio || 1
                });

            pathname = newPath;

        }
    }

});

However, newPath returns null. I also checked that this.currItem.src is indeed the current image path.

Do you have an idea what the problem might be?

Cheers,

Stefan

Link to comment
Share on other sites

Oliver,

That's odd. I logged the variables, and null is returned for newPath:

$('.product-gallery').magnificPopup({

    // ...

    callbacks: {
        change: function() {

            var target   = this.currItem;
            var pathname = target.src;

            console.log("pathname: " + pathname);

            var newPath = $('body').responsiveImages(
                'getURL',
                pathname,
                { swidth: screen.width,
                  pwidth: $(window).width(),
                  pxratio: window.devicePixelRatio || 1
                });

            console.log("newPath: " + newPath);

            pathname = newPath;
        }
    }
});

Console output:

pathname: /sovonex/site/assets/files/1037/pim_watermark3_top-drive-services_-_top_drive_operations_in_saudi_arabia_185.jpg
newPath: null

Still, somewhere I must have made a mistake. I just can't figure out where.

Cheers,

Stefan

Link to comment
Share on other sites

Oliver,

I assume you mean this function:

    // Generates new URL name from original
    getURL: function(original_url, params, debug) {

      console.log("getURL: input url: " + original_url);

      var swidth = params.swidth || 0,
        pwidth = params.pwidth || 0,
        pxratio = params.pxratio || 1;
      var url = original_url.replace(/(\.[a-z]+)$/, '.s' + swidth + '.p' + pwidth + '.r' + pxratio + '$1');

      console.log("getURL: output url: " + url);

      return url;
    }

Could it be that getURL never gets called inside the change callback?

I logged the original url as well as the return value of this function, which output the urls - original and modified - of all images on the page, like this:
 

getURL: input url: /sovonex/site/assets/files/1076/rig-components_-_mast_-_1_165.440x295.jpg js_65e0f5e4d5c7444a9301374984dc5cae_dev.js?no-cache=1411218743:2888
getURL: output url: /sovonex/site/assets/files/1076/rig-components_-_mast_-_1_165.440x295.s1366.p400.r1.jpg

However, when I clicked on a thumbnail to trigger the change callback, nothing is output from getURL.

Cheers,

Stefan

Link to comment
Share on other sites

Oliver,

Neither the original url nor the return value of getPath is logged when clicking on a thumbnail (= calling the change callback). This is why I suspect getPath does not get called in this case.

I uploaded the latest changes as requested. One of the galleries on this site can be found at:

http://staging.sovonex.com/top-drive-services/

The non-minified javascript file is located at /site/assets/aiom/.

I really appreciate your support and patience!

Cheers,

Stefan

Link to comment
Share on other sites

Thanks, Stefan. When I look at your code it seems to me, your initialization of responsiveImages isn’t executed on document.ready, what may cause the instance being not set up correctly. I repeated initialization via console after the page had been loaded completely. After doing this $('body').responsiveImages('getURL', ...) returned a path as expected. So I recommend to change your init code to something like this:

/*-----------------------------------------------------------------------------------*/
/* RESPONSIVE IMGAGES PLUGIN */
/*-----------------------------------------------------------------------------------*/
$(function() {
  $('body').responsiveImages({
    respondToResize: true, // if you want to load other image sizes on resize,
    respondToUpscaleOnly: true, // load other sizes only on upscale
    resolutionInterval: 50, // load image size of closest multiple of 50px (rendered 430px -> load 450px)
    imgSelector: 'img.adaptive', // if you want to be more selective, change it
    loadingClass: 'is-loading', // add a class to img while loading
    callOnUpdate: null, // optional callback when images are updated
    //callOnEach: null, //optional callback called for each images after loading
    callOnEach: function(image) {
      // http://stackoverflow.com/questions/21363955/get-each-image-natural-height-with-jquery
      var tempImage = new Image();
      tempImage.src = image.attr('src');

      var width = tempImage.naturalWidth;
      var height = tempImage.naturalHeight;

      image.attr('width', width);
      image.attr('height', height);

      var attribute = image.attr('data-original');
      if (attribute) image.attr('data-original', image.attr('src'));
    },
    debug: false // set to true to enable console output

  });
});

BTW: Responsive Images preloads images automatically. When callOnEach callback is called, the image has already been loaded. So you don’t need to create a new Image() and can access naturalHeight of the image directly to set the dimensions via html attributes. 

Link to comment
Share on other sites

Dear Oliver,

Thanks for taking a look at my site.

I wrapped the initialization call inside $(function() {...}). I also used $(document).ready(function () {...}), but to no avail as getPath still does not get called.

So, assuming the plugin is initialized correctly, do you see any reason of why getPath can be called on the console, but not on the server?

Also, thanks for you tip about setting the image width and height!

Cheers,

Stefan

Link to comment
Share on other sites

Some more observations:

I get different behaviours on different devices:

  • Desktop, Ubuntu, Firefox or Chrome: The large gallery images don't load.
  • Mobile, Android, Firefox: The large gallery images load on all pages tested (except for one single image, which did not load).
  • iPad, Safari: The large gallery images don't load. In addition, the thumbnail images first appear and then disappear again, leaving the gallery without images.

Cheers,

Stefan

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...