Jump to content

Using ProCache With Wilcox' Adaptive Images Plugin


bytesource
 Share

Recommended Posts

Hi, 

I was looking into using the Adaptive Images plugin on my updated website to reduce the load on mobile devices. This plugin serves differently sized versions of the same image depending on the visitor's screen size. 

However, I definitely also want to install the ProCache plugin, which - if I am not mistaken - makes my site static. 

So, I was wondering if a plugin like Adaptive Images would actually be usable on a site that has the ProCache plugin installed. 

If anyone has been using both plugins on the same site I would love to hear about it. 

Cheers, 

Stefan

Link to comment
Share on other sites

Without testing it and just looking at the .htaccess file it looks like it should work since the .htaccess is routing images through the PHP script. ProCache bypasses PHP using .htaccess so it should be possible to make the two compatible.

It will slow your page load times slightly as it has to fire up PHP to check some things, but would still be quicker than doing it without ProCache on at all.

I can't help thinking though that there is a way to do this without PHP at all. Since you can write some code in ProcessWire to create any size versions of images you require (think about hooking page save and producing your variations then) all you need then surely is some JS to detect screen size and load the appropriate sized image, falling back to the largest. The advantage here is no PHP is used at all.

I make it sound so easy, but it's probably not :)

  • Like 1
Link to comment
Share on other sites

Yes, for instance, Foundation 5 includes jquery that can be used to interchange between content or images depending on media queries

http://foundation.zurb.com/docs/components/interchange.html

There is also responsejs.com that does a similar job in a similar way.

You could probably do this with plain old javascript, to be honest (but I am not sure how!)

But with any of these methods, you can use the PW API to create your images, or use Crop Image module to create specific images and then just call them depending on viewport size.

  • Like 1
Link to comment
Share on other sites

One thing that should be possible is to create your 'own image' format.

I do think there are opensource solutions for this. But to lazy to search one :-)

But basically it looks like this:

<?php

$phone = $image->size(40,15);
$tablet = $image->size(200,75);
$desktop = $image->size(400,150);
 
$image = "<div class='my-adaptive-image'>" .
"    <img src='/path/to/transparent.png' " .
"    	data-phone='$phone->url' " .
"    	data-tablet='$tablet->url' " .
"    	data-desktop='$desktop->url' " .
"    	style='display: block; height: 0 width: 0;'" .
"    	/>" .
"    <noscript><img src='$desktop->url' /></noscript>" .
"<div>";

echo $image;
 

You can us Javascript to replace the transparent.png with the URL matches the data attribute. And use javascript to remove the style information. At that point there a fully adaptive image.

If there's no Javascript active, then the inline style of the first image prevents displaying it. And the Image inside the <noscript> takes over.

There are downsides to this methode. 

1. It forces the browser to repaint your page every time it finds an image.

2 It needs 1 extra request for every page where the transparent pixel is used. (but this one get cached, so not really a big deal)

  • Like 1
Link to comment
Share on other sites

Since you can write some code in ProcessWire to create any size versions of images you require (think about hooking page save and producing your variations then) all you need then surely is some JS to detect screen size and load the appropriate sized image, falling back to the largest. The advantage here is no PHP is used at all.

Pete, that's a good way to go. With the creation of different sized images, I would do it at uploading images through the images inputfield, the most common way I think. And if someone add images through the API somehow, he simply can add some more line of code to craete the images.

It can go like this:

public function init() {
	$this->addHookBefore('InputfieldFile::fileAdded', $this, 'createImages');
}

public function createImages($event) {
        $inputfield = $event->object;
        if('images' != $inputfield->name) return;      // we assume images field !! name of the field is: images !! otherwise change it

        $p = $inputfield->value['page'];               // get the page
        if('gallery'!=$p->template) return;            // don't do it on other pages than galleries

        $image = $event->argumentsByName("pagefile");  // get the image

        $image->width(400);
        $image->width(800);
        $image->width(1200);
        $image->size(200, 200);
}

This hooks into before the image gets added and creates the additional variations. It does not replace the event. After that the admin thumb is created.

It is very basic and could be made a bit comfortable with checking the images filedname itself, etc.

But it works fine for an individual single site.

  • Like 2
Link to comment
Share on other sites

@Martijn: do you know this format "<picture>"?  I have thought about a little module that supports creating retina images and that at least need to add a property to pageimage to provide the retina url. I haven't wrote a line of code, just collecting informations.

