-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
120 lines (97 loc) · 2.79 KB
/
index.js
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
export default class OverlookerElementTiming {
constructor(propName = 'oet', wnd = window) {
this.observers = [];
this.timings = [];
this.wnd = wnd;
if (!this.wnd[propName]) {
this.wnd[propName] = [];
}
if (!(this.wnd[propName] instanceof OverlookerElementTiming)) {
if (this.wnd[propName].forEach instanceof Function) {
this.wnd[propName].forEach(this._prepareEntry.bind(this));
}
this.wnd[propName] = this;
} else {
this.wnd[propName].observe((entry) => this.push(entry));
}
}
_fireObservers(entry) {
this.timings.push(entry);
this.observers.forEach((cb) => cb(entry));
}
_calcVisibility(viewportSize, position, size) {
if (position > 0) {
return viewportSize - (position + size) >= 0 ? size : Math.max(viewportSize - position, 0);
} else if (position < 0) {
return Math.abs(position) > size ? 0 : size + position;
} else {
return viewportSize > size ? size : viewportSize;
}
}
_prepareEntry(rawEntry) {
const {
name,
startTime,
renderTime,
loadTime,
intersectionRect,
identifier,
naturalWidth,
naturalHeight,
url
} = rawEntry;
const timingEntries = this.wnd.performance.getEntriesByName(url);
const timingEntry = timingEntries && timingEntries.length ? timingEntries[0].toJSON() : null;
const { innerHeight, innerWidth } = this.wnd;
const {
x,
y,
width: intersectWidth,
height: intersectHeight
} = intersectionRect;
const height = naturalHeight || intersectHeight;
const width = naturalWidth || intersectWidth;
const visibleHeight = this._calcVisibility(innerHeight, y, height);
const visibleWidth = this._calcVisibility(innerWidth, x, width);
const totalPixels = width * height;
const visiblePixels = visibleWidth * visibleHeight;
const visiblePercent = totalPixels ? visiblePixels / totalPixels : 0;
const fetchStart = timingEntry ? timingEntry.fetchStart : startTime;
const load = timingEntry ? timingEntry.responseEnd : loadTime;
const entry = {
type: name,
name: identifier,
view: {
visiblePercent: visiblePercent,
height,
width
},
timings: name === 'image-paint' ? {
fetchStart,
load,
render: loadTime
} : {
render: renderTime
}
};
this._fireObservers(entry);
}
push(...entries) {
entries.forEach(this._prepareEntry.bind(this));
}
getAll() {
return this.timings;
}
clear() {
this.timings = [];
}
observe(cb, buffered) {
if (buffered) {
this.timings.forEach((timing) => cb(timing));
}
this.observers.push(cb);
}
unobserve(cb) {
this.observers = this.observers.filter((c) => c !== cb);
}
}