diff --git a/src/components/img/img.ts b/src/components/img/img.ts
index b928f2da93..244e5eace7 100644
--- a/src/components/img/img.ts
+++ b/src/components/img/img.ts
@@ -8,7 +8,89 @@ import { Platform } from '../../platform/platform';
/**
- * @private
+ * @name Img
+ * @description
+ * Two of the biggest cuprits of scrolling jank is starting up a new
+ * HTTP request, and rendering images. These two reasons is largely why
+ * `ion-img` was created and the problems which it is helping to solve.
+ * The standard `
` element is often a large source of these problems,
+ * and what makes matters worse is that the app does not have fine-grained
+ * control of each img element.
+ *
+ * The `ion-img` component is similar to the standard `
` element,
+ * but it also adds features in order to provide improved performance.
+ * Features include only loading images which are visible, using web workers
+ * for HTTP requests, preventing jank while scrolling and in-memory caching.
+ *
+ * Note that `ion-img` also comes with a few more restrictions in comparison to
+ * the standard `
` element. A good rule is, if there are only a few images
+ * to be rendered on one page, then the standard `
` may be best. However, if
+ * a page has the potential for hundreds or even thousands of images within a
+ * scrollable area, then `ion-img` would be better suited for the job.
+ *
+ *
+ * ### Lazy Loading
+ *
+ * Lazy loading images refers to only loading images which are actually
+ * visible within the user's viewport. This also means that images which are
+ * not viewable on the initial load would not be downloaded. Next, as the user
+ * scrolls down, each image which becomes visible is then loaded on-demand.
+ *
+ * The benefits of this approach is that unnecessary HTTP requests are not
+ * started and valuable bandwidth wasted, and to free up browser resources
+ * which would be wasted on images which are not even viewable. For example,
+ * animated GIFs are enourmous performance drains, however, with `ion-img`
+ * the app is able to dedicate resources to just the viewable images.
+ *
+ *
+ * ### Image Dimensions
+ *
+ * By providing image dimensions up front, Ionic is able to accurately size
+ * up the image's location within the viewport, which helps lazy load only
+ * images which are viewable. Image dimensions can either by set as properties,
+ * inline styles, or stylesheets. It doesn't matter which method of setting
+ * dimensions is used, but it's important that somehow each `ion-img`
+ * has been given an exact size.
+ *
+ * For example, by default `` and `` already come
+ * with exact sizes when placed within ``. By giving each image an
+ * exact size, this then further locks in the size of each `ion-item`, which
+ * again helps improve scroll performance.
+ *
+ * @usage
+ * ```html
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * ```
+ *
+ *
+ * ### Web Worker and XHR Requests
+ *
+ * Another big cause of scroll jank is kicking off a new HTTP request, which
+ * is exactly what images do. Normally, this isn't a problem for something like
+ * a blog since all image HTTP requests are started immediately as HTML
+ * parses. However, Ionic has the ability to include hundreds to thousands of
+ * images within one page, but we're not actually loading all of the images at once.
+ *
+ * Imagine an app where users can slowly, or quickly, scroll through hundreds of
+ * images. If they're scrolling extremely fast, the app wouldn't want to start all of
+ * those requests, but if they're scrolling slowly they would. Additionally, it's
+ * most browsers can only have six requests at one time for the same domain, so
+ * it's extemely important that we're managing which images we should downloading.
+ *
+ * By place XMLHttpRequest within a web worker, we're able to pass off the heavy
+ * lifting to another thread. Not only are able to take the load of the main thread,
+ * but we're also able to accurately control exactly which images should be
+ * downloading, along with the ability to abort unnecessary requests. Aborting
+ * requets is just as important so that Ionic can free up connections for the most
+ * important images which are visible.
+ *
*/
@Component({
selector: 'ion-img',
@@ -28,10 +110,6 @@ export class Img implements OnDestroy {
/** @internal */
_cache: boolean = true;
/** @internal */
- _lazy: boolean = true;
- /** @internal */
- _ww: boolean = true;
- /** @internal */
_cb: Function;
/** @internal */
_bounds: any;
@@ -69,6 +147,9 @@ export class Img implements OnDestroy {
this._isLoaded(false);
}
+ /**
+ * @input {string} Image src.
+ */
@Input()
get src(): string {
return this._src;
@@ -87,6 +168,9 @@ export class Img implements OnDestroy {
}
}
+ /**
+ * @private
+ */
reset() {
if (this._requestingSrc) {
// abort any active requests
@@ -102,6 +186,9 @@ export class Img implements OnDestroy {
}
}
+ /**
+ * @private
+ */
update() {
if (this._src && this._content.isImgsRefreshable()) {
if (this.canRequest && (this._src !== this._renderedSrc && this._src !== this._requestingSrc) && !this._tmpDataUri) {
@@ -132,10 +219,7 @@ export class Img implements OnDestroy {
}
}
- /**
- * @internal
- */
- _loadResponse(msg: ImgResponseMessage) {
+ private _loadResponse(msg: ImgResponseMessage) {
this._requestingSrc = null;
if (msg.status === 200) {
@@ -201,6 +285,11 @@ export class Img implements OnDestroy {
return this._rect;
}
+ /**
+ * @input {any} Sets the bounding rectangle of the element relative to the viewport.
+ * When using `VirtualScroll`, each virtual item should pass its bounds to each
+ * `ion-img`.
+ */
@Input()
set bounds(b: any) {
if (isPresent(b)) {
@@ -208,22 +297,12 @@ export class Img implements OnDestroy {
}
}
- @Input()
- get lazyLoad(): boolean {
- return this._lazy;
- }
- set lazyLoad(val: boolean) {
- this._lazy = isTrueProperty(val);
- }
-
- @Input()
- get webWorker(): boolean {
- return this._ww;
- }
- set webWorker(val: boolean) {
- this._ww = isTrueProperty(val);
- }
-
+ /**
+ * @input {boolean} After an image has been successfully downloaded, it can be cached
+ * in-memory. This is useful for `VirtualScroll` by allowing image responses to be
+ * cached, and not rendered, until after scrolling has completed, which allows for
+ * smoother scrolling.
+ */
@Input()
get cache(): boolean {
return this._cache;
@@ -232,19 +311,27 @@ export class Img implements OnDestroy {
this._cache = isTrueProperty(val);
}
+ /**
+ * @input {string} Image width. If this property is not set it's important that
+ * the dimensions are still set using CSS.
+ */
@Input()
set width(val: string | number) {
this._wQ = getUnitValue(val);
this._setDims();
}
+ /**
+ * @input {string} Image height. If this property is not set it's important that
+ * the dimensions are still set using CSS.
+ */
@Input()
set height(val: string | number) {
this._hQ = getUnitValue(val);
this._setDims();
}
- _setDims() {
+ private _setDims() {
if (this.canRender && (this._w !== this._wQ || this._h !== this._hQ)) {
var wrapperEle: HTMLImageElement = this._elementRef.nativeElement;
var renderer = this._renderer;
@@ -263,7 +350,8 @@ export class Img implements OnDestroy {
}
/**
- * Set the `alt` attribute on the inner `img` element.
+ * @input {string} Set the `alt` attribute which gets assigned to
+ * the inner `img` element.
*/
@Input() alt: string = '';