Would be fit perfectly to it to also create adaptive image variations and provide the markup. Which one would be better regarding browser support, the <picture> or your <img data- one?

And do you have some lines of JavaScript for that? :)  If yes, - can we put it together, collaborating on a module?

Link to comment
Share on other sites

@Horst,

I was just thinking loud there, so I don't have a real test case & no js. But I have a site where I swap a transparent pixel, with no fallback if js is disabled. Nothing special there.

After you posted your code I instantly thought about a module as the extra markup I don't want to type manually every time. Adaptive images must be easy to use. And should work without Javascript. After That I searched the net for the <picture> element, ( not that I'm keen with those HTML5 tags for those things ) Then the baby starts crying. 

Will come back to this.

  • Like 2
Link to comment
Share on other sites

@Sinnut: thanks for the links. I don't know much of css / js things, but in first place i like solutions that do not rely on activated scripting. Best would be something like MadeMyDay shows in his post under <picture> with css media queries. JS should be come in only for browsers that do not support media queries or the picture - tag.

On the other side, nearly all pages with foto galleries today rely on JS, - so I'm yet not totally sure how to go. But the <picture> thing sounds promising.

Link to comment
Share on other sites

@Horst,

Maybe it's a little bit clumsy but I was playing around with my <div> & <noscript> adaptive image. I don't think it's fully compatible yet with old IE.

I just post this as a rough idea.

The image: 

$image = $page->images->first();

//thumbs
$tiny = $image->width(100);
$small = $image->width(200);
$tablet = $image->width(400);
$desktop = $image->width(800);

// adaptive-image
$img .= "<div class='adaptive'>";
$img .=     "<img src='data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' ";
$img .=         "data-tiny='$tiny->url' ";
$img .=         "data-small='$small->url' ";
$img .=         "data-tablet='$tablet->url' ";
$img .=         "data-desktop='$desktop->url' ";
$img .=         "alt='$desktop->description' ";
$img .=         "/>";
$img .=     "<noscript>";
$img .=         "<img src='$desktop->url' alt='$desktop->description' />";
$img .=     "</noscript>";
$img .= "</div>";

echo $img;

The Javascript:

//javascript
var adaptive = {

    /**
     * The widths should be in an ascending order
     * Names can be changed but should match the datac attribute
     *
     */

    sizes: {
        'tiny': 0,        // from 0 till 399
        'small': 400,     // from 400 till 699
        'tablet': 700,
        'desktop': 1200
    },
    // After window resize delay ( Change if you wish )
    delay: 300,
    // Width of the viewport
    screen: 0,
    // Name of the current size
    sizeName: null,
    // Timeout for the window resize
    timeOut: null,
    // Calculate viewport width
    calcScreenWidth: function () {
        adaptive.screen = window.innerWidth > 0 ? window.innerWidth : screen.width;
    },
    // Get the current size name (breakpoint)
    calcSizeName: function () {
        for (var sizeName in adaptive.sizes) {
            if (adaptive.screen > adaptive.sizes[sizeName]) {
                adaptive.sizeName = sizeName;
            }
        }
    },

    init: function () {

        adaptive.calcScreenWidth();
        adaptive.calcSizeName();

        var containers = document.getElementsByClassName('adaptive');

        for (var container in containers) {
            var container = containers[container];
            var img = container.firstChild;
            if ( typeof img != 'undefined' ) {
                img.src = img.getAttribute("data-" + adaptive.sizeName);
            }
        }

        // do it again after resize end
        window.onresize = function() {
            window.clearTimeout(adaptive.timeOut);
            adaptive.timeOut = window.setTimeout(adaptive.init(), adaptive.delay);
        }
    }
}

// DOM ready
$(function() {
    adaptive.init();
});
  • Like 2
Link to comment
Share on other sites

Thanks Martijn, I will try out later, or tomorrow.

one thing I think it could have is a log which versions it has loaded. Means if it has already a larger version, there is no need to load a smaller one when resizing the window. (assuming it is displayed fluid!)

But the decision to load a new one or not cannot depend simply on the direction of window resize, resize smaller = no load | resize larger = load, that's wrong.

  1. onload it's medium
  2. resize small  <=
  3. resize large  =>

   = only 3. need to load a new image

  1. onload it's large
  2. resize small  <=
  3. resize medium  =>

   = no need to load a new image, even when window resizes larger

Or is this stupid?

  • Like 2
Link to comment
Share on other sites

Nope, clever ! :-)

Do you think a jQuery plugin suits better, basically more like this ?

// calling like this
$(".adaptive").adaptive({
    sizes: {
        'tiny': 0,        // from 0 till 399
        'small': 400,     // from 400 till 699
        'tablet': 700,
        'desktop': 1200
    },
    delay: 400
});

// or calling like this or something
$(".adaptive").adaptive(<?= $wireAdaptiveImage->settings() ?>);
  • Like 2
Link to comment
Share on other sites

@Martijn: forgotten to say: your solution is better than some big libraries because it's support for noscript!

EDIT:

If it gets support for old IE8, it were perfect!

Edited by horst
Link to comment
Share on other sites

 Do you think a jQuery plugin suits better, basically more like this ?

...

Hhm, don't really know, (I'm a php man).

The first one can working without jQuery? Is this an advantage? Otherwise I think jQuery plugin looks nicer, is more compact?

Link to comment
Share on other sites

Hhm, don't really know, (I'm a php man).

Logical thinking has nothing to do with a language. :-)

jQuery solves compatibility issues ( can be solved without ).

It's more obvious how to use. But requires jQuery & the plug-in to be loaded. ( extra requests )

On the other hand I don't know a project where I don't use jQuery (other people ?)

And calling the jQuery plugin is so much easier for your eyes.

  • Like 2
Link to comment
Share on other sites

@SiNNuT & Horst I didn't forget your post about bandwidth checking. But to be honest, I don't know where to start to implement it as a solution as I don't know which steps we should take to make it work. I lack the javascript skills. I lack general knowledge about requests and the time to build or borrow code from an existing plug-in. However, I do think that bandwidth checking theory is great. 

I assume bandwidth checking is done with a test, but bandwidth on cellular network can be very fluctuating. We don't want to end up with a very positive test on a resource heavy page, forcing the browser to load all heavy images while the connection speed is dropped. We can't do a test for every single image because of the extra requests. Max parallel http connections from the same (sub)domain is really limited as you already know.

If you hook your Retina MacBookPro to your handy with a bad cellular connection, what to do now?

I can't get a complete picture of the whole adaptive image game. 

Link to comment
Share on other sites

@Martijn: would be best, the browsers have implemented the <picture> tag and do this stuff by themself.

The workaround solution for it (picturefill) do not have a bandwith check too, (or I haven't seen it).

I have linked to the hisrc because I have thought maybe you can take this, because it looks close to what you have. This way you don't need to build all new. This also has no bandwith checking. Also I cannot imagin how to implement that on a per image basis.

the PageimageAdaptive should do the following:

  1. has a configpage where you can add the data for the different variations  (imagefields ?, templates ?)
  2. hook into imageupload and create the variations
  3. add new property / properties to pageimage to output complete img markup and / or only url/s
  4. optionally enable retina variations in the configpage or request with pageimage options on a per image basis
  5. need something to output / inject the needed JS code into the page

Have I forgotten something?

Actually I can do 1., 2., 4.

3. I will find out how to do it

5. I don't know yet

Link to comment
Share on other sites

Responding to your points, duplicating what you're saying in most cases.

1. PageimageAdaptive->getConfigInputfields() is the place I think. (inputfield settings)

2. Agree :-)

3. Indeed we need a adaptiveRender() methode or something. And a FilenameArray, from low -> hight

4. Request with PageImage options, defaulting from point 1, but overwriting possibility per PageImage.

5. As this should work with ProCache. Maybe we can find a way that works native in one or more modern browsers with a js fallback for the others. Basically I tell drop my idea and find a way to show deafult image if JS is disabled and picture element is not supported.

ps,

Other members, it's open for discussion :-)

  • Like 1
Link to comment
Share on other sites

Also I want to add. My JS depends on settings set in the script. It's better that the script would read them from the meta data from the images it self.

I don't think it is a bad idea to have our own flexible element, by shim/shiv our own, say <wireimage></wireimage>. That when it is easier to implement and more logical for the things we want to achieve. 

Diogo & Soma and others who are good with Javascript. What do they have to say about the Javascript backup/solution 

Link to comment
Share on other sites

Good article!

If we want to follow that, we should go with hisrc & jQuery, or independently with foresight. (Or modify them | take out the bandwith thing | create something own)

I don't think it is a bad idea to have our own flexible element, by shim/shiv our own, say <wireimage></wireimage>. That when it is easier to implement and more logical for the things we want to achieve.

Which effects does this have for browsers with disabled JS? Can it have a NoJS-fallback?

Edited by horst
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

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