forked from 1Marc/hisrc
-
Notifications
You must be signed in to change notification settings - Fork 63
/
hisrc.js
273 lines (229 loc) · 8.73 KB
/
hisrc.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
/*
* Hisrc jQuery Plugin
*
* Copyright (c) 2012
* Licensed under the MIT license.
*
*/
(function($){
$.hisrc = {
bandwidth: null,
connectionTestResult: null,
connectionKbps: null,
connectionType: null,
devicePixelRatio: null
};
$.hisrc.defaults = {
useTransparentGif: false,
transparentGifSrc: 'data:image/gif;base64,R0lGODlhAQABAIAAAMz/AAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==',
minKbpsForHighBandwidth: 300,
speedTestUri: '50K.jpg',
speedTestKB: 50,
speedTestExpireMinutes: 30,
forcedBandwidth: false,
srcIsLowResolution: true
};
// for performance, run this right away (requires jQuery, but no need to wait for DOM to be ready)
$.hisrc.speedTest = function(options) {
$(window).hisrc(options);
};
$.fn.hisrc = function(options) {
var settings = $.extend({
callback: function() {}
}, $.hisrc.defaults, options),
$els = $(this),
// check bandwidth via @Modernizr's network-connection.js
connection = navigator.connection || { type: 0 }, // polyfill
isSlowConnection = connection.type == 3
|| connection.type == 4
|| /^[23]g$/.test(connection.type);
// get pixel ratio
$.hisrc.devicePixelRatio = 1;
if(window.devicePixelRatio !== undefined) {
$.hisrc.devicePixelRatio = window.devicePixelRatio;
} else if (window.matchMedia !== undefined) {
for (var i = 1; i <= 2; i += 0.5) {
if (window.matchMedia('(min-resolution: ' + i + 'dppx)').matches) {
$.hisrc.devicePixelRatio = i;
}
}
}
// variables/functions below for speed test are taken from Foresight.js
// Copyright (c) 2012 Adam Bradley
// Licensed under the MIT license.
// https://github.com/adamdbradley/foresight.js
// Modified by Christopher Deutsch for hisrc.js
var speedTestUri = settings.speedTestUri,
STATUS_LOADING = 'loading',
STATUS_COMPLETE = 'complete',
LOCAL_STORAGE_KEY = 'fsjs', // may as well piggy-back on Forsight localstorage key since we're doing the same thing.
speedConnectionStatus,
initSpeedTest = function () {
// only check the connection speed once, if there is a status then we've
// already got info or it already started
if ( speedConnectionStatus ) {
return;
}
// force that this device has a low or high bandwidth, used more so for debugging purposes
if ( settings.forcedBandwidth ) {
$.hisrc.bandwidth = settings.forcedBandwidth;
$.hisrc.connectionTestResult = 'forced';
speedConnectionStatus = STATUS_COMPLETE;
$els.trigger('speedTestComplete.hisrc');
return;
}
// if the device pixel ratio is 1, then no need to do a network connection
// speed test since it can't show hi-res anyways
if ( $.hisrc.devicePixelRatio === 1 ) {
$.hisrc.connectionTestResult = 'skip';
speedConnectionStatus = STATUS_COMPLETE;
$els.trigger('speedTestComplete.hisrc');
return;
}
// if we know the connection is 2g or 3g
// don't even bother with the speed test, cuz its slow
// Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
// Available under the BSD and MIT licenses: www.modernizr.com/license/
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/network-connection.js
// Modified by Adam Bradley for Foresight.js
$.hisrc.connectionType = connection.type;
if ( isSlowConnection ) {
// we know this connection is slow, don't bother even doing a speed test
$.hisrc.connectionTestResult = 'connTypeSlow';
speedConnectionStatus = STATUS_COMPLETE;
$els.trigger('speedTestComplete.hisrc');
return;
}
// check if a speed test has recently been completed and its
// results are saved in the local storage
try {
var fsData = JSON.parse( localStorage.getItem( LOCAL_STORAGE_KEY ) );
if ( fsData !== null ) {
if ( ( new Date() ).getTime() < fsData.exp ) {
// already have connection data within our desired timeframe
// use this recent data instead of starting another test
$.hisrc.bandwidth = fsData.bw;
$.hisrc.connectionKbps = fsData.kbps;
$.hisrc.connectionTestResult = 'localStorage';
speedConnectionStatus = STATUS_COMPLETE;
$els.trigger('speedTestComplete.hisrc');
return;
}
}
} catch( e ) { }
var
speedTestImg = document.createElement( 'img' ),
endTime,
startTime,
speedTestTimeoutMS;
speedTestImg.onload = function () {
// speed test image download completed
// figure out how long it took and an estimated connection speed
endTime = ( new Date() ).getTime();
var duration = ( endTime - startTime ) / 1000;
duration = ( duration > 1 ? duration : 1 ); // just to ensure we don't divide by 0
$.hisrc.connectionKbps = ( ( settings.speedTestKB * 1024 * 8 ) / duration ) / 1024;
$.hisrc.bandwidth = ( $.hisrc.connectionKbps >= settings.minKbpsForHighBandwidth ? 'high' : 'low' );
speedTestComplete( 'networkSuccess' );
};
speedTestImg.onerror = function () {
// fallback incase there was an error downloading the speed test image
speedTestComplete( 'networkError', 5 );
};
speedTestImg.onabort = function () {
// fallback incase there was an abort during the speed test image
speedTestComplete( 'networkAbort', 5 );
};
// begin the network connection speed test image download
startTime = ( new Date() ).getTime();
speedConnectionStatus = STATUS_LOADING;
if ( document.location.protocol === 'https:' ) {
// if this current document is SSL, make sure this speed test request
// uses https so there are no ugly security warnings from the browser
speedTestUri = speedTestUri.replace( 'http:', 'https:' );
}
speedTestImg.src = speedTestUri + "?r=" + Math.random();
// calculate the maximum number of milliseconds it 'should' take to download an XX Kbps file
// set a timeout so that if the speed test download takes too long
// than it isn't a 'high-bandwidth' and ignore what the test image .onload has to say
// this is used so we don't wait too long on a speed test response
// Adding 350ms to account for TCP slow start, quickAndDirty === TRUE
speedTestTimeoutMS = ( ( ( settings.speedTestKB * 8 ) / settings.minKbpsForHighBandwidth ) * 1000 ) + 350;
setTimeout( function () {
speedTestComplete( 'networkSlow' );
}, speedTestTimeoutMS );
},
speedTestComplete = function ( connTestResult, expireMinutes ) {
// if we haven't already gotten a speed connection status then save the info
if (speedConnectionStatus === STATUS_COMPLETE) { return; }
// first one with an answer wins
speedConnectionStatus = STATUS_COMPLETE;
$.hisrc.connectionTestResult = connTestResult;
try {
if ( !expireMinutes ) {
expireMinutes = settings.speedTestExpireMinutes;
}
var fsDataToSet = {
kbps: $.hisrc.connectionKbps,
bw: $.hisrc.bandwidth,
exp: ( new Date() ).getTime() + (expireMinutes * 60000)
};
localStorage.setItem( LOCAL_STORAGE_KEY, JSON.stringify( fsDataToSet ) );
} catch( e ) { }
// trigger swap once speedtest is complete.
$els.trigger('speedTestComplete.hisrc');
},
setImageSource = function ( $el, src ) {
if ( settings.useTransparentGif ) {
$el.attr('src', settings.transparentGifSrc)
.css('max-height', '100%')
.css('max-width', '100%')
.css('background', 'url("' + src + '") no-repeat 0 0')
.css('background-size', 'contain');
} else {
$el.attr( 'src', src );
}
};
settings.callback.call(this);
$els.each(function(){
var $el = $(this);
var src = $el.attr('src');
if (src) {
if (!$el.data('m1src')) {
$el.data('m1src', src);
}
$el.on('speedTestComplete.hisrc', function(){
if (speedConnectionStatus === STATUS_COMPLETE) {
if (isSlowConnection) {
$el.attr( 'src', $el.data('m1src') );
} else {
// check if client can get high res image
if ($.hisrc.devicePixelRatio > 1 && $.hisrc.bandwidth === 'high') {
var image2x = $el.data('2x');
if (!image2x) {
// use naming convention.
image2x = $el.data('m1src').replace(/\.\w+$/, function(match) { return "@2x" + match; });
}
setImageSource( $el, image2x );
} else {
// don't load 1x unless src is a low res version.
if (settings.srcIsLowResolution) {
var image1x = $el.data('1x');
if (!image1x) {
// use naming convention.
image1x = $el.data('m1src').replace(/\.\w+$/, function(match) { return "@1x" + match; });
}
setImageSource( $el, image1x );
}
}
}
// turn off so hisrc() can be called many times on same element.
$el.off('speedTestComplete.hisrc');
}
});
}
});
initSpeedTest();
return $els;
};
})(jQuery);