-
Notifications
You must be signed in to change notification settings - Fork 143
/
lazyload-image.ts
83 lines (77 loc) 路 2.99 KB
/
lazyload-image.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/mergeMap';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/of';
import { Observable } from 'rxjs/Observable';
import { getScrollListener } from './scroll-listener';
function isVisible(element: HTMLElement, threshold = 0, _window = window) {
const rect = element.getBoundingClientRect();
// Is the element in viewport but larger then viewport itself
const elementLargerThenViewport = rect.top <= threshold && rect.bottom >= -threshold;
// Is the top of the element in the viewport
const topInsideViewport = rect.top >= 0 && rect.top <= _window.innerHeight;
// Is the bottom of the element in the viewport
const belowInsideViewport = rect.bottom >= 0 && rect.bottom <= _window.innerHeight;
// Is the right side of the element in the viewport
const rightsideInViewport = rect.right >= -threshold && (rect.right - threshold) <= _window.innerWidth;
// Is the left side of the element is the viewport
const leftsideInViewport = rect.left >= -threshold && (rect.left - threshold) <= _window.innerWidth;
return (
elementLargerThenViewport ||
((topInsideViewport || belowInsideViewport) &&
(rightsideInViewport || leftsideInViewport))
);
}
function loadImage(imagePath: string): Observable<HTMLImageElement> {
return Observable
.create(observer => {
const img = new Image();
img.src = imagePath;
img.onload = () => {
observer.next(imagePath);
observer.complete();
};
img.onerror = err => {
observer.error(null);
};
});
}
function setImage(element: HTMLElement, imagePath: string) {
const isImgNode = element.nodeName.toLowerCase() === 'img';
if (isImgNode) {
(<HTMLImageElement>element).src = imagePath;
} else {
element.style.backgroundImage = `url('${imagePath}')`;
}
return element;
}
function setLoadedStyle(element: HTMLElement) {
const styles = element.className
.split(' ')
.filter(s => !!s)
.filter(s => s !== 'ng-lazyloading');
styles.push('ng-lazyloaded');
element.className = styles.join(' ');
return element;
}
export function lazyLoadImage(image: HTMLElement, imagePath: string, defaultImagePath: string, errorImgPath: string, offset: number) {
if (defaultImagePath) {
setImage(image, defaultImagePath);
}
return (scrollObservable: Observable<Event>) => {
return scrollObservable
.filter(() => isVisible(image, offset))
.take(1)
.mergeMap(() => loadImage(imagePath))
.do(() => setImage(image, imagePath))
.catch(() => {
if (errorImgPath) {
setImage(image, errorImgPath);
}
return Observable.of(1);
})
.do(() => setLoadedStyle(image));
};
}