Git Product home page Git Product logo

imager.js's Introduction

Imager.js Build Status

Imager.js is an alternative solution to the issue of how to handle responsive image loading, created by developers at BBC News.

Why?

There are many responsive image solutions in the wild: srcset, src-n, PictureFill and so on. They are either verbose or hard to debug (and to maintain/integrate). Some of them don't deal well with pixel density and suffer from double asset payload (meaning you end up downloading assets unnecessarily).

We wanted something simple, which works and which is fast as well as network friendly (only download what you need, when you need it).

Imager implements the BBC Responsive News technique which incorporates:

  • loading any image once
  • loading the most suitable sized image

How does it work?

Imager runs through the following workflow:

  1. lookup placeholder elements
  2. replace placeholders with transparent images
  3. update src attribute for each image and assign the best quality/size ratio URL

Finally, it will lazy load images to speed up page load time even further.

Compatibility

Imager is tested against the following mobile and desktop browsers:

  • Chrome 33
  • Firefox 22
  • Opera 12.15
  • Edge 12
  • Internet Explorer 8, 9, 10 and 11
  • Safari 5, 6, 7, 8 and 9
  • Mobile Safari 4, 5, 6 and 7
  • Android 2, 3 and 4

Install

npm bower old school
npm install --save imager.js bower install --save imager.js download zip file

Using

<div style="width: 240px">
    <div class="delayed-image-load" data-src="http://placehold.it/{width}" data-alt="alternative text"></div>
</div>

<script>
    new Imager({ availableWidths: [200, 260, 320, 600] });
</script>

This will result in the following HTML output:

<div style="width: 240px">
    <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" alt="alternative text" class="image-replace">
</div>

<script>
    new Imager({ availableWidths: [200, 260, 320, 600] });
</script>

260 has been elected as the best available width (as it is the closest upper size relative to 240 pixels).

Pixel Ratio / HiDPI / Retina

Let's say we have generated 4 sizes of images (200, 260, 320 and 600) in 3 different pixel ratio flavours (1, 1.3 and 2):

<div style="width: 240px">
    <div class="delayed-image-load" data-src="http://example.com/assets/{width}/imgr{pixel_ratio}.png" data-alt="alternative text"></div>
</div>

<script>
    new Imager({ availableWidths: [200, 260, 320, 600], availablePixelRatios: [1, 1.3, 2] });
</script>

The img[src] will be computed as following (according to the reported window.devicePixelRatio value by the device):

  • http://example.com/assets/260/imgr.png if no pixel ratio is detected, or advertised as 1
  • http://example.com/assets/260/imgr-2x.png if pixel ratio is advertised as 2 (or any value greater than 2)
  • http://example.com/assets/260/imgr-1.3x.png if pixel ratio is advertised as 1.3

Head to this device pixel density test resource to learn more about the available pixel ratio for your device.

Interpolating {width} value

Imager has the ability to replace {width} with a non-numeric value if you provide the widthInterpolator option, which is a function that returns the string to be injected into the image URL for a given width. This feature allows you to use a human readable name or integrate with third-party image providers.

<div style="width: 240px">
    <div class="delayed-image-load" data-src="http://example.com/assets/imgr-{width}.png" data-alt="alternative text"></div>
</div>

<script>
    new Imager({
        availableWidths: [200, 260, 320, 600],
        widthInterpolator: function(width, pixelRatio) {
          return width + 'x' + (width / 2);
        }
    });
</script>

The img[src] will be computed as http://example.com/assets/imgr-260x130.png instead of http://example.com/assets/imgr-260.png.

Alternatively you can define availableWidths as an Object where the key is the width, and the value is the string to be injected into the image URL.

<div style="width: 240px">
    <div class="delayed-image-load" data-src="http://example.com/assets/imgr-{width}.png" data-alt="alternative text"></div>
</div>

<script>
    new Imager({
        availableWidths: {
            200: 'square',
            260: 'small',
            320: 'medium',
            600: 'large'
        }
    });
</script>

The img[src] will be computed as http://example.com/assets/imgr-small.png instead of http://example.com/assets/imgr-260.png.

Mixing various configurations

You might want to generate HiDPI responsive images. But what if you also include images from another provider which serves a totally different set of sizes, without pixel ratio?

Here is an example to serve your own images alongside Flickr images.

<div style="width: 240px">
    <div class="delayed-image-load"        data-src="http://placehold.it/{width}" data-alt="alternative text 1"></div>
    <div class="delayed-flickr-image-load" data-src="//farm5.staticflickr.com/4148/4990539658_a38ed4ec6e_{width}.jpg" data-alt="alternative text 2"></div>
</div>

<script>
    var imgrPlaceholder = new Imager('.delayed-image-load', {
        availableWidths: [200, 260, 320, 600]
    });

    var imgrFlickr = new Imager('.delayed-flickr-image-load', {
        availableWidths: {
            150: 't_d',
            500: 'd',
            640: 'z_d'
        }
    });
</script>

This will result in the following HTML output:

<div style="width: 240px">
    <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" alt="alternative text 1" class="image-replace">
    <img src="//farm5.staticflickr.com/4148/4990539658_a38ed4ec6e_d.jpg" data-src="//farm5.staticflickr.com/4148/4990539658_a38ed4ec6e_{width}.jpg" alt="alternative text 2" class="image-replace">
</div>

Passing a collection of elements

You might want to pass a NodeList or an array of placeholder elements as the first argument rather than a class selector.

<div style="width: 240px">
    <div class="delayed-image-load" data-src="http://placehold.it/{width}" data-alt="alternative text"></div>
</div>

<script>
    var placeholderElems = document.querySelectorAll('.delayed-image-load');
    var imgrPlaceholder = new Imager(placeholderElems, {
        availableWidths: [200, 260, 320, 600]
    });
</script>

This will result in the following HTML output:

<div style="width: 240px">
    <img src="http://placehold.it/260" data-src="http://placehold.it/{width}" alt="alternative text" class="image-replace">
</div>

Documentation

Browse Imager public APIs and options – versioned alongside the source code of the project:

Demos

Additional and fully working examples lie in the demos folder.

They are using it

Background

This is an experiment in offering developers an interim solution to responsive images based on the ImageEnhancer concept researched and developed by the team at BBC News.

At present, support for srcset and PictureFill are not widespread and the polyfills for these solutions also come with a number of drawbacks.

Mark McDonnell (@integralist) documented the process and rewrote the original code so it could be evolved and improved with the help of the open-source community.

The goal of this project is to automate the process with the help of the Grunt JavaScript task runner (potentially via grunt-responsive-images for image generation based on a source directory).

Much of this work can be repurposed to work with a more standards-based approach once support improves in modern browsers.

For the purposes of maintaining a distinguishment between the ImageEnhancer concept built by BBC News and this project, we're calling it Imager.js

Read more on BBC Responsive News blog.

Credits

Licence

Copyright 2015 British Broadcasting Corporation

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

imager.js's People

Contributors

addyosmani avatar benjambles avatar bpscott avatar feedmypixel avatar inetbug avatar integralist avatar joewillnyc avatar joshk avatar kenoir avatar kkirsche avatar longprao avatar marcinwenger avatar nikai3d avatar nkp avatar omgmog avatar paul-butcher avatar thom4parisot avatar wildlyinaccurate avatar willbamford avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

imager.js's Issues

Aspect ratio of images while loading page

On a news site with 100+ images on the front-page, one of our devs was using a lowsrc to make sure the image elements on the page would maintain size initially - this of course resulted in server problems due to the sheer volume of requests.

Our solution was to put a wrapper-element around every image placeholder, e.g. using CSS like:

.image-wrapper {
    width: 100%;
    position: relative;
    overflow: hidden;
}

.image-wrapper > img {
    position: absolute;
    left: 0;
    top: 0;
}

In other words, we get the image width/height on the server-side, calculate the aspect-ratio in percent, and use padding-bottom to maintain aspect ratio of the wrapper element:

<div class="image-wrapper" style="padding-bottom:62.25%">
    ... response image here ...
</div>

This works - the page loads without anything jumping around.

This approach works because this site is responsive, loading the same image at different resolutions - but would not work if the site was adaptive, e.g. if it was loading versions of the image with different aspect ratios to match design variations on smaller devices.

This makes me wonder - currently, Imager only needs to care about image widths, since the height is calculated by the browser when the images load. Could we have support for optionally specifying both the width and height of each image version?

This would enable the script to create wrappers around generated image-elements, using an approach similar to what I described above - which would enable responsive (and adaptive) images to initially (or at least very early) reserve the amount of space they need, so that things don't jump around while the page is loading.

Thoughts?

Progressive quality of images

For one of the websites I'm working on, I've built a similar but slightly different image loader. For larger images, it first loads an image at 10% quality, then keeps doubling that quality until the full version (100%) is loaded. It tacks the quality at the end of the filename, eg [email protected], [email protected] and so on. Would you be interested in a pull request which implements this?

Replaced image width attribute

Hope im not missing something obvious here.

using:

<span data-class="list-item-image" class="delayed-image-load" data-src="http://placehold.it/480x310" data-alt="tile"></span>

with settings:

var delayedImages = new Imager(".delayed-image-load", {
    className: "image-loaded",
    lazyload: true,
    scrollDelay: 2000,
    availableWidths: [480]
});

renders:

<img src="http://placehold.it/480x310" class="list-item-image image-loaded" alt="tile" data-src="http://placehold.it/480x310" width="480">

Is there a way to not to render width attribute of replaced image?

currently i've commented out this line to make it work.

Thanks,
Great plugin!

Check if image is visible

I have a responsive layout with images hidden on mobile and visible on a tablet/desktop. by default all the images are loaded. So on mobile also the hidden images are processed and loaded bij Imager.js. A extra check if the div/img element is visible would be great. Or is this feature already available?

Thanks!

Lazy loading does not load images when revealed by a resize

To reproduce:

  1. Open the lazyloading demo: /demos/lazyload/index.html in a small window, showing just the text.
  2. Resize the window so that the first image would be visible

Nothing happens. Now scroll around, the images start loading as expected.

Witnessed in Chrome 33, Firefox 13, IE 9

[PROPOSAL] Strategy implementation

The intention

Imager replaces a DIV (or container) tag by a placeholder image prior to its width URL calculation. The logic of Imager might pleased everybody but users have different contraints:

  • their CMS is too complicated to hack
  • for design reasons, you might want to add the placeholder image inside the container

The proposal

The user can decide how the responsive image is treated without altering the internals of Imager.

Here are the various options to implement that.

One buildfile per strategy

  • imager-core.js + imager-strategy-replacer.js = imager.js
  • imager-core.js + imager-strategy-container.js = imager-container.js
  • function Imager() + (Imager.prototype.getPlaceholder + Imager.prototype.processPlaceholder()) = imager-custom.js
<script src="imager.js">
<script>
var imgr = new Imager();
</script>

or

<script src="imager-container.js">
<script>
var imgr = new Imager();
</script>

Pros:

  • Nothing to configure, just dropping in the good file

Cons:

  • would not be possible to mix strategies together within a same page
  • might be more complicated for someone wanting to bake his own strategy

DIY

<script src="imager.js">
<script src="imager-strategy-replacer.js">
<script src="imager-strategy-container.js">
<script>
// by default it will look for the `replacer` one
var imgr = new Imager();

// or we can specify which strategy we want to use
var imgr_sidebar = new Imager({ strategy: 'container' });
</script>

Pros:

  • Freedom to make Imager working the exact way you want
  • Ability to use different replacements within a same page

Cons:

  • May be slightly less intuitive than the other proposal

[Question] Extra offset for `isThisElementOnScreen` method?

I am using lazyload: true but I'd like to trigger load for images offscreen that are close(ish) to being in the viewport. My team is wishing the images were loading sooner, but I still want some lazy loading ability.

I am proposing the idea of being able to configure an additional offset that triggers loading earlier if desired. I know the idea of lazy loading is muddied a little with this concept, but I am seeing a need for it in my projects sometimes and still provides some lazy loading benefit (the default would be 0). I could submit a really simple PR. Thoughts?

Example:

this.lazyLoadOffset = opts.lazyLoadOffset || 0;
new Imager('.the-target', {
    lazyload: true,
    // Offset would start at Imager.getPageOffset() + clientHeight
    lazyLoadOffset: document.documentElement.clientHeight
});

Pixel density sizes array

The config would look like:

// original and BC way
var manager = new Imager(document.querySelectorAll(".delayed-image-load"), {
  availableWidths: [96, 130, 165, 200, 235, 270, ]
});

// by pixel density 
var manager = new Imager(document.querySelectorAll(".delayed-image-load"), {
  availableWidths: {
    "1x": [96, 130, 165, 200, 235, 270, ],
    "2x": [200, 400, ]
  }
});

Integrate Grunt tooling for responsive images

I've added grunt-responsive-images to our tooling setup for this project with some basic configuration in place.

https://github.com/BBC-News/Imager.js/blob/master/Gruntfile.js#L28

It might be useful for us to drop in some hi-res sample images into app/images which we can hook up to this task. That way it can generate us the images needed for demonstrating how Imager.js works without the placeholder site.

We might need to figure out the best naming strategy for files however and how they'll hook into https://github.com/BBC-News/Imager.js/blob/master/app/scripts/imager.js#L63 and https://github.com/BBC-News/Imager.js/blob/master/app/scripts/imager.js#L115

[PROPOSAL] Optimise DOM reads/writes

Currently Imager is doing a sequence of read/write read/write, which is very costly on a document with many images.

Batching Reads and Writes should improve Imager's performance dramatically:

  1. READ (parse DOM + read dimensions)
  2. WRITE (insert the correct images where needed)

See FT's FastDOM for documentation on the matter.

[PROPOSAL] Updading `src` only if the size gets bigger

tl;dr

Don't waste radio effort to download a better quality image as the browser can just redimension it.

Use Case

<div style="width: 480px">
  <img src="/assets/480/example.jpg" data-src="/assets/{width}/example.jpg" class="responsive-img">
</div>

Should become:

<div style="width: 240px">
  <img src="/assets/480/example.jpg" data-src="/assets/{width}/example.jpg" class="responsive-img">
</div>

Instead of:

<div style="width: 240px">
  <img src="/assets/240/example.jpg" data-src="/assets/{width}/example.jpg" class="responsive-img">
</div>

Pros

  • time saved
  • no network usage

Cons

  • uses CPU to compute

Interrogations

  • repaint costs > network costs

I guess waking up the radio has a much higher latency though. To be confirmed.


^ Resize? Resize? No Resize!

Interpolation of src-attribute

Please consider adding an interpolation hook for the src attribute value, e.g.:

@@ -124,6 +124,7 @@
         this.widthsMap        = {};
         this.refreshPixelRatio();
         this.widthInterpolator = opts.widthInterpolator || returnFn;
+               this.srcInterpolator   = opts.srcInterpolator || returnFn;

         // Needed as IE8 adds a default `width`/`height` attribute…
         this.gif.removeAttribute('height');
@@ -359,9 +360,12 @@
     };

     Imager.prototype.changeImageSrcToUseNewImageDimensions = function (src, selectedWidth) {
-        return src
-            .replace(/{width}/g, Imager.transforms.width(selectedWidth, this.widthsMap))
-            .replace(/{pixel_ratio}/g, Imager.transforms.pixelRatio(this.devicePixelRatio));
+               var width      = Imager.transforms.width(selectedWidth, this.widthsMap),
+                       pixelRatio = Imager.transforms.pixelRatio(this.devicePixelRatio);
+
+               return this.srcInterpolator(src
+            .replace(/{width}/g, width)
+            .replace(/{pixel_ratio}/g, pixelRatio), width, pixelRatio);
     };

I had to add this because the images in my scenario have unpredictable filenames, which cannot be computed on the client-side. I think this is a pretty common scenario? Other responsive image loaders provide some means of handling this scenario.

My precise solution was to use image placeholder with like this:

<div data-src='{"low":"/photo/cache/16/16_280_0_12_0_576_360_2_fb45.jpg","high":"/photo/cache/16/16_720_0_12_0_576_360_2_e2b9.jpg"}' class="responsive-image"></div>

With Imager configured like this:

            var images = new Imager('.responsive-image', {
                availableWidths: { 280: "low", 720: "high" },
                srcInterpolator: function(src, width) {
                    return jQuery.parseJSON(src)[width];
                }
            });

It's a fairly simple solution. The only alternative I could come up with, was to create a dedicated instance of Imager for every individual image, which seems really ineffecient, and would mean I'd have to generate JS to load every individual image.

Only replace {width} placeholder, without changing element

I'm using imager and also fluidbox, which is a relatively straightforward lightbox. It uses the following html:

<a href="/path/to/full/size/image">
    <img src="/path/to/thumbnail" alt="lorem ipsum" />
</a>
<!-- See here: https://github.com/terrymun/Fluidbox#basic -->

Where the <a> links to the full size image (displayed on click), and the <img> is just the thumbnail (example). Since the image that the <a> links to is only displayed on click, it doesn't have any width before that. Which means that imager can't measure the width.

Since these images are full screen it would be awesome if I could just pass the screenwidth to imager, as that is the width that the image'll transform to on click. Is there a way to deal with such a use case?

[PROPOSAL] AMD Support

BBC's original implementation of Imager (known as Image Enhancer) was wrapped up as an AMD module so it could be loaded into other scripts using an AMD compatible loader script such as RequireJS or Curl.

Before we can re-introduce the new and improved Imager back into the BBC code base we'd need to ensure it is AMD compatible (currently it's not, it creates a global Imager property instead).

/cc @oncletom

Problems with Imager when browser zooming

I have successfully implemented Imager.js on a development environment using the Pixel ratio method for retina detection:

http://example.com/assets/{width}/imgr{pixel_ratio}.png

It works fine but in Chrome and FF when the page is zoomed in or out Imager doesnt work - the images aren't loaded. Safari is fine.

A quick look in the console reveals that the plugin is appending an invalid pixel-ratio to the file name and therefor not finding the correct image - ie:

/assets/images/280/imgr-0.8999999761581421x.png

I take it this is because when the browser is zoomed the pixel-ratio is affected and Imager acts accordingly? Safari by default only zooms the text so that's why its not affected.

Is this a known issue and is there any way around it?

Thanks

Too much technology ends up smothering the actual implementation details

Upon cloning down the code in this repo I've discovered an awful lot of technology is being installed and yet the majority of it is not required to implement the solution this repo was aiming to solve and provide.

I understand Grunt will be utilised in the near future to help automate the process as shown in the original example but either for someone new to the technology stack (e.g. Yeoman, Grunt, Sass, Compass and a whole host of grunt related packages within package.json) I feel this repo is losing focus on its purpose.

The tooling that has been set-up can be fantastic and very helpful I agree, but I feel this repo would benefit much more from only implementing the bare bone essentials needed for it to function properly.

For example, we don't need Sass to generate the CSS required and we don't need Yeoman to handle bootstrapping... etc.

This seems like over-engineering to me.

If the user decides to utilise those tools then that's fine and acceptable for them to implement them around the solution we're providing.

Otherwise we just end up confusing users and potentially alienating them from trying out the solution we're proposing.

@addyosmani would be good to get your thoughts on this :-)

Update/push bower version

Hi, from Bower I'm getting the 0.2.0 version which isn't currently working for me. If I pull the version directly from Github everything is great though.

Any chance you want to push that version using bower?

Lazy load broken on Android

Lazy loading seems to be broken both on real Android phones and on Android emulators, at least for the default Android browser.

It seems that the default browser (and apparently also most third-party browsers) do not fire the scroll event until after the scroll is finished. (Same with touchmove.) So somewhere along the line the Imager must get "confused" and doesn't write a src for the replaced image. This is unfortunate, since a phone is probably the best use case for lazy loading.

I have seen working lazy-load code that uses a function bound to the img onload event that writes the new src. I don't know whether this method was tried and discarded or not, but I'll see if I can make it work, at least for my use.

How can I responsive to retina device?

Hello everybody:
I want the web page is responsive to retina device, but imager.js only reference to generated img regardless of the devicePixelRatio of the device. Whether should I introduce Retina.js in the page? Doesn't imager.js handle the condition?

Best Regards.

`widthInterpolator ` can interpolate `{width}` replacement to deal with aspect ratios

Defining availableWidths as an array is brilliantly simple if your image server has just the width in the URL.
Defining availableWidths as a short object is great if your image server has things that are nothing to do with the width in the url.

Things gets a little bit hairy if your url depends on the width, but also contains the things based off the width in the url, such as the image height for constraining purposes. For instance BBC Programme Images look like this for a fixed ratio 16:9 image: http://ichef.bbci.co.uk/images/ic/640x360/p01mzt0r.jpg.

I could build an object that looks like:

{
  160: "160x90",
  240: "240x135",
  320: "320x180",
  480: "480x270",
  560: "560x315"
//...
}

Then pass that into availableWidths, but that's a bit ugly.

I could also define availableWidths as a function, but then I'd have to reimplement all the width clamping logic which really should be imager's problem.

What would be nice would be if I could do something like this:

<div class="delayed-image-load-16x9" data-src="http://ichef.bbci.co.uk/images/ic/{width}/p01mzt0r.jpg" data-alt="alt"></div>
new Imager('.delayed-image-load-16x9', {
    availableWidths: [160, 240, 320, 480, 560],
    widthInterpolater: function(w){ return w + 'x' + (i / (16/9)); }   
  });

That would build me urls like http://ichef.bbci.co.uk/images/ic/160x90/p01mzt0r.jpg

I've had a nose through the code and it looks like this would be pretty easy to add into Imager, but I wanted to get a thumbs up from somebody before bothering to make the changes. Is this something you would be interested in?

Specify domain

In order to keep regex functionality simple and easy to understand, it may be handy to allow a cdn/domain to passed as an options something like..

this.domain = opts.domain || '';

and return the path like this..

return domain + path + file + selectedWidth + extension;

This means the regex wont have to be changed for different environments, it also make switching from relative to absolute paths a touch easier

Tests

  • Karma tests
  • TravisCI config

[PROPOSAL] Update API

The intention

Once we have instantiated an Imager instance, there is no documented way to update the pool of responsive images it handles (unless a DIY of the cache property).

The proposal

Adding a prototype method to replace the actual pool of responsive images by another one.

Ideally, it will share the same behavior as the Constructor Explicit Argument API (cf. #22).

Note: not satisfied with the naming, as it should suggest updating the list of related responsive images and not updating their src attribute (cf. #25).

With jQuery:

var imgr = new Imager();

pubsub.on('news.updated', function(){
  imgr.updateElements($('#main .delayed-image-load'));
});

With DOM NodeList:

var imgr = new Imager();

pubsub.on('news.updated', function(){
  imgr.updateElements(document.querySelectorAll('#main .delayed-image-load'));
});

With string CSS selector:

var imgr = new Imager();

pubsub.on('news.updated', function(){
  imgr.updateElements('#main .delayed-image-load');
});

[PROPOSAL] Build tool to optimise Imager library (so it includes only code actually used)

Looking over the proposals that @oncletom has written up, it seems like it would be a good idea to have some form of Grunt task that the user could use to optimise the API of Imager.

By this I mean, if we look at #25 (triggering events manually), I suggested making sure the default behaviour was the resize event and the user could override that behaviour. So if the user decided to do just that, the Imager library would still have a chunk of code that would no longer be needed in production. It would be good if they could run a grunt task which they could specify what API's they have used (or which they have overridden) and then Grunt would clean-up the Imager library code so it only included code actually used.

JS error: Cannot call method 'replaceChild' of null --- Upon Scroll only

After implementing imager, a JS error is logged upon scroll.
I have implemented imager with lazyload only.

the error i receive is as follows:

Uncaught TypeError: Cannot call method 'replaceChild' of null imager.js:193
Imager.createGif imager.js:193
(anonymous function) imager.js:204
applyEach imager.js:20
Imager.changeDivsToEmptyImages imager.js:201
Imager.scrollCheck imager.js:163
(anonymous function) imager.js:353

Can anyone shed any light on what could be causing this issue.
Thanks.

Measuring element width in a layout that uses flexbox layout

Working on a site that uses flexbox CSS layout, I ran into an issue where only the lowest-resolution image would get loaded, even after resizing.

I narrowed it down to image.parentNode.clientWidth always returning zero in the determineAppropriateResolution function.

Adding a second fallback to offsetWidth seems to fix the issue:

Imager.prototype.determineAppropriateResolution = function (image) {
  return Imager.getClosestValue(image.getAttribute('data-width') || image.parentNode.clientWidth || image.parentNode.offsetWidth, this.availableWidths);
};

My problem isn't completely fixed- it still doesn't initially load the correct size image, but this seems to be an important step on the way.

Issues with resizing of Lazyloaded images

While attempting to use the experimental lazyload option I believe that there is a bug regarding once an image has been loaded, it will no longer resize according to whatever information within the availableWidths array. eg If the image loads at 640, no matter what the size of the viewport, it will remain 640.

I've uploaded an example with the demo mostly untouched with some minor changes:

  • I've moved the imager.js path to be root rather than one level up
  • I've changed the hardcoded 320 filename to each image to the {width} parameter
  • All of the appropriate images have been generated with Grunt

You can view the example here: http://anthonybruno.io/sandbox/imager

Separation of concerns

  • Something which handles the DOM Elements
  • Something which performs the calculation logic
  • Something which glues that / listen to events / broadcast events

Imager 0.(2 | 1.1) Release

What to do before releasing:

  • update examples
  • add a CHANGELOG.md
  • update README.md (and mention the CHANGELOG)
  • eventually detail API changes and usage recommendations
  • decide if we bump to 0.2 or 0.1.1

Localize repaints

Instead of injecting a blank placeholder img which in turn is replaced with an actual image - you could use the Fluid Video technique on the element containing the image (maybe keep the .delayed-image-load-div?):

.delayed-image-load {
    position: relative;
}
.delayed-image-load:after {
    display: block;
    content: " ";
    width: 100%;
    padding-bottom: 56.25%;
}
.delayed-image-load > img {
    position: absolute;
}

Position absolute moves elements out of flow and so only needs to repaint the actual area it covers - instead of the entire parent block (or worse) :)

NPM registry conflict with 'imager'

npm install imager installs a different tool:

18:27:22 ~/src/.../conde/cnt-feature-slideshow:data-model-redux ☹
↳ npm show imager

{ name: 'imager',
  description: 'Easy way to resize, crop and upload images to Rackspace cloudfiles and Amazon S3',
  'dist-tags': { latest: '0.2.0' },
  versions:
   [ '0.0.1',
     '0.0.2',
     '0.0.3',
     '0.0.4',
     '0.0.5',
     '0.0.6',
     '0.0.7',
     '0.0.8',
     '0.0.9',
     '0.1.0',
     '0.1.1',
     '0.1.2',
     '0.1.3',
     '0.1.4',
     '0.1.5',
     '0.1.6',
     '0.1.7',
     '0.1.8',
     '0.1.9',
     '0.1.10',
     '0.1.11',
     '0.1.12',
     '0.2.0' ],
  maintainers: 'madhums <[email protected]>',
  time:
   { '0.0.1': '2012-03-03T21:17:20.177Z',
     '0.0.2': '2012-03-03T21:49:36.799Z',
     '0.0.3': '2012-03-03T22:16:39.508Z',
     '0.0.4': '2012-03-04T06:03:05.799Z',
     '0.0.5': '2012-04-26T19:07:48.731Z',
     '0.0.6': '2012-05-28T19:28:58.866Z',
     '0.0.7': '2012-06-03T15:01:45.044Z',
     '0.0.8': '2012-08-04T10:55:26.137Z',
     '0.0.9': '2012-08-11T09:38:04.075Z',
     '0.1.0': '2012-08-24T11:13:51.069Z',
     '0.1.1': '2012-09-08T15:51:28.612Z',
     '0.1.2': '2012-09-08T21:30:57.613Z',
     '0.1.3': '2012-09-25T21:11:19.833Z',
     '0.1.4': '2012-12-10T08:20:29.466Z',
     '0.1.5': '2013-02-19T14:55:46.790Z',
     '0.1.6': '2013-03-06T06:52:56.371Z',
     '0.1.7': '2013-04-20T18:04:15.042Z',
     '0.1.8': '2013-04-20T20:45:49.304Z',
     '0.1.9': '2013-04-22T06:10:30.808Z',
     '0.1.10': '2013-08-31T00:26:21.979Z',
     '0.1.11': '2013-09-10T08:40:51.877Z',
     '0.1.12': '2013-09-17T18:54:34.621Z',
     '0.2.0': '2013-11-14T07:42:08.078Z' },
  author: 'Madhusudhan Srinivasa <[email protected]> (http://madhums.github.com/)',
  repository:
   { type: 'git',
     url: 'git://github.com/madhums/node-imager.git' },
  version: '0.2.0',
  keywords:
   [ 'upload',
     'image',
     'graphicsmagick',
     'imagemagick',
     'rackspace',
     'cloudfiles',
     'resize',
     'file',
     'crop',
     'amazon',
     's3' ],
  homepage: 'https://github.com/madhums/node-imager',
  main: 'index',
  engines: { node: '>= 0.8.x' },
  dependencies:
   { gm: '1.13.x',
     pkgcloud: '0.8.x',
     knox: '0.8.x',
     mime: '1.2.x',
     async: '0.2.x',
     underscore: '1.5.x' },
  devDependencies:
   { mocha: '1.14.x',
     should: '2.1.x',
     express: '3.4.x',
     superagent: '0.15.x' },
  scripts: { test: 'NODE_ENV=test ./node_modules/.bin/mocha --timeout 50000 --reporter spec test/test.js' },
  readmeFilename: 'README.md',
  bugs: { url: 'https://github.com/madhums/node-imager/issues' },
  dist:
   { shasum: '3b44878f39de34880758436bb8086e4e55a62385',
     tarball: 'http://registry.npmjs.org/imager/-/imager-0.2.0.tgz' },
  directories: {} }

Allow smaller image to be downloaded even if a larger version is already available

Art Direction is necessary to optimize legibility (not the proper term, maybe) of small images, when simply resizing a bigger one is not enough.

I know ordinary people don't resize their browsers, but they eventualy turn their smartphones/tablets from landscape to portrait mode, with decreased width for the page.

It would be great to be able to force downloading of a smaller image in this case, either image by image, or globally.

Imager use with single-page application?

I'm looking into converting a section of a site (http://kvdesign.net/work) into a single-page "application" using Backbone.Marionette. This would (I hope!) make it easier to change it into something along the lines of the Google image-search results page.

The current site uses a slightly modified Imager throughout, with the image variations being created and cached dynamically with a custom ExpressionEngine extension/plugin. This part I can bypass easily enough, but would it be best to...

  1. Render the html as originally output and create the default Imager "onrender" and let it do its thing, since the initial DOM would be loaded before the necessary image elements are there, or

  2. Incorporate the Imager's functionality directly into my application code and render the "correct" image from the start, or

  3. Bag the whole Backbone idea and live with some confusing jQuery spaghetti code. ;-)

There seem to be advantages and disadvantages to each, with #1 only having the disadvantage of an additional screen redraw. #2 gets rid of that, but then would require the full Imager anyway to take care of screen rotation, etc, unless I re-rendered the "page" with different image srcs. (Plus I'd have to figure it all out.) #3 is probably the easiest to wrap my head around, but lacks elegance.

I'm not worried about older browsers, since her target audience mostly uses up-to-date hardware and software, including retina-capable stuff. Things just have to look good and have a bit of UI "goodness" that designers and their clients like to see. (The entire site was originally conceived as a single-page, parallax site.)

Any suggestions?

[PROPOSAL] Delaying width calculation and `src` replacement

The intention

Imager replaces the images either on the next Animation Frame or in the next supposed to be frame interval (16.6ms + 4ms w/ setTimeout).

We might not want to replace any src of a same pool at the same pace:

  • orientationchange: after some delay to let the device recalculating right
  • scroll: after the last triggered event (or any third-party has loaded images after a scroll delay)
  • AJAX request: immediately

My concern is Imager should not do too many things outside of its scope (resizing images when asked).

The proposal

This is especially relevant and less head-painful if events are not bundled anymore (cf. #25).

In any case, it will use setTimeout as a fallback if requestAnimationFrame is not available. It will wait the correct amount of Animation Frames

update(optional_delay)

Immediate:

imgr.update();

In 500ms:

imgr.update(500);

When I want:

$(window).on('resize', function(){
  imgr.update(250);
});

$(window).on('load news.updated', function(){
  imgr.update();
});

$(document).bind('scrollstop', function() {
  imgr.update();
});

delay configuration option

var imgr = new Imager({
  delay: 50     //50 ms or 1 frame
});

Wondering what update() without any arguments would mean now or with config delay.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.