momentJS Timer doesn´t work on Firefox - javascript

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.

Related

Why wouldn't this countdown timer show on my mobile?

I have some Javascript that is basically a countdown timer:
<script>
var clockRunning = false;
var clockPlaceholder = document.getElementById("clock-placeholder");
var targetDate;
var clock;
function updateClock() {
var cd = countdown(targetDate, null, countdown.DAYS | countdown.HOURS | countdown.MINUTES | countdown.SECONDS, 4);
clockPlaceholder.innerHTML = cd.toString();
if (targetDate.getTime() < (new Date()).getTime()) {
endCountdown();
}
}
function startCountdown() {
if (clockRunning == false) {
var h, m, s;
// setup target Date object
var now = new Date(); // console.debug(now.toString());
var laravelTime = '{{ $auction->endtime }}';
targetDate = new Date(laravelTime);
// start clock
clock = setInterval(updateClock, 1000);
clockRunning = true;
}
}
function endCountdown() {
clockPlaceholder.innerHTML = "Auction Ended"
clearInterval(clock);
clockRunning = false;
}
</script>
This line: var laravelTime = '{{ $auction->endtime }}'; just gets the endtime from the DB.
Anyway, it works perfectly on my computer but when I browse to the page on my mobile phone (iOS) it doesn't appear at all. Neither Safari nor Chrome shows it.
I'm quite new to js. Any help would be appreciated!

JS mini-game in grid, browser frozen after first replication

I'm trying to create a small game that replicate neighbors cells in a grid. I use a web worker that draw replicate cells every seconds. I'm able to replicate the first second. If my initial cell is row3col3, the new replicated cells will be :
row3col2, row3col4
row2col3, row4col3
The problem is, after the first second (and the replication), the game freezes, and i'm not able to do something. Can't click on cells, etc.
EDIT : After few seconds, it go to '00:02' but Chrome crashed "Aw, Snap! Something went wrong...' [RELOAD]
EDIT 2 : After looking on the memory used, It appears I have an memory overflow, 16000 Mb ! My method is bad, so.
I know my code is not really optimised, and I think that is the problem. Unfortunatly, i'm not able to do more efficient code, so I ask some help to you guys, to give me some ways to explore.
Here the code :
var lastClicked;
var cellTab = Array();
var replicant = Array();
var newReplicant = Array();
var count = 5;
var rows = 20;
var cols = 20;
var randomRow = Math.floor((Math.random() * rows));
var randomCol = Math.floor((Math.random() * cols));
var grid = clickableGrid(rows, cols,randomRow,randomCol,cellTab, function(el,row,col,i){
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
console.log("You clicked on item #:",i);
$(el).addClass('clicked');
lastClicked = el;
});
document.getElementById("game").appendChild(grid);
function clickableGrid( rows, cols, randomRow, randomCol, cellTab, callback ){
var i=0;
var grid = document.createElement('table');
grid.className = 'grid';
for (var r=0;r<rows;++r){
var tr = grid.appendChild(document.createElement('tr'));
for (var c=0;c<cols;++c){
var cell = tr.appendChild(document.createElement('td'));
$(cell).addClass('row'+r+'col'+c);
if(randomCol == c && randomRow == r)
{
storeCoordinate(r, c, replicant);
$(cell).css('background', '#000000');
}
storeCoordinate(r, c, cellTab);
cell.addEventListener('click',(function(el,r,c,i){
return function(){
callback(el,r,c,i);
}
})(cell,r,c,i),false);
}
}
return grid;
}
function storeCoordinate(xVal, yVal, array)
{
array.push({x: xVal, y: yVal});
}
function replicate(replicant)
{
for (var i = 0; i < replicant.length; i++) {
console.log(replicant);
var supRowX = replicant[i].x-1;
var supRowY = replicant[i].y;
storeCoordinate(supRowX, supRowY, newReplicant);
var subRowX = replicant[i].x+1;
var subRowY = replicant[i].y;
storeCoordinate(subRowX, subRowY, newReplicant);
var supColsX = replicant[i].x;
var supColsY = replicant[i].y-1;
storeCoordinate(supColsX, supColsY, newReplicant);
var subColsX = replicant[i].x;
var subColsY = replicant[i].y+1;
storeCoordinate(subColsX, subColsY, newReplicant);
}
}
function drawReplicant(replicant, cellTab)
{
for (var i = 0; i < replicant.length; i++) {
if($.inArray(replicant[i], cellTab))
{
$('.row'+replicant[i].x+'col'+replicant[i].y).css('background', '#000000');
}
}
}
var w = null; // initialize variable
// function to start the timer
function startTimer()
{
// First check whether Web Workers are supported
if (typeof(Worker)!=="undefined"){
// Check whether Web Worker has been created. If not, create a new Web Worker based on the Javascript file simple-timer.js
if (w==null){
w = new Worker("w.countdown.js");
}
// Update timer div with output from Web Worker
w.onmessage = function (event) {
document.getElementById("timer").innerHTML = event.data;
console.log(event.data);
replicate(replicant);
replicant = newReplicant;
drawReplicant(replicant, cellTab);
};
} else {
// Web workers are not supported by your browser
document.getElementById("timer").innerHTML = "Sorry, your browser does not support Web Workers ...";
}
}
// function to stop the timer
function stopTimer()
{
w.terminate();
timerStart = true;
w = null;
}
startTimer();
And here, the web worker :
var timerStart = true;
function myTimer(d0)
{
// get current time
var d=(new Date()).valueOf();
// calculate time difference between now and initial time
var diff = d-d0;
// calculate number of minutes
var minutes = Math.floor(diff/1000/60);
// calculate number of seconds
var seconds = Math.floor(diff/1000)-minutes*60;
var myVar = null;
// if number of minutes less than 10, add a leading "0"
minutes = minutes.toString();
if (minutes.length == 1){
minutes = "0"+minutes;
}
// if number of seconds less than 10, add a leading "0"
seconds = seconds.toString();
if (seconds.length == 1){
seconds = "0"+seconds;
}
// return output to Web Worker
postMessage(minutes+":"+seconds);
}
if (timerStart){
// get current time
var d0=(new Date()).valueOf();
// repeat myTimer(d0) every 100 ms
myVar=setInterval(function(){myTimer(d0)},1000);
// timer should not start anymore since it has been started
timerStart = false;
}
Maybe it's because I use jQuery ?

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);

Javascript only works in IE Quirks, 7 and Chrome and Firefox. Doesn't work in IE 8 or 9 Standards

My code makes a number of divisions appear to orbit around an invisible horizontal axis on a plane. How it works: it fires a mouseevent listener onMouseDown, and captures the X of the user's cursor relative to the window. onMouseUp is simulated by a setTimeout function that is called 90 milliseconds later, it does the same and then subtracts the two values to determine the distance and direction to spin.
My question is: Why does it work correctly in FF, Chrome, and IE Quirks and IE 7 Standards, but not IE 8 Standards or IE 9 Standards?
IE8: the model breaks down and the divisons float away outside the containing boundary division. IE9: No response from the JS whatsoever.
The following contains the entire javascript on the page, which can be found # http://electrifiedpulse.com/360.html :
<script type=text/javascript>
var objectCount = 8; var pixel = new Array(); var size = new Array();
var command = "Stop"; var panel = new Array('0','Back','Front','Front','Back','Front','Back','Front','Back');
var quadrant = new Array(); var originalSize = 50;
var WindowWidth = 360; var WindowWidthHalf = WindowWidth/2; var sTime=0; var s1=0; var scrollSpeed;
var myX, myY;
function myMove(evt) {
if (window.event){myX = event.clientX;myY = event.clientY;}
else{myX = evt.clientX;myY = evt.clientY;}
}
document.onmousemove = myMove;
if (!window.event) {document.captureEvents(Event.MOUSEMOVE);}
function iScrollStop(){
sTime = sTime - 10;
document.getElementById('I_CONTROLS').innerHTML = sTime + ", " + scrollSpeed;
if(sTime<=0) command = "Stop";
else setTimeout(function(){iScrollStop()},10);
}
function iScrollPause(){
setTimeout(function(){this.checkPause()},100);
this.checkPause = function(){if(s1>sTime){command="Stop"; sTime=0; s1=0;}}
}
var iInitialX; //var d='Up';
function iScrollListen(d){
if(d=='Down'){ iInitialX = myX; setTimeout(function(){iScrollListen('Up')},90); iScrollPause();
}else if(d=='Up'){
var spinDirection = 'Right';
var iDifference = myX - iInitialX; if(iDifference < 0){ spinDirection = 'Left'; iDifference = Math.abs(iDifference);}
if (command!=spinDirection){sTime=0;s1=0;} var doScroll=0; if(command=='Stop') doScroll=1;
command = spinDirection; s1=sTime; sTime+=(iDifference*15); if(s1<=0)iScrollStop();
if(doScroll==1) iScroll();
}
}
function iScrollControl(c){command = c; if((c=='Left')||(c=='Right')) iScroll();}
function iScroll(){
scrollSpeed=(sTime<=1)? 1 : Math.ceil(sTime/1000);
if(scrollSpeed>=10)scrollSpeed=10;
scrollSpeed = 15 - scrollSpeed;
if(command=='Left') pixelDirection=2;
else if(command=='Right') pixelDirection=(0-2);
pixelDirectionNeg = (0-pixelDirection);
for(i=1;i<=objectCount;i++){
iObj = document.getElementById("iObject" + i);
pixel[i] = iObj.offsetLeft;
if((pixel[i]>=WindowWidthHalf)&&(pixel[i]<=WindowWidth)){
if(panel[i]=="Front") quadrant[i] = 4;
else quadrant[i] = 3;
}
if((pixel[i]>=0)&&(pixel[i]<=WindowWidthHalf)){
if(panel[i]=="Front") quadrant[i] = 1;
else quadrant[i] = 2;
}
if(quadrant[i]==1){
iObj.style.left = pixel[i]-pixelDirection;
size[i] = (pixel[i]-pixelDirection)*(1/(WindowWidthHalf/(originalSize/2))) + (originalSize/2);
Attribute(iObj,size[i]);
if(pixel[i]-pixelDirection<=0){quadrant[i]=2; panel[i]='Back';}
if(pixel[i]-pixelDirection>=WindowWidthHalf){quadrant[i]=4; panel[i]='Front';}
}
if(quadrant[i]==2){
iObj.style.left = pixel[i]-pixelDirectionNeg;
size[i] = (pixel[i]-pixelDirectionNeg)*(-1/(WindowWidthHalf/(originalSize/2))) + (originalSize/2);
Attribute(iObj,size[i]);
if(pixel[i]-pixelDirectionNeg<=0){quadrant[i]=1; panel[i]='Front';}
if(pixel[i]-pixelDirectionNeg>=WindowWidthHalf){quadrant[i]=3; panel[i]='Back';}
}
if(quadrant[i]==3){
iObj.style.left = pixel[i]-pixelDirectionNeg;
size[i] = (WindowWidth-(pixel[i]-pixelDirectionNeg))*(-1/(WindowWidthHalf/(originalSize/2))) + (originalSize/2);
Attribute(iObj,size[i]);
if(pixel[i]-pixelDirectionNeg<=WindowWidthHalf){quadrant[i]=2; panel[i]='Back';}
if(pixel[i]-pixelDirectionNeg>=WindowWidth){quadrant[i]=4; panel[i]='Front';}
}
if(quadrant[i]==4){
iObj.style.left = pixel[i]-pixelDirection;
size[i] = (WindowWidth-(pixel[i]-pixelDirection))*(1/(WindowWidthHalf/(originalSize/2))) + (originalSize/2);
Attribute(iObj,size[i]);
if(pixel[i]-pixelDirection<=WindowWidthHalf){quadrant[i]=1; panel[i]='Front';}
if(pixel[i]-pixelDirection>=WindowWidth){quadrant[i]=3; panel[i]='Back';}
}
}
if((command=='Left')||(command=='Right')) setTimeout(function(){iScroll()},scrollSpeed);
}
function Attribute(iObj,s){
iObj.style.width = s; iObj.style.height = s; iObj.style.top='50%'; iObj.style.marginTop = (0-(s/2))+"px"; iObj.style.zIndex = s;
}
</script>
I don't know what may or may not be relevant to you, so I included the entire script. If you want you could ignore the longest function,
iScroll()
#RyanStortz. Try to register events in this maner:
var isMouseCaptured=false;
function i_boundary_mousedown(ev) {
isMouseCaptured=true;
iScrollListen("Down");
}
function doc_mousemove(ev) {
if(isMouseCaptured) {
ev=ev||event;
myX=ev.clientX;
myY=ev.clientY;
}
}
function doc_mouseup(ev) {
if(isMouseCaptured) {
isMouseCaptured=false;
ev=ev||event;
myX=ev.clientX;
myY=ev.clientY;
}
}
var i_boundaryObj=document.getElementById('I_BOUNDARY');
if(window.addEventListener) {
i_boundaryObj.addEventListener('mousedown',i_boundary_mousedown,false);
document.addEventListener('mousemove',doc_mousemove,false);
document.addEventListener('mouseup',doc_mouseup,false)
}
else if(window.attachEvent) {
i_boundaryObj.attachEvent('onmousedown',i_boundary_mousedown)
document.attachEvent('onmousemove',doc_mousemove);
document.attachEvent('onmouseup',doc_mouseup)
}
else ;//
Add for DIV with class "I_BOUNDARY" id attribute "I_BOUNDARY" and remove onmousedown attribute.

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