Use default html assets

This commit is contained in:
Maddie Zhan 2021-09-27 11:11:08 +08:00
parent 42cc7740a5
commit 2583e5113a
11 changed files with 2688 additions and 995 deletions

View File

@ -0,0 +1,490 @@
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<meta charset="UTF-8" />
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i){return document.getElementById(i);}
//LIST OF TEST SERVERS. See documentation for details if needed
var SPEEDTEST_SERVERS=[
{ //this server doesn't actually exist, remove it
name:"Example Server 1", //user friendly name for the server
server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
},
{ //this server doesn't actually exist, remove it
name:"Example Server 2", //user friendly name for the server
server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
}
//add other servers here, comma separated
];
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
s.setParameter("telemetry_level","basic"); //enable telemetry
//SERVER AUTO SELECTION
function initServers(){
var noServersAvailable=function(){
I("message").innerHTML="No servers available";
}
var runServerSelect=function(){
s.selectServer(function(server){
if(server!=null){ //at least 1 server is available
I("loading").className="hidden"; //hide loading message
//populate server list for manual selection
for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
var option=document.createElement("option");
option.value=i;
option.textContent=SPEEDTEST_SERVERS[i].name;
if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
I("server").appendChild(option);
}
//show test UI
I("testWrapper").className="visible";
initUI();
}else{ //no servers are available, the test cannot proceed
noServersAvailable();
}
});
}
if(typeof SPEEDTEST_SERVERS === "string"){
//need to fetch list of servers from specified URL
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
if(servers==null){ //failed to load server list
noServersAvailable();
}else{ //server list loaded
SPEEDTEST_SERVERS=servers;
runServerSelect();
}
});
}else{
//hardcoded server list
s.addTestPoints(SPEEDTEST_SERVERS);
runServerSelect();
}
}
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
var dlColor="#6060AA",
ulColor="#616161";
var progColor=meterBk;
//CODE FOR GAUGES
function drawMeter(c,amount,bk,fg,progress,prog){
var ctx=c.getContext("2d");
var dp=window.devicePixelRatio||1;
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
var sizScale=ch*0.0055;
if(c.width==cw&&c.height==ch){
ctx.clearRect(0,0,cw,ch);
}else{
c.width=cw;
c.height=ch;
}
ctx.beginPath();
ctx.strokeStyle=bk;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=fg;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
ctx.stroke();
if(typeof progress !== "undefined"){
ctx.fillStyle=prog;
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
}
}
function mbpsToAmount(s){
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
}
function format(d){
d=Number(d);
if(d<10) return d.toFixed(2);
if(d<100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData=null;
function startStop(){
if(s.getState()==3){
//speedtest is running, abort
s.abort();
data=null;
I("startStopBtn").className="";
I("server").disabled=false;
initUI();
}else{
//test is not running, begin
I("startStopBtn").className="running";
I("shareArea").style.display="none";
I("server").disabled=true;
s.onupdate=function(data){
uiData=data;
};
s.onend=function(aborted){
I("startStopBtn").className="";
I("server").disabled=false;
updateUI(true);
if(!aborted){
//if testId is present, show sharing panel, otherwise do nothing
try{
var testId=uiData.testId;
if(testId!=null){
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
I("resultsImg").src=shareURL;
I("resultsURL").value=shareURL;
I("testId").innerHTML=testId;
I("shareArea").style.display="";
}
}catch(e){}
}
};
s.start();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced){
if(!forced&&s.getState()!=3) return;
if(uiData==null) return;
var status=uiData.testState;
I("ip").textContent=uiData.clientIp;
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
I("pingText").textContent=format(uiData.pingStatus);
I("jitText").textContent=format(uiData.jitterStatus);
}
function oscillate(){
return 1+0.02*Math.sin(Date.now()/100);
}
//update the UI every frame
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
function frame(){
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI(){
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#loading{
background-color:#FFFFFF;
color:#404040;
text-align:center;
}
span.loadCircle{
display:inline-block;
width:2em;
height:2em;
vertical-align:middle;
background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
background-size:2em 2em;
margin-right:0.5em;
animation: spin 0.6s linear infinite;
}
@keyframes spin{
0%{transform:rotate(0deg);}
100%{transform:rotate(359deg);}
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#serverArea{
margin-top:1em;
}
#server{
font-size:1em;
padding:0.2em;
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:16em;
height:12.5em;
position:relative;
box-sizing:border-box;
}
div.testArea2{
display:inline-block;
width:14em;
height:7em;
position:relative;
box-sizing:border-box;
text-align:center;
}
div.testArea div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.testArea2 div.testName{
display:block;
text-align:center;
font-size:1.4em;
}
div.testArea div.meterText{
position:absolute;
bottom:1.55em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
div.testArea2 div.meterText{
display:inline-block;
font-size:2.5em;
}
div.meterText:empty:before{
content:"0.00";
}
div.testArea div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testArea2 div.unit{
display:inline-block;
}
div.testArea canvas{
position:absolute;
top:0; left:0; width:100%; height:100%;
z-index:1;
}
div.testGroup{
display:block;
margin: 0 auto;
}
#shareArea{
width:95%;
max-width:40em;
margin:0 auto;
margin-top:2em;
}
#shareArea > *{
display:block;
width:100%;
height:auto;
margin: 0.25em 0;
}
#privacyPolicy{
position:fixed;
top:2em;
bottom:2em;
left:2em;
right:2em;
overflow-y:auto;
width:auto;
height:auto;
box-shadow:0 0 3em 1em #000000;
z-index:999999;
text-align:left;
background-color:#FFFFFF;
padding:1em;
}
a.privacy{
text-align:center;
font-size:0.8em;
color:#808080;
padding: 0 3em;
}
div.closePrivacyPolicy {
width: 100%;
text-align: center;
}
div.closePrivacyPolicy a.privacy {
padding: 1em 3em;
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
}
div.visible{
animation: fadeIn 0.4s;
display:block;
}
div.hidden{
animation: fadeOut 0.4s;
display:none;
}
@keyframes fadeIn{
0%{
opacity:0;
}
100%{
opacity:1;
}
}
@keyframes fadeOut{
0%{
display:block;
opacity:1;
}
100%{
display:block;
opacity:0;
}
}
</style>
<title>LibreSpeed Example</title>
</head>
<body onload="initServers()">
<h1>LibreSpeed Example</h1>
<div id="loading" class="visible">
<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
</div>
<div id="testWrapper" class="hidden">
<div id="startStopBtn" onclick="startStop()"></div><br/>
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
<div id="serverArea">
Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
</div>
<div id="test">
<div class="testGroup">
<div class="testArea2">
<div class="testName">Ping</div>
<div id="pingText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
<div class="testArea2">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
<div id="shareArea" style="display:none">
<h3>Share results</h3>
<p>Test ID: <span id="testId"></span></p>
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg" />
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</div>
<div id="privacyPolicy" style="display:none">
<h2>Privacy Policy</h2>
<p>This HTML5 Speedtest server is configured with telemetry enabled.</p>
<h4>What data we collect</h4>
<p>
At the end of the test, the following data is collected and stored:
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
</p>
<h4>How we use the data</h4>
<p>
Data collected through this service is used to:
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
</p>
<h4>Your consent</h4>
<p>
By starting the test, you consent to the terms of this privacy policy.
</p>
<h4>Data removal</h4>
<p>
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
Contact this email address for all deletion requests: <a href="mailto:PUT@YOUR_EMAIL.HERE">TO BE FILLED BY DEVELOPER</a>.
</p>
<br/><br/>
<div class="closePrivacyPolicy">
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
</div>
<br/>
</div>
</body>
</html>

View File

@ -0,0 +1,245 @@
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="favicon.ico">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<title>LibreSpeed Example</title>
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
//LIST OF TEST SERVERS. See documentation for details if needed
var SPEEDTEST_SERVERS=[
{ //this server doesn't actually exist, remove it
name:"Example Server 1", //user friendly name for the server
server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
},
{ //this server doesn't actually exist, remove it
name:"Example Server 2", //user friendly name for the server
server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
}
//add other servers here, comma separated
];
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
s.onupdate=function(data){ //callback to update data in UI
I("ip").textContent=data.clientIp;
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
I("pingText").textContent=data.pingStatus;
I("jitText").textContent=data.jitterStatus;
}
s.onend=function(aborted){ //callback for test ended/aborted
I("startStopBtn").className=""; //show start button again
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
initUI();
}
}
function selectServer(){ //called after loading server list
s.selectServer(function(server){ //run server selection. When the server has been selected, display it in the UI
if(server==null){
I("serverId").textContent="No servers available";
}else{
I("startStopBtn").style.display=""; //show start/stop button again
I("serverId").textContent=server.name; //show name of test server
}
});
}
function loadServers(){ //called when the page is fully loaded
I("startStopBtn").style.display="none"; //hide start/stop button during server selection
if(typeof SPEEDTEST_SERVERS === "string"){
//load servers from url
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
//list loaded
SPEEDTEST_SERVERS=servers;
selectServer();
});
}else{
//hardcoded list of servers, already loaded
s.addTestPoints(SPEEDTEST_SERVERS);
selectServer();
}
}
function startStop(){ //start/stop button pressed
if(s.getState()==3){
//speedtest is running, abort
s.abort();
}else{
//test is not running, begin
s.start();
I("startStopBtn").className="running";
}
}
//function to (re)initialize UI
function initUI(){
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
function I(id){return document.getElementById(id);}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:14em;
height:9em;
position:relative;
box-sizing:border-box;
}
div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.meterText{
position:absolute;
bottom:1.5em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
#dlText{
color:#6060AA;
}
#ulText{
color:#309030;
}
#pingText,#jitText{
color:#AA6060;
}
div.meterText:empty:before{
color:#505050 !important;
content:"0.00";
}
div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testGroup{
display:inline-block;
}
@media all and (max-width:65em){
body{
font-size:1.5vw;
}
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
div.testGroup{
display:block;
margin: 0 auto;
}
}
</style>
</head>
<body>
<h1>LibreSpeed Example</h1>
<div id="startStopBtn" onclick="startStop()"></div>
<div id="serverId">Selecting server...</div>
<div id="test">
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Ping</div>
<div id="pingText" class="meterText"></div>
<div class="unit">ms</div>
</div>
<div class="testArea">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText"></div>
<div class="unit">ms</div>
</div>
</div>
<div id="ipArea">
IP Address: <span id="ip"></span>
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
<script type="text/javascript">
initUI();
loadServers();
</script>
</body>
</html>

View File

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<meta charset="UTF-8" />
<head>
<title>LibreSpeed Example</title>
<link rel="shortcut icon" href="favicon.ico">
</head>
<script type="text/javascript" src="speedtest.js"></script>
<body>
<h1>LibreSpeed Example</h1>
<h4>IP Address</h4>
<p id="ip"></p>
<h4>Download</h4>
<p id="download"></p>
<h4>Upload</h4>
<p id="upload"></p>
<h4>Latency</h4>
<p id="ping"></p>
<script type="text/javascript">
var s=new Speedtest();
s.onupdate = function (data) { // when status is received, put the values in the appropriate fields
document.getElementById('download').textContent = data.dlStatus + ' Mbit/s'
document.getElementById('upload').textContent = data.ulStatus + ' Mbit/s'
document.getElementById('ping').textContent = data.pingStatus + ' ms, ' + data.jitterStatus + ' ms jitter'
document.getElementById('ip').textContent = data.clientIp
}
s.start(); // start the speedtest with default settings
</script>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</body>
</html>

View File

@ -0,0 +1,256 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>LibreSpeed Example</title>
<link rel="shortcut icon" href="favicon.ico">
<style type="text/css">
html,
body {
margin: 0;
padding: 0;
border: none;
text-align: center;
}
#startBtn {
display: inline-block;
border: 0.15em solid #000000;
padding: 0.3em 0.5em;
margin: 0.6em;
color: #000000;
text-decoration: none;
}
#ip {
margin: 0.8em 0;
font-size: 1.2em;
}
#chart1Area,
#chart2Area {
width: 100%;
max-width: 30em;
height: 10em;
display: block;
margin: 0 auto;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script> <!--THIS LIBRARY SUCKS!-->
<script src="speedtest.js"></script>
<script type="text/javascript">
var s = null
function runTest() {
var chart1ctx = document.getElementById('chart1Area').getContext('2d')
var chart2ctx = document.getElementById('chart2Area').getContext('2d')
var dlDataset = {
label: 'Download',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(75,192,192,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(75,192,192,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [0],
spanGaps: false
}
var ulDataset = {
label: 'Upload',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(192,192,75,0.4)',
borderColor: 'rgba(192,192,75,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(192,192,75,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(192,192,75,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [0],
spanGaps: false
}
var pingDataset = {
label: 'Ping',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(75,220,75,0.4)',
borderColor: 'rgba(75,220,75,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(75,220,75,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(75,220,75,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [],
spanGaps: false
}
var jitterDataset = {
label: 'Jitter',
fill: false,
lineTension: 0.1,
backgroundColor: 'rgba(220,75,75,0.4)',
borderColor: 'rgba(220,75,75,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(220,75,75,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(220,75,75,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [],
spanGaps: false
}
var chart1Options = {
type: 'line',
data: {
datasets: [dlDataset, ulDataset]
},
options: {
responsive: true,
legend: {
position: 'bottom'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true
}
}],
yAxes: [{
display: true,
scaleLabel: 'Speed',
ticks: {
beginAtZero: true
}
}]
}
}
}
var chart2Options = {
type: 'line',
data: {
datasets: [pingDataset, jitterDataset]
},
options: {
responsive: true,
legend: {
position: 'bottom'
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true
}
}],
yAxes: [{
display: true,
scaleLabel: 'Latency',
ticks: {
beginAtZero: true
}
}]
}
}
}
var chart1 = new Chart(chart1ctx, chart1Options)
var chart2 = new Chart(chart2ctx, chart2Options)
document.getElementById('startBtn').style.display = 'none'
document.getElementById('testArea').style.display = ''
document.getElementById('abortBtn').style.display = ''
s=new Speedtest();
s.onupdate = function (data) {
var status = data.testState
if (status === 1 && Number(data.dlStatus) > 0) {
for(var i=~~(20*Number(data.dlProgress));i<20;i++) chart1.data.datasets[0].data[i]=(Number(data.dlStatus))
chart1.data.labels[chart1.data.datasets[0].data.length - 1] = ''
chart1.update()
}
if (status === 3 && Number(data.ulStatus) > 0) {
for(var i=~~(20*Number(data.ulProgress));i<20;i++) chart1.data.datasets[1].data[i]=(Number(data.ulStatus))
chart1.data.labels[chart1.data.datasets[1].data.length - 1] = ''
chart1.update()
}
if (status === 2 && Number(data.pingStatus) > 0) {
chart2.data.datasets[0].data.push(Number(data.pingStatus))
chart2.data.datasets[1].data.push(Number(data.jitterStatus))
chart2.data.labels[chart2.data.datasets[0].data.length - 1] = ''
chart2.data.labels[chart2.data.datasets[1].data.length - 1] = ''
chart2.update()
}
ip.textContent = data.clientIp
}
s.onend=function(aborted){
document.getElementById('abortBtn').style.display = 'none'
document.getElementById('startBtn').style.display = ''
s = null
if (aborted) {
document.getElementById('testArea').style.display = 'none'
}
}
s.start();
}
function abortTest() {
if (s) s.abort();
}
</script>
</head>
<body>
<h1>LibreSpeed - Chart.js example</h1>
<div id="testArea" style="display:none">
<p id="ip">Please wait...</p>
<h2>Speed</h2>
<canvas id="chart1Area"></canvas>
<h2>Latency</h2>
<canvas id="chart2Area"></canvas>
<br/>
<a href="javascript:abortTest()" id="abortBtn">Abort</a>
</div>
<a href="javascript:runTest()" id="startBtn">Run speedtest</a>
<br/><br/> Charts by <a href="http://www.chartjs.org/">Chart.js</a><br/><br/><a href="https://github.com/librespeed/speedtest">Source code</a>
</body>
</html>

View File

@ -0,0 +1,174 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<title>LibreSpeed Example</title>
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
//CUSTOM SETTINGS HERE
s.setParameter("test_order","D_U"); //we only want download and upload test
s.setParameter("time_auto",false); //fixed duration for tests
s.setParameter("time_dl_max",10); //10 seconds for the download test
s.setParameter("time_ul_max",15); //15 seconds for the upload test
//END OF CUSTOM SETTINGS
s.onupdate=function(data){ //callback to update data in UI
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
}
s.onend=function(aborted){ //callback for test ended/aborted
I("startStopBtn").className=""; //show start button again
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
initUI();
}
}
function startStop(){ //start/stop button pressed
if(s.getState()==3){
//speedtest is running, abort
s.abort();
}else{
//test is not running, begin
s.start();
I("startStopBtn").className="running";
}
}
//function to (re)initialize UI
function initUI(){
I("dlText").textContent="";
I("ulText").textContent="";
}
function I(id){return document.getElementById(id);}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:14em;
height:9em;
position:relative;
box-sizing:border-box;
}
div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.meterText{
position:absolute;
bottom:1.5em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
#dlText{
color:#6060AA;
}
#ulText{
color:#309030;
}
div.meterText:empty:before{
color:#505050 !important;
content:"0.00";
}
div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testGroup{
display:inline-block;
}
@media all and (max-width:65em){
body{
font-size:2vw;
}
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
div.testGroup{
display:block;
margin: 0 auto;
}
}
</style>
</head>
<body>
<h1>LibreSpeed Example</h1>
<div id="startStopBtn" onclick="startStop()"></div>
<div id="test">
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
<script type="text/javascript">
initUI();
</script>
</body>
</html>

View File

@ -0,0 +1,365 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<meta charset="UTF-8" />
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i){return document.getElementById(i);}
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
s.setParameter("telemetry_level","basic"); //enable telemetry
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
var dlColor="#6060AA",
ulColor="#616161";
var progColor=meterBk;
//CODE FOR GAUGES
function drawMeter(c,amount,bk,fg,progress,prog){
var ctx=c.getContext("2d");
var dp=window.devicePixelRatio||1;
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
var sizScale=ch*0.0055;
if(c.width==cw&&c.height==ch){
ctx.clearRect(0,0,cw,ch);
}else{
c.width=cw;
c.height=ch;
}
ctx.beginPath();
ctx.strokeStyle=bk;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=fg;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
ctx.stroke();
if(typeof progress !== "undefined"){
ctx.fillStyle=prog;
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
}
}
function mbpsToAmount(s){
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
}
function format(d){
d=Number(d);
if(d<10) return d.toFixed(2);
if(d<100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData=null;
function startStop(){
if(s.getState()==3){
//speedtest is running, abort
s.abort();
data=null;
I("startStopBtn").className="";
initUI();
}else{
//test is not running, begin
I("startStopBtn").className="running";
I("shareArea").style.display="none";
s.onupdate=function(data){
uiData=data;
};
s.onend=function(aborted){
I("startStopBtn").className="";
updateUI(true);
if(!aborted){
//if testId is present, show sharing panel, otherwise do nothing
try{
var testId=uiData.testId;
if(testId!=null){
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
I("resultsImg").src=shareURL;
I("resultsURL").value=shareURL;
I("testId").innerHTML=testId;
I("shareArea").style.display="";
}
}catch(e){}
}
};
s.start();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced){
if(!forced&&s.getState()!=3) return;
if(uiData==null) return;
var status=uiData.testState;
I("ip").textContent=uiData.clientIp;
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
I("pingText").textContent=format(uiData.pingStatus);
I("jitText").textContent=format(uiData.jitterStatus);
}
function oscillate(){
return 1+0.02*Math.sin(Date.now()/100);
}
//update the UI every frame
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
function frame(){
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI(){
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:16em;
height:12.5em;
position:relative;
box-sizing:border-box;
}
div.testArea2{
display:inline-block;
width:14em;
height:7em;
position:relative;
box-sizing:border-box;
text-align:center;
}
div.testArea div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.testArea2 div.testName{
display:block;
text-align:center;
font-size:1.4em;
}
div.testArea div.meterText{
position:absolute;
bottom:1.55em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
div.testArea2 div.meterText{
display:inline-block;
font-size:2.5em;
}
div.meterText:empty:before{
content:"0.00";
}
div.testArea div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testArea2 div.unit{
display:inline-block;
}
div.testArea canvas{
position:absolute;
top:0; left:0; width:100%; height:100%;
z-index:1;
}
div.testGroup{
display:block;
margin: 0 auto;
}
#shareArea{
width:95%;
max-width:40em;
margin:0 auto;
margin-top:2em;
}
#shareArea > *{
display:block;
width:100%;
height:auto;
margin: 0.25em 0;
}
#privacyPolicy{
position:fixed;
top:2em;
bottom:2em;
left:2em;
right:2em;
overflow-y:auto;
width:auto;
height:auto;
box-shadow:0 0 3em 1em #000000;
z-index:999999;
text-align:left;
background-color:#FFFFFF;
padding:1em;
}
a.privacy{
text-align:center;
font-size:0.8em;
color:#808080;
padding: 0 3em;
}
div.closePrivacyPolicy {
width: 100%;
text-align: center;
}
div.closePrivacyPolicy a.privacy {
padding: 1em 3em;
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
}
</style>
<title>LibreSpeed Example</title>
</head>
<body>
<h1>LibreSpeed Example</h1>
<div id="testWrapper">
<div id="startStopBtn" onclick="startStop()"></div><br/>
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
<div id="test">
<div class="testGroup">
<div class="testArea2">
<div class="testName">Ping</div>
<div id="pingText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
<div class="testArea2">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
<div id="shareArea" style="display:none">
<h3>Share results</h3>
<p>Test ID: <span id="testId"></span></p>
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg" />
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</div>
<div id="privacyPolicy" style="display:none">
<h2>Privacy Policy</h2>
<p>This HTML5 Speedtest server is configured with telemetry enabled.</p>
<h4>What data we collect</h4>
<p>
At the end of the test, the following data is collected and stored:
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
</p>
<h4>How we use the data</h4>
<p>
Data collected through this service is used to:
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
</p>
<h4>Your consent</h4>
<p>
By starting the test, you consent to the terms of this privacy policy.
</p>
<h4>Data removal</h4>
<p>
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
Contact this email address for all deletion requests: <a href="mailto:PUT@YOUR_EMAIL.HERE">TO BE FILLED BY DEVELOPER</a>.
</p>
<br/><br/>
<div class="closePrivacyPolicy">
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
</div>
<br/>
</div>
<script type="text/javascript">setTimeout(function(){initUI()},100);</script>
</body>
</html>

View File

@ -0,0 +1,262 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<meta charset="UTF-8" />
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i){return document.getElementById(i);}
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
var dlColor="#6060AA",
ulColor="#616161";
var progColor=meterBk;
//CODE FOR GAUGES
function drawMeter(c,amount,bk,fg,progress,prog){
var ctx=c.getContext("2d");
var dp=window.devicePixelRatio||1;
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
var sizScale=ch*0.0055;
if(c.width==cw&&c.height==ch){
ctx.clearRect(0,0,cw,ch);
}else{
c.width=cw;
c.height=ch;
}
ctx.beginPath();
ctx.strokeStyle=bk;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=fg;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
ctx.stroke();
if(typeof progress !== "undefined"){
ctx.fillStyle=prog;
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
}
}
function mbpsToAmount(s){
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
}
function format(d){
d=Number(d);
if(d<10) return d.toFixed(2);
if(d<100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData=null;
function startStop(){
if(s.getState()==3){
//speedtest is running, abort
s.abort();
data=null;
I("startStopBtn").className="";
initUI();
}else{
//test is not running, begin
I("startStopBtn").className="running";
s.onupdate=function(data){
uiData=data;
};
s.onend=function(aborted){
I("startStopBtn").className="";
updateUI(true);
};
s.start();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced){
if(!forced&&s.getState()!=3) return;
if(uiData==null) return;
var status=uiData.testState;
I("ip").textContent=uiData.clientIp;
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
I("pingText").textContent=format(uiData.pingStatus);
I("jitText").textContent=format(uiData.jitterStatus);
}
function oscillate(){
return 1+0.02*Math.sin(Date.now()/100);
}
//update the UI every frame
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
function frame(){
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI(){
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:16em;
height:12.5em;
position:relative;
box-sizing:border-box;
}
div.testArea2{
display:inline-block;
width:14em;
height:7em;
position:relative;
box-sizing:border-box;
text-align:center;
}
div.testArea div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.testArea2 div.testName{
display:block;
text-align:center;
font-size:1.4em;
}
div.testArea div.meterText{
position:absolute;
bottom:1.55em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
div.testArea2 div.meterText{
display:inline-block;
font-size:2.5em;
}
div.meterText:empty:before{
content:"0.00";
}
div.testArea div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testArea2 div.unit{
display:inline-block;
}
div.testArea canvas{
position:absolute;
top:0; left:0; width:100%; height:100%;
z-index:1;
}
div.testGroup{
display:block;
margin: 0 auto;
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
}
</style>
<title>LibreSpeed Example</title>
</head>
<body>
<h1>LibreSpeed Example</h1>
<div id="testWrapper">
<div id="startStopBtn" onclick="startStop()"></div>
<div id="test">
<div class="testGroup">
<div class="testArea2">
<div class="testName">Ping</div>
<div id="pingText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
<div class="testArea2">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</div>
<script type="text/javascript">setTimeout(function(){initUI()},100);</script>
</body>
</html>

View File

@ -0,0 +1,192 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<title>LibreSpeed Example</title>
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
s.onupdate=function(data){ //callback to update data in UI
I("ip").textContent=data.clientIp;
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
I("pingText").textContent=data.pingStatus;
I("jitText").textContent=data.jitterStatus;
}
s.onend=function(aborted){ //callback for test ended/aborted
I("startStopBtn").className=""; //show start button again
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
initUI();
}
}
function startStop(){ //start/stop button pressed
if(s.getState()==3){
//speedtest is running, abort
s.abort();
}else{
//test is not running, begin
s.start();
I("startStopBtn").className="running";
}
}
//function to (re)initialize UI
function initUI(){
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
function I(id){return document.getElementById(id);}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:14em;
height:9em;
position:relative;
box-sizing:border-box;
}
div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.meterText{
position:absolute;
bottom:1.5em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
#dlText{
color:#6060AA;
}
#ulText{
color:#309030;
}
#pingText,#jitText{
color:#AA6060;
}
div.meterText:empty:before{
color:#505050 !important;
content:"0.00";
}
div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testGroup{
display:inline-block;
}
@media all and (max-width:65em){
body{
font-size:1.5vw;
}
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
div.testGroup{
display:block;
margin: 0 auto;
}
}
</style>
</head>
<body>
<h1>LibreSpeed Example</h1>
<div id="startStopBtn" onclick="startStop()"></div>
<div id="test">
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Ping</div>
<div id="pingText" class="meterText"></div>
<div class="unit">ms</div>
</div>
<div class="testArea">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText"></div>
<div class="unit">ms</div>
</div>
</div>
<div id="ipArea">
IP Address: <span id="ip"></span>
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
<script type="text/javascript">
initUI();
</script>
</body>
</html>

View File

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<title>LibreSpeed Example</title>
<link rel="shortcut icon" href="favicon.ico">
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
s.onupdate=function(data){ //callback to update data in UI
I("ip").textContent=data.clientIp;
I("dlText").textContent=(data.testState==1&&data.dlStatus==0)?"...":data.dlStatus;
I("ulText").textContent=(data.testState==3&&data.ulStatus==0)?"...":data.ulStatus;
I("pingText").textContent=data.pingStatus;
I("jitText").textContent=data.jitterStatus;
var prog=(Number(data.dlProgress)*2+Number(data.ulProgress)*2+Number(data.pingProgress))/5;
I("progress").style.width=(100*prog)+"%";
}
s.onend=function(aborted){ //callback for test ended/aborted
I("startStopBtn").className=""; //show start button again
if(aborted){ //if the test was aborted, clear the UI and prepare for new test
initUI();
}
}
function startStop(){ //start/stop button pressed
if(s.getState()==3){
//speedtest is running, abort
s.abort();
}else{
//test is not running, begin
s.start();
I("startStopBtn").className="running";
}
}
//function to (re)initialize UI
function initUI(){
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
function I(id){return document.getElementById(id);}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:14em;
height:9em;
position:relative;
box-sizing:border-box;
}
div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.meterText{
position:absolute;
bottom:1.5em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
#dlText{
color:#6060AA;
}
#ulText{
color:#309030;
}
#pingText,#jitText{
color:#AA6060;
}
div.meterText:empty:before{
color:#505050 !important;
content:"0.00";
}
div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testGroup{
display:inline-block;
}
@media all and (max-width:65em){
body{
font-size:1.5vw;
}
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
div.testGroup{
display:block;
margin: 0 auto;
}
}
#progressBar{
width:90%;
height:0.3em;
background-color:#EEEEEE;
position:relative;
display:block;
margin:0 auto;
margin-bottom:2em;
}
#progress{
position:absolute;
top:0; left:0;
height:100%;
width:0%;
transition: width 2s;
background-color:#90BBFF;
}
</style>
</head>
<body>
<h1>LibreSpeed Example</h1>
<div id="startStopBtn" onclick="startStop()"></div>
<div id="test">
<div id="progressBar"><div id="progress"></div></div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Ping</div>
<div id="pingText" class="meterText"></div>
<div class="unit">ms</div>
</div>
<div class="testArea">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText"></div>
<div class="unit">ms</div>
</div>
</div>
<div id="ipArea">
IP Address: <span id="ip"></span>
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
<script type="text/javascript">
initUI();
</script>
</body>
</html>

941
web/assets/index.html Normal file → Executable file
View File

@ -1,479 +1,449 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"/>
<meta charset="UTF-8"/>
<link rel="shortcut icon" href="../../favicon.ico">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald:300,400|Source+Sans+Pro:400,600">
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i) {
return document.getElementById(i);
}
<link rel="shortcut icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
<meta charset="UTF-8" />
<script type="text/javascript" src="speedtest.js"></script>
<script type="text/javascript">
function I(i){return document.getElementById(i);}
var meterBk = "#ebecf0"; // ui--input-border
var dlColor = "#02b159", // grass-green
ulColor = "#02b159", // grass-green
pingColor = "#02b159", // grass-green
jitColor = "#02b159"; // grass-green
var progColor = "#0ac9f7"; // sky-blue
//LIST OF TEST SERVERS. See documentation for details if needed
var SPEEDTEST_SERVERS=[
{ //this server doesn't actually exist, remove it
name:"Example Server 1", //user friendly name for the server
server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
},
{ //this server doesn't actually exist, remove it
name:"Example Server 2", //user friendly name for the server
server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
}
//add other servers here, comma separated
];
function setPageTitle() {
var pageTitleDiv = document.getElementById('pageTitle');
var titlePrefixNode = document.createTextNode("You're currently using this server:");
var lineBreakElement = document.createElement('br');
var locationNode = document.createTextNode('Unknown');
switch (window.location.hostname) {
case 'us1.zzz.cat':
locationNode.textContent = 'Unites States 1 (Fremont, Linode)';
break;
case 'us2.zzz.cat':
locationNode.textContent = 'Unites States 2 (LAX (CN2), Bandwagon)';
break;
case 'us3.zzz.cat':
locationNode.textContent = 'Unites States 3 (LAX (CN2 GIA-E), Bandwagon)';
break;
case 'jp1.zzz.cat':
locationNode.textContent = 'Japan 1 (Tokyo 2, Linode)';
break;
case 'jp2.zzz.cat':
locationNode.textContent = 'Japan 2 (Tokyo 2, Linode)';
break;
case 'sg1.zzz.cat':
locationNode.textContent = 'Singapore (Singapore, Linode)';
break;
case 'ca1.zzz.cat':
locationNode.textContent = 'Canada (Toronto, Linode)';
break;
default:
locationNode.textContent = window.location.hostname;
break;
}
//INITIALIZE SPEEDTEST
var s=new Speedtest(); //create speedtest object
s.setParameter("telemetry_level","basic"); //enable telemetry
pageTitleDiv.appendChild(titlePrefixNode);
pageTitleDiv.appendChild(lineBreakElement);
pageTitleDiv.appendChild(locationNode);
}
//INITIALIZE SPEEDTEST
var s = new Speedtest(); //create speedtest object
//CODE FOR GAUGES
function drawMeter(c, amount, bk, fg, progress, prog) {
var ctx = c.getContext("2d");
var dp = window.devicePixelRatio || 1;
var cw = c.clientWidth * dp, ch = c.clientHeight * dp;
var sizScale = ch * 0.0055;
if (c.width == cw && c.height == ch) {
ctx.clearRect(0, 0, cw, ch);
} else {
c.width = cw;
c.height = ch;
}
ctx.beginPath();
ctx.strokeStyle = bk;
ctx.lineWidth = 4 * sizScale;
ctx.arc(c.width / 2, c.height / 2, c.height / 2 - ctx.lineWidth, -Math.PI * 1.2, Math.PI * 0.2);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = fg;
ctx.lineWidth = 4 * sizScale;
ctx.arc(c.width / 2, c.height / 2, c.height / 2 - ctx.lineWidth, -Math.PI * 1.2, amount * Math.PI * 1.2 - Math.PI * 1.2);
ctx.stroke();
if (typeof progress !== "undefined") {
ctx.fillStyle = prog;
ctx.fillRect(c.width * 0.3, c.height - 28 * sizScale, c.width * 0.4 * progress, 4 * sizScale);
}
}
function mbpsToAmount(s) {
return 1 - (1 / (Math.pow(1.3, Math.sqrt(s))));
}
function msToAmount(s) {
return 1 - (1 / (Math.pow(1.08, Math.sqrt(s))));
}
function format(d) {
d = Number(d);
if (d < 10) return d.toFixed(2);
if (d < 100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData = null;
function startStop() {
if (s.getState() == 3) {
//speedtest is running, abort
s.abort();
data = null;
I("startStopBtn").className = "";
//SERVER AUTO SELECTION
function initServers(){
var noServersAvailable=function(){
I("message").innerHTML="No servers available";
}
var runServerSelect=function(){
s.selectServer(function(server){
if(server!=null){ //at least 1 server is available
I("loading").className="hidden"; //hide loading message
//populate server list for manual selection
for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
var option=document.createElement("option");
option.value=i;
option.textContent=SPEEDTEST_SERVERS[i].name;
if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
I("server").appendChild(option);
}
//show test UI
I("testWrapper").className="visible";
initUI();
} else {
//test is not running, begin
I("startStopBtn").className = "running";
I("shareArea").style.display = "none";
s.onupdate = function (data) {
uiData = data;
};
s.onend = function (aborted) {
I("startStopBtn").className = "";
updateUI(true);
if (!aborted) {
//if testId is present, show sharing panel, otherwise do nothing
try {
var testId = uiData.testId;
if (testId != null) {
var shareURL = window.location.href.substring(0, window.location.href.lastIndexOf("/")) + "/results?id=" + testId;
I("resultsImg").src = shareURL;
I("resultsURL").value = shareURL;
I("testId").innerHTML = testId;
I("shareArea").style.display = "";
}
} catch (e) {
}
}
};
s.start();
}else{ //no servers are available, the test cannot proceed
noServersAvailable();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced) {
if (!forced && s.getState() != 3) return;
if (uiData == null) return;
var status = uiData.testState;
I("ip").textContent = "IP Address: " + uiData.clientIp;
I("dlText").textContent = (status == 1 && uiData.dlStatus == 0) ? "..." : format(uiData.dlStatus);
drawMeter(I("dlMeter"), mbpsToAmount(Number(uiData.dlStatus * (status == 1 ? oscillate() : 1))), meterBk, dlColor, Number(uiData.dlProgress), progColor);
I("ulText").textContent = (status == 3 && uiData.ulStatus == 0) ? "..." : format(uiData.ulStatus);
drawMeter(I("ulMeter"), mbpsToAmount(Number(uiData.ulStatus * (status == 3 ? oscillate() : 1))), meterBk, ulColor, Number(uiData.ulProgress), progColor);
I("pingText").textContent = format(uiData.pingStatus);
drawMeter(I("pingMeter"), msToAmount(Number(uiData.pingStatus * (status == 2 ? oscillate() : 1))), meterBk, pingColor, Number(uiData.pingProgress), progColor);
I("jitText").textContent = format(uiData.jitterStatus);
drawMeter(I("jitMeter"), msToAmount(Number(uiData.jitterStatus * (status == 2 ? oscillate() : 1))), meterBk, jitColor, Number(uiData.pingProgress), progColor);
}
function oscillate() {
return 1 + 0.02 * Math.sin(Date.now() / 100);
}
//update the UI every frame
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || (function (callback, element) {
setTimeout(callback, 1000 / 60);
});
function frame() {
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI() {
drawMeter(I("dlMeter"), 0, meterBk, dlColor, 0);
drawMeter(I("ulMeter"), 0, meterBk, ulColor, 0);
drawMeter(I("pingMeter"), 0, meterBk, pingColor, 0);
drawMeter(I("jitMeter"), 0, meterBk, jitColor, 0);
I("dlText").textContent = "";
I("ulText").textContent = "";
I("pingText").textContent = "";
I("jitText").textContent = "";
I("ip").textContent = "";
}
</script>
<style type="text/css">
:root {
--dark-gray: #32363b;
--grass-green: #02b159;
}
html, body {
background-color: white;
border: none;
box-sizing: border-box;
color: var(--dark-gray);
padding: 0;
margin: 0;
}
html {
line-height: 1.15;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
font-size: 18px;
font-size: 1.125rem;
line-height: 1.33333;
font-family: "Source Sans Pro", sans-serif;
font-weight: 400;
letter-spacing: 0;
margin: 1rem 1rem 2rem;
text-align: center;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
*, *:before, *:after {
box-sizing: inherit;
}
#startStopBtn {
display: inline-block;
margin: 0 auto;
padding-left: 2rem;
padding-right: 2rem;
color: white;
background-color: var(--grass-green);
border: 0.15em solid var(--grass-green);
border-radius: 0.3em;
transition: all 0.3s;
box-sizing: border-box;
height: 3em;
line-height: 2.7em;
cursor: pointer;
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
font-weight: 600;
}
#startStopBtn:hover {
/*box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);*/
}
#startStopBtn.running {
background-color: var(--dark-gray);
border-color: var(--dark-gray);
color: white;
}
#startStopBtn:before {
content: "Start Speed Test";
}
#startStopBtn.running:before {
content: "Abort";
}
#test {
margin-top: 2rem;
margin-bottom: 2rem;
}
div.testArea {
display: inline-block;
width: calc(100% - 2rem - 2rem); /* subtract margins */
max-width: 16em;
margin: 2rem;
position: relative;
box-sizing: border-box;
}
div.testArea::before {
content: '';
display: block;
padding-top: 100%;
}
div.testName {
bottom: 0;
font-size: 1rem;
font-weight: 600;
left: 0;
position: absolute;
width: 100%;
z-index: 9;
}
div.meterText {
bottom: 1.8em;
font-family: "Oswald", sans-serif;
font-size: 4em;
font-weight: 300;
left: 0;
line-height: 1;
position: absolute;
width: 100%;
z-index: 9;
}
div.meterText:empty:before {
content: "0.00";
}
div.unit {
bottom: 3.5em;
font-family: "Oswald", sans-serif;
font-size: 1.5em;
font-weight: 400;
letter-spacing: 0.5px;
left: 0;
line-height: 1;
position: absolute;
text-transform: uppercase;
width: 100%;
z-index: 9;
}
div.testArea canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
#ipArea {
margin-top: 2rem;
}
#shareArea {
width: 95%;
max-width: 25em;
margin: 0 auto;
margin-top: 2em;
}
#shareArea > * {
display: block;
width: 100%;
height: auto;
margin: 0.25em 0;
}
#privacyPolicy {
position: fixed;
top: 10em;
bottom: 10em;
left: 15em;
right: 15em;
overflow-y: auto;
width: auto;
height: auto;
box-shadow: 0 0 3em 1em #000000;
z-index: 999999;
text-align: left;
background-color: #FFFFFF;
padding: 1em;
}
#privacyCloseBtn {
display: inline-block;
margin: 0 auto;
padding-left: 2rem;
padding-right: 2rem;
color: white;
background-color: var(--grass-green);
border: 0.15em solid var(--grass-green);
border-radius: 0.3em;
transition: all 0.3s;
box-sizing: border-box;
height: 3em;
line-height: 2.7em;
cursor: pointer;
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
font-weight: 600;
}
#resultsURL {
color: #333;
font-size: 1.2rem;
padding: 0.5rem 1rem;
border-radius: 0.2rem;
background-color: rgb(255, 255, 255);
border: green;
display: block;
border-style: dashed;
border-width: 2px;
margin: 0.8em 0 0.8em 0;
}
#testId {
margin-top: 1.4em;
}
a.privacy {
margin-top: 2em;
text-align: center;
font-size: 0.8em;
color: #808080;
display: block;
}
@media all and (max-width: 65em) {
/* 1040 px */
div.testGroup {
margin-left: -1rem;
margin-right: -1rem;
}
if(typeof SPEEDTEST_SERVERS === "string"){
//need to fetch list of servers from specified URL
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
if(servers==null){ //failed to load server list
noServersAvailable();
}else{ //server list loaded
SPEEDTEST_SERVERS=servers;
runServerSelect();
}
});
}else{
//hardcoded server list
s.addTestPoints(SPEEDTEST_SERVERS);
runServerSelect();
}
}
div.testArea {
font-size: 1.5384615vw; /* 16 px */
margin: 1rem;
width: calc(100% - 1rem - 1rem); /* subtract margins */
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
var dlColor="#6060AA",
ulColor="#616161";
var progColor=meterBk;
//CODE FOR GAUGES
function drawMeter(c,amount,bk,fg,progress,prog){
var ctx=c.getContext("2d");
var dp=window.devicePixelRatio||1;
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
var sizScale=ch*0.0055;
if(c.width==cw&&c.height==ch){
ctx.clearRect(0,0,cw,ch);
}else{
c.width=cw;
c.height=ch;
}
ctx.beginPath();
ctx.strokeStyle=bk;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle=fg;
ctx.lineWidth=12*sizScale;
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
ctx.stroke();
if(typeof progress !== "undefined"){
ctx.fillStyle=prog;
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
}
}
function mbpsToAmount(s){
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
}
function format(d){
d=Number(d);
if(d<10) return d.toFixed(2);
if(d<100) return d.toFixed(1);
return d.toFixed(0);
}
//UI CODE
var uiData=null;
function startStop(){
if(s.getState()==3){
//speedtest is running, abort
s.abort();
data=null;
I("startStopBtn").className="";
I("server").disabled=false;
initUI();
}else{
//test is not running, begin
I("startStopBtn").className="running";
I("shareArea").style.display="none";
I("server").disabled=true;
s.onupdate=function(data){
uiData=data;
};
s.onend=function(aborted){
I("startStopBtn").className="";
I("server").disabled=false;
updateUI(true);
if(!aborted){
//if testId is present, show sharing panel, otherwise do nothing
try{
var testId=uiData.testId;
if(testId!=null){
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
I("resultsImg").src=shareURL;
I("resultsURL").value=shareURL;
I("testId").innerHTML=testId;
I("shareArea").style.display="";
}
}catch(e){}
}
}
@media all and (max-width: 40em) {
/* 640 px */
div.testArea {
font-size: 0.8em; /* 12.8 px */
}
}
</style>
<title>zzz.cat Speedtest</title>
};
s.start();
}
}
//this function reads the data sent back by the test and updates the UI
function updateUI(forced){
if(!forced&&s.getState()!=3) return;
if(uiData==null) return;
var status=uiData.testState;
I("ip").textContent=uiData.clientIp;
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
I("pingText").textContent=format(uiData.pingStatus);
I("jitText").textContent=format(uiData.jitterStatus);
}
function oscillate(){
return 1+0.02*Math.sin(Date.now()/100);
}
//update the UI every frame
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
function frame(){
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI(){
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
I("dlText").textContent="";
I("ulText").textContent="";
I("pingText").textContent="";
I("jitText").textContent="";
I("ip").textContent="";
}
</script>
<style type="text/css">
html,body{
border:none; padding:0; margin:0;
background:#FFFFFF;
color:#202020;
}
body{
text-align:center;
font-family:"Roboto",sans-serif;
}
h1{
color:#404040;
}
#loading{
background-color:#FFFFFF;
color:#404040;
text-align:center;
}
span.loadCircle{
display:inline-block;
width:2em;
height:2em;
vertical-align:middle;
background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
background-size:2em 2em;
margin-right:0.5em;
animation: spin 0.6s linear infinite;
}
@keyframes spin{
0%{transform:rotate(0deg);}
100%{transform:rotate(359deg);}
}
#startStopBtn{
display:inline-block;
margin:0 auto;
color:#6060AA;
background-color:rgba(0,0,0,0);
border:0.15em solid #6060FF;
border-radius:0.3em;
transition:all 0.3s;
box-sizing:border-box;
width:8em; height:3em;
line-height:2.7em;
cursor:pointer;
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
}
#startStopBtn:hover{
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
}
#startStopBtn.running{
background-color:#FF3030;
border-color:#FF6060;
color:#FFFFFF;
}
#startStopBtn:before{
content:"Start";
}
#startStopBtn.running:before{
content:"Abort";
}
#serverArea{
margin-top:1em;
}
#server{
font-size:1em;
padding:0.2em;
}
#test{
margin-top:2em;
margin-bottom:12em;
}
div.testArea{
display:inline-block;
width:16em;
height:12.5em;
position:relative;
box-sizing:border-box;
}
div.testArea2{
display:inline-block;
width:14em;
height:7em;
position:relative;
box-sizing:border-box;
text-align:center;
}
div.testArea div.testName{
position:absolute;
top:0.1em; left:0;
width:100%;
font-size:1.4em;
z-index:9;
}
div.testArea2 div.testName{
display:block;
text-align:center;
font-size:1.4em;
}
div.testArea div.meterText{
position:absolute;
bottom:1.55em; left:0;
width:100%;
font-size:2.5em;
z-index:9;
}
div.testArea2 div.meterText{
display:inline-block;
font-size:2.5em;
}
div.meterText:empty:before{
content:"0.00";
}
div.testArea div.unit{
position:absolute;
bottom:2em; left:0;
width:100%;
z-index:9;
}
div.testArea2 div.unit{
display:inline-block;
}
div.testArea canvas{
position:absolute;
top:0; left:0; width:100%; height:100%;
z-index:1;
}
div.testGroup{
display:block;
margin: 0 auto;
}
#shareArea{
width:95%;
max-width:40em;
margin:0 auto;
margin-top:2em;
}
#shareArea > *{
display:block;
width:100%;
height:auto;
margin: 0.25em 0;
}
#privacyPolicy{
position:fixed;
top:2em;
bottom:2em;
left:2em;
right:2em;
overflow-y:auto;
width:auto;
height:auto;
box-shadow:0 0 3em 1em #000000;
z-index:999999;
text-align:left;
background-color:#FFFFFF;
padding:1em;
}
a.privacy{
text-align:center;
font-size:0.8em;
color:#808080;
padding: 0 3em;
}
div.closePrivacyPolicy {
width: 100%;
text-align: center;
}
div.closePrivacyPolicy a.privacy {
padding: 1em 3em;
}
@media all and (max-width:40em){
body{
font-size:0.8em;
}
}
div.visible{
animation: fadeIn 0.4s;
display:block;
}
div.hidden{
animation: fadeOut 0.4s;
display:none;
}
@keyframes fadeIn{
0%{
opacity:0;
}
100%{
opacity:1;
}
}
@keyframes fadeOut{
0%{
display:block;
opacity:1;
}
100%{
display:block;
opacity:0;
}
}
</style>
<title>LibreSpeed Example</title>
</head>
<body>
<div id="testWrapper">
<h1 id="pageTitle"></h1>
<div id="startStopBtn" onclick="startStop()"></div>
<br/>
<div id="test">
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
<div class="testArea">
<div class="testName">Ping</div>
<canvas id="pingMeter" class="meter"></canvas>
<div id="pingText" class="meterText"></div>
<div class="unit">ms</div>
</div>
<div class="testArea">
<div class="testName">Jitter</div>
<canvas id="jitMeter" class="meter"></canvas>
<div id="jitText" class="meterText"></div>
<div class="unit">ms</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
<div><a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a></div>
<div id="shareArea" style="display:none">
<h3>Share your results</h3>
<input type="text" value="" id="resultsURL" readonly="readonly"
onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg"/>
<p>Test ID: <span id="testId"></span></p>
</div>
</div>
<body onload="initServers()">
<h1>LibreSpeed Example</h1>
<div id="loading" class="visible">
<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
</div>
<div id="testWrapper" class="hidden">
<div id="startStopBtn" onclick="startStop()"></div><br/>
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
<div id="serverArea">
Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
</div>
<div id="test">
<div class="testGroup">
<div class="testArea2">
<div class="testName">Ping</div>
<div id="pingText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
<div class="testArea2">
<div class="testName">Jitter</div>
<div id="jitText" class="meterText" style="color:#AA6060"></div>
<div class="unit">ms</div>
</div>
</div>
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbps</div>
</div>
</div>
<div id="ipArea">
<span id="ip"></span>
</div>
<div id="shareArea" style="display:none">
<h3>Share results</h3>
<p>Test ID: <span id="testId"></span></p>
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg" />
</div>
</div>
<a href="https://github.com/librespeed/speedtest">Source code</a>
</div>
<div id="privacyPolicy" style="display:none">
<h2>Privacy Policy</h2>
@ -481,25 +451,25 @@
<h4>What data we collect</h4>
<p>
At the end of the test, the following data is collected and stored:
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
</p>
<h4>How we use the data</h4>
<p>
Data collected through this service is used to:
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
</p>
<h4>Your consent</h4>
<p>
@ -507,17 +477,14 @@
</p>
<h4>Data removal</h4>
<p>
If you want to have your information deleted, you need to provide either the ID of the test or your IP address.
This is the only way to identify your data, without this information we won't be able to comply with your
request.<br/><br/>
Contact this email address for all deletion requests: maddie at zzz dot cat.
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
Contact this email address for all deletion requests: <a href="mailto:PUT@YOUR_EMAIL.HERE">TO BE FILLED BY DEVELOPER</a>.
</p>
<br/><br/>
<a id="privacyCloseBtn" class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a><br/>
<div class="closePrivacyPolicy">
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
</div>
<br/>
</div>
<script type="text/javascript">setPageTitle();</script>
<script type="text/javascript">setTimeout(function () {
initUI()
}, 100);</script>
</body>
</html>

View File

@ -1,508 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"/>
<title>zzz.cat Speedtest</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Oswald:300,400|Source+Sans+Pro:400,600"
type="text/css" media="all"/>
<style type="text/css">
:root {
--dark-gray: #32363b;
--grass-green: #02b159;
}
html, body {
background-color: white;
border: none;
box-sizing: border-box;
color: var(--dark-gray);
padding: 0;
margin: 0;
}
html {
line-height: 1.15;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
font-size: 18px;
font-size: 1.125rem;
line-height: 1.33333;
font-family: "Source Sans Pro", sans-serif;
font-weight: 400;
letter-spacing: 0;
margin: 1rem 1rem 2rem;
text-align: center;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
*, *:before, *:after {
box-sizing: inherit;
}
#startStopBtn {
display: inline-block;
margin: 0 auto;
padding-left: 2rem;
padding-right: 2rem;
color: white;
background-color: var(--grass-green);
border: 0.15em solid var(--grass-green);
border-radius: 0.3em;
transition: all 0.3s;
box-sizing: border-box;
height: 3em;
line-height: 2.7em;
cursor: pointer;
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
font-weight: 600;
}
#startStopBtn:hover {
/*box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);*/
}
#startStopBtn.running {
background-color: var(--dark-gray);
border-color: var(--dark-gray);
color: white;
}
#startStopBtn:before {
content: "Start Speed Test";
}
#startStopBtn.running:before {
content: "Abort";
}
#test {
margin-top: 2rem;
margin-bottom: 2rem;
}
div.testArea {
display: inline-block;
width: calc(100% - 2rem - 2rem); /* subtract margins */
max-width: 16em;
margin: 2rem;
position: relative;
box-sizing: border-box;
}
div.testArea::before {
content: '';
display: block;
padding-top: 100%;
}
div.testName {
bottom: 0;
font-size: 1rem;
font-weight: 600;
left: 0;
position: absolute;
width: 100%;
z-index: 9;
}
div.meterText {
bottom: 1.8em;
font-family: "Oswald", sans-serif;
font-size: 4em;
font-weight: 300;
left: 0;
line-height: 1;
position: absolute;
width: 100%;
z-index: 9;
}
div.meterText:empty:before {
content: "0.00";
}
div.unit {
bottom: 3.5em;
font-family: "Oswald", sans-serif;
font-size: 1.5em;
font-weight: 400;
letter-spacing: 0.5px;
left: 0;
line-height: 1;
position: absolute;
text-transform: uppercase;
width: 100%;
z-index: 9;
}
div.testArea canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
#ipArea {
margin-top: 2rem;
}
#shareArea {
width: 95%;
max-width: 40em;
margin: 0 auto;
margin-top: 2em;
}
#shareArea > * {
display: block;
width: 100%;
height: auto;
margin: 0.25em 0;
}
#privacyPolicy {
position: fixed;
top: 10em;
bottom: 10em;
left: 15em;
right: 15em;
overflow-y: auto;
width: auto;
height: auto;
box-shadow: 0 0 3em 1em #000000;
z-index: 999999;
text-align: left;
background-color: #FFFFFF;
padding: 1em;
}
#privacyCloseBtn {
display: inline-block;
margin: 0 auto;
padding-left: 2rem;
padding-right: 2rem;
color: white;
background-color: var(--grass-green);
border: 0.15em solid var(--grass-green);
border-radius: 0.3em;
transition: all 0.3s;
box-sizing: border-box;
height: 3em;
line-height: 2.7em;
cursor: pointer;
/*box-shadow:0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);*/
font-weight: 600;
}
a.privacy {
margin-top: 2em;
text-align: center;
font-size: 0.8em;
color: #808080;
display: block;
}
@media all and (max-width: 65em) {
/* 1040 px */
div.testGroup {
margin-left: -1rem;
margin-right: -1rem;
}
div.testArea {
font-size: 1.5384615vw; /* 16 px */
margin: 1rem;
width: calc(100% - 1rem - 1rem); /* subtract margins */
}
}
@media all and (max-width: 40em) {
/* 640 px */
div.testArea {
font-size: 0.8em; /* 12.8 px */
}
}
</style>
<script type="text/javascript">
function I(id) {
return document.getElementById(id);
}
var meterBk = "#ebecf0"; // ui--input-border
var dlColor = "#02b159", // grass-green
ulColor = "#02b159", // grass-green
pingColor = "#02b159", // grass-green
jitColor = "#02b159"; // grass-green
var progColor = "#0ac9f7"; // sky-blue
function setPageTitle() {
var pageTitleDiv = document.getElementById('pageTitle');
var titlePrefixNode = document.createTextNode('Speed Test:');
var lineBreakElement = document.createElement('br');
var locationNode = document.createTextNode('Unknown');
switch (window.location.hostname) {
case 'us1.zzz.cat':
locationNode.textContent = 'Unites States 1 (Fremont, Linode)';
break;
case 'us2.zzz.cat':
locationNode.textContent = 'Unites States 2 (LAX (CN2), Bandwagon)';
break;
case 'us3.zzz.cat':
locationNode.textContent = 'Unites States 3 (LAX (CN2 GIA-E), Bandwagon)';
break;
case 'jp1.zzz.cat':
locationNode.textContent = 'Japan 1 (Tokyo 2, Linode)';
break;
case 'jp2.zzz.cat':
locationNode.textContent = 'Japan 2 (Tokyo 2, Linode)';
break;
case 'sg1.zzz.cat':
locationNode.textContent = 'Singapore (Singapore, Linode)';
break;
case 'ca1.zzz.cat':
locationNode.textContent = 'Canada (Toronto, Linode)';
break;
default:
locationNode.textContent = window.location.hostname;
break;
}
pageTitleDiv.appendChild(titlePrefixNode);
pageTitleDiv.appendChild(lineBreakElement);
pageTitleDiv.appendChild(locationNode);
}
//CODE FOR GAUGES
function drawMeter(c, amount, bk, fg, progress, prog) {
var ctx = c.getContext("2d");
var dp = window.devicePixelRatio || 1;
var cw = c.clientWidth * dp, ch = c.clientHeight * dp;
var sizScale = ch * 0.0055;
if (c.width == cw && c.height == ch) {
ctx.clearRect(0, 0, cw, ch);
} else {
c.width = cw;
c.height = ch;
}
ctx.beginPath();
ctx.strokeStyle = bk;
ctx.lineCap = "round";
ctx.lineWidth = 4 * sizScale;
ctx.arc(
c.width / 2,
c.height / 2,// c.height/2-58*sizScale,
c.height / 2 - ctx.lineWidth,//c.height/1.8-ctx.lineWidth,
-Math.PI * 1.2,
Math.PI * 0.2
);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = fg;
ctx.lineCap = (amount > 0 ? "round" : "butt");
ctx.lineWidth = 4 * sizScale;
ctx.arc(
c.width / 2,
c.height / 2,// c.height/2-58*sizScale,
c.height / 2 - ctx.lineWidth,//c.height/1.8-ctx.lineWidth,
-Math.PI * 1.2,
amount * Math.PI * 1.2 - Math.PI * 1.2
);
ctx.stroke();
if (typeof progress !== "undefined") {
ctx.fillStyle = prog;
ctx.fillRect(
c.width * 0.3,
c.height - 28 * sizScale,
c.width * 0.4 * progress,
4 * sizScale
);
}
}
function mbpsToAmount(s) {
return 1 - (1 / (Math.pow(1.3, Math.sqrt(s))));
}
function msToAmount(s) {
return 1 - (1 / (Math.pow(1.08, Math.sqrt(s))));
}
//SPEEDTEST AND UI CODE
var w = null; //speedtest worker
var data = null; //data from worker
function startStop() {
if (w != null) {
//speedtest is running, abort
w.postMessage('abort');
w = null;
data = null;
I("startStopBtn").className = "";
initUI();
} else {
//test is not running, begin
w = new Worker('speedtest_worker.js');
w.postMessage('start'); //Add optional parameters as a JSON object to this command
I("startStopBtn").className = "running";
w.onmessage = function (e) {
data = JSON.parse(e.data);
var status = data.testState;
if (status >= 4) {
//test completed
I("startStopBtn").className = "";
w = null;
updateUI(true);
}
};
}
}
//this function reads the data sent back by the worker and updates the UI
function updateUI(forced) {
if (!forced && (!data || !w)) return;
console.log(data);
var status = data.testState;
I("ip").textContent = data.clientIp;
I("dlText").textContent = (status == 1 && data.dlStatus == 0) ? "..." : data.dlStatus;
drawMeter(I("dlMeter"), mbpsToAmount(Number(data.dlStatus * (status == 1 ? oscillate() : 1))), meterBk, dlColor, Number(data.dlProgress), progColor);
I("ulText").textContent = (status == 3 && data.ulStatus == 0) ? "..." : data.ulStatus;
drawMeter(I("ulMeter"), mbpsToAmount(Number(data.ulStatus * (status == 3 ? oscillate() : 1))), meterBk, ulColor, Number(data.ulProgress), progColor);
I("pingText").textContent = data.pingStatus;
drawMeter(I("pingMeter"), msToAmount(Number(data.pingStatus * (status == 2 ? oscillate() : 1))), meterBk, pingColor, Number(data.pingProgress), progColor);
I("jitText").textContent = data.jitterStatus;
drawMeter(I("jitMeter"), msToAmount(Number(data.jitterStatus * (status == 2 ? oscillate() : 1))), meterBk, jitColor, Number(data.pingProgress), progColor);
}
function oscillate() {
return 1 + 0.02 * Math.sin(Date.now() / 100);
}
//poll the status from the worker (this will call updateUI)
setInterval(function () {
if (w) w.postMessage('status');
}, 200);
//update the UI every frame
window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || (function (callback, element) {
setTimeout(callback, 1000 / 60);
});
function frame() {
requestAnimationFrame(frame);
updateUI();
}
frame(); //start frame loop
//function to (re)initialize UI
function initUI() {
drawMeter(I("dlMeter"), 0, meterBk, dlColor, 0);
drawMeter(I("ulMeter"), 0, meterBk, ulColor, 0);
drawMeter(I("pingMeter"), 0, meterBk, pingColor, 0);
drawMeter(I("jitMeter"), 0, meterBk, jitColor, 0);
I("dlText").textContent = "";
I("ulText").textContent = "";
I("pingText").textContent = "";
I("jitText").textContent = "";
I("ip").textContent = "";
}
</script>
</head>
<body>
<div>
<h1 id="pageTitle"></h1>
<div id="test">
<div class="testGroup">
<div class="testArea">
<div class="testName">Download</div>
<canvas id="dlMeter" class="meter"></canvas>
<div id="dlText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
<div class="testArea">
<div class="testName">Upload</div>
<canvas id="ulMeter" class="meter"></canvas>
<div id="ulText" class="meterText"></div>
<div class="unit">Mbit/s</div>
</div>
<div class="testArea">
<div class="testName">Ping</div>
<canvas id="pingMeter" class="meter"></canvas>
<div id="pingText" class="meterText"></div>
<div class="unit">ms</div>
</div>
<div class="testArea">
<div class="testName">Jitter</div>
<canvas id="jitMeter" class="meter"></canvas>
<div id="jitText" class="meterText"></div>
<div class="unit">ms</div>
</div>
</div>
<div id="ipArea">
IP Address: <span id="ip"></span>
</div>
<div id="shareArea" style="display:none">
<h3>Share results</h3>
<p>Test ID: <span id="testId"></span></p>
<input type="text" value="" id="resultsURL" readonly="readonly"
onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
<img src="" id="resultsImg"/>
</div>
</div>
<div id="startStopBtn" onclick="startStop()"></div>
<div id="privacyPolicy" style="display:none;">
<h2>Privacy Policy</h2>
<p>This HTML5 Speedtest server is configured with telemetry enabled.</p>
<h4>What data we collect</h4>
<p>
At the end of the test, the following data is collected and stored:
<ul>
<li>Test ID</li>
<li>Time of testing</li>
<li>Test results (download and upload speed, ping and jitter)</li>
<li>IP address</li>
<li>ISP information</li>
<li>Approximate location (inferred from IP address, not GPS)</li>
<li>User agent and browser locale</li>
<li>Test log (contains no personal information)</li>
</ul>
</p>
<h4>How we use the data</h4>
<p>
Data collected through this service is used to:
<ul>
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
</ul>
No personal information is disclosed to third parties.
</p>
<h4>Your consent</h4>
<p>
By starting the test, you consent to the terms of this privacy policy.
</p>
<h4>Data removal</h4>
<p>
If you want to have your information deleted, you need to provide either the ID of the test or your IP
address. This is the only way to identify your data, without this information we won't be able to comply
with your request.<br/><br/>
Contact this email address for all deletion requests: maddie at zzz dot cat</a>.
</p>
<br/><br/>
<a id="privacyCloseBtn" class="privacy" href="#"
onclick="I('privacyPolicy').style.display='none'">Close</a><br/>
</div>
<div><a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a></div>
</div>
<script type="text/javascript">setPageTitle();</script>
<script type="text/javascript">setTimeout(initUI, 100);</script>
</body>
</html>