0

I have a little JavaScript AJAX script that gets the speed on progress in kbps or whatever - let's say MB/s. And now I want add a gauge that shows the speed graphically.

I would have a image containing the gauge design and another with the pointer. The pointer by default points at the top - the lowest value would be -120deg and highest 120deg. But that wouldn't be nice if someone has a 1mb connection, so I need to add an exponential calculation.

Here are the values...

  • 0-1MB: -120deg -> -90deg
  • 1-5MB: -90deg -> -60deg
  • 5-10MB: -60deg -> -30deg
  • 10-20MB: -30deg -> 0deg
  • 20-30MB: 0deg -> 30deg
  • 30-50MB: 30deg -> 60deg
  • 50-75MB: 60deg -> 90deg
  • 75-100MB: 90deg -> 120deg

I totally don't know how to start with the calculation.

The animation is done by CSS

-webkit-transform:rotate(Xdeg)

and it would update on

xhr.onprogress

the calculation to get the speed is:

kb/s=((e.loaded/((new Date()-start)/1000))/1024).toFixed(2),
MB/S=(d/1024*8).toFixed(2)

When I have the MB/s I just want to set the gauge deg.

How can I achieve these values?

Here is a not-completely-working variant. I wrote it with while but I think that it's not the proper way.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>gauge</title>
<style>
img{position:fixed;top:100px;left:100px;}
</style>
<script>
var b=[1,5,10,20,30,50,75,100,150],
deg=30;
get=function(a){
 var l=b.length
 while(l--){
  if(b[l]<=a&&a<b[l+1]){
   rotation=((l*deg)+(deg/(b[l+1]-b[l])*(a-b[l])));
   pointer=document.getElementsByTagName('img')[1]
   pointer.style['-webkit-transform']='rotate('+(rotation-120)+'deg)';
   console.log(rotation)
  }
 }
}
</script>
</head>
<body>
<input onChange="get(this.value)">
<img src="gauge1.png"><img src="pointer.png">
</body>
</html>

It does not work with values under 5 and over 150.

EDIT here is the WORKING code for what i need

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>gauge</title>
<style>
img{position:fixed;top:100px;left:100px;}
.pointer{-webkit-transform:rotate(-120deg);}
input{width:100%;}
</style>
<script>
var pointer,
get=function(a){
 var b=[0,1,5,10,20,30,50,75,100],l=b.length,c=30,x=-120;
 if(a>=b[l-1]){
  x=120;
 }else{
  while(l--){
   if(b[l]<a&&a<=b[l+1]){
    x=(c*l-120)+c*((a-b[l])/(b[l+1]-b[l]));
    break;
   }
  }
 }
 pointer.style['-webkit-transform']='rotate('+x+'deg)';
}
window.onload=function(){
 pointer=document.getElementsByClassName('pointer')[0];
}
</script>
</head>
<body>
<img src="gauge1.png"><img class="pointer" src="pointer.png">
<input type="range" min="0" max="100" value="0" onChange="get(this.value)" step="0.1">
</body>
</html>
Andy
  • 49,085
  • 60
  • 166
  • 233
cocco
  • 16,442
  • 7
  • 62
  • 77
  • Where's your existing code? What have you tried? What research have you done on the subject? Sounds to me like you'll be needing some trigonometrical functions! – DevlshOne Aug 13 '13 at 16:14
  • huh trigonometrical funtions... long time i didn't heard this word..and thats why i don't even know what to search for.. – cocco Aug 13 '13 at 16:15
  • What part are you having trouble with? Are you having trouble animating/rendering the gauge? or you having trouble translating between magnitude(mb/s) and degrees? – Sam I am says Reinstate Monica Aug 13 '13 at 16:16
  • sine, cosine, tangents... all mathematical functions you'll need to create your speed gauge. – DevlshOne Aug 13 '13 at 16:17
  • 1
    awww. sine cosine... TANGENTS... looks like it's to much asked...yeah thats the problem.i don't know how to get the ???magintude??. – cocco Aug 13 '13 at 16:17
  • i know only that i have for example 5,5 MB/s speed... how do i get the 30 and something deg that end up beeing -55deg or something like that by removing 120deg. – cocco Aug 13 '13 at 16:20
  • 1
    You should be able to adapt my answers in http://stackoverflow.com/questions/8731326/javascript-slider-weighted-values/9135087#9135087 . – Andrew Morton Aug 13 '13 at 16:26
  • What do you mean by "exponential"? Are you talking about a logarithmic scale? – Bergi Aug 13 '13 at 18:23
  • maybe i mean a alogarithmic scale?? .. it's needs to be fluid as possible.. so the less calc and loops are involved then better it is... i need to get the rigth position of the pointer inside the gauge based on the mb's – cocco Aug 13 '13 at 18:26
  • You're missing `0` as the first element of the array. That same line ends with a `,` instead of a `;`. If the input value is greater than the maximum (last) value in the array, just set the input value to the last element in the array. – Andrew Morton Aug 13 '13 at 18:58
  • You could do this by making the formula for the angle vary with the [logarithm](http://en.wikipedia.org/wiki/Logarithm) of the speed. The formula would probably be of the form `a * log(mbps, base b) - 120`. Where `a` and `b` would be numbers chosen to fit your curve, and `mbps` is the input. – Rory O'Kane Aug 13 '13 at 19:02
  • the , is right because else i need to write var 2 times. – cocco Aug 13 '13 at 19:03
  • I adde a possible answer... i hope that any better soluitions come out. – cocco Aug 13 '13 at 20:38
  • Re: comma - ooh sorry, I missed that :blush – Andrew Morton Aug 13 '13 at 20:38
  • @cocco I have what I think is a much cleaner solution for you. Please look over my answer carefully and let me know if you don't understand it. – Timothy Shields Aug 13 '13 at 22:29
  • [0,1,5,10,20,30,50,75,100] each of this steps is separated by exactly 30deg. imagine [0,1,2,98,99] from 2 to 98 it should rotate 30deg.also from 1 to 2 – cocco Aug 13 '13 at 23:42

2 Answers2

4

Formulation of exponential function fitting your specifications

Let d be degrees in [-120 , 120].

Let f(d) be the download speed in MB/S, where f(d) = a * RATEd + b.

Let MIN and MAX be the download speeds corresponding to -120 degrees and 120 degrees, respectively.

Then we have the following two equations.

MIN = f(-120) = a * RATE-120 + b

MAX = f(120) = a * RATE120 + b

We can solve for a and b as follows.

MAX - MIN = a * (RATE120 - RATE-120)

=> a = (MAX - MIN) / (RATE120 - RATE-120)

=> b = MIN - a * RATE-120

Now you choose MIN, MAX, and RATE. The inverse of function s(d) is what you will use to map a speed in MB/S to a value in degrees.

d = f-1(s) = logRATE((s - b)/a)


Magic formula ready for use

If you choose MIN = 0.1 MB/S = 100 kB/S, MAX = 100 MB/S, and RATE = 1.011662, you get f-1(20) = 0 as well. The function then becomes this:

d = f-1(s) = log1.011662 ((s + 6.488681037) / 26.48810966)

And it looks like this:

enter image description here

Notice the three key points that are passed through:

  • (0.1 MB/S, -120 degrees)
  • (20 MB/S, 0 degrees)
  • (100 MB/S, 120 degrees)

In JavaScript, the formula looks like this:

d = Math.log((s + 6.488681037) / 26.48810966) / Math.log(1.011662)

where s is a speed in MB/S and d is the degrees you should use.

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • how doi write this formulain javascript? – cocco Aug 13 '13 at 23:14
  • @cocco I just updated the answer with a JavaScript formula that you can try out. – Timothy Shields Aug 13 '13 at 23:17
  • yeah this wouldbe great... but it's not precise.. 0-1MB/s should be in the 30deg range. and as you can see the 5-10 and 10-20 have the step the same size... – cocco Aug 13 '13 at 23:17
  • Math.log ... gives alot of NAN – cocco Aug 13 '13 at 23:22
  • @cocco I'm trying this on my end and it's working perfectly fine. – Timothy Shields Aug 13 '13 at 23:28
  • i had to a*1 as it saw it as a string but the curve is wrong ... i need steps. check my answer and just replace the whole get function with your... and check the gauge images i added as datauri – cocco Aug 13 '13 at 23:32
  • at 1MB/s the gauge is at 0.3MB/s,at 10MB/s the gauge is at 8.5MB/s – cocco Aug 13 '13 at 23:34
  • the solution would be fantastic as it does not need while loops and mancy if's but i think this doesn't allows you to differ precisely every 30deg. – cocco Aug 13 '13 at 23:38
  • [0,1,5,10,20,30,50,75,100] each of this steps is separated by exactly 30deg. imagine [0,1,2,98,99] from 2 to 98 it should rotate 30deg.also from 1 to 2 – cocco Aug 13 '13 at 23:44
  • your solution is great.. prolly with a stronger curve at the start it would be perfect for exactly this values... but at the other side it's hard to draw a nice gauge with the indicators not separated at the same distance.anyway +1 – cocco Aug 13 '13 at 23:53
  • except that it's short ... but would this be faster using the Math.log functin vs the while "short" loop? – cocco Aug 14 '13 at 00:03
  • @cocco I should clarify. My solution will **not** exactly line up with your table. My solution is fitting an exponential curve to your data so that the transform between MB/S and degrees is smooth. The three points I listed at the end of my answer are the three points from your table that the curve passes through. The rest of the rows in your table may not be passed through by the curve. – Timothy Shields Aug 14 '13 at 01:10
0

This is a working code for what i need. but i know you guys have a better way.

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>gauge</title>
<style>
img{position:fixed;top:100px;left:100px;}
.pointer{-webkit-transform:rotate(-120deg);}
input{width:100%;}
</style>
<script>
var pointer,
get=function(a){
 var b=[0,1,5,10,20,30,50,75,100],l=b.length,c=30,x=-120;
 if(a>=b[l-1]){
  x=120;
 }else{
  while(l--){
   if(b[l]<a&&a<=b[l+1]){
    x=(c*l-120)+c*((a-b[l])/(b[l+1]-b[l]));
    break;
   }
  }
 }
 pointer.style['-webkit-transform']='rotate('+x+'deg)';
}
window.onload=function(){
 pointer=document.getElementsByClassName('pointer')[0];
}
</script>
</head>
<body>
<img src="gauge1.png"><img class="pointer" src="pointer.png">
<input type="range" min="0" max="100" value="0" onChange="get(this.value)" step="0.1">
</body>
</html>

here are the images

    <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGUAAABlCAMAAABjot39AAACJVBMVEVpaWlmZmaampptbW1xcXGK
ioqCgoJ2dnalpaWZmZmmpqZra2ttbW19fX2GhoZubm6jo6OZmZlra2t0dHSdnZ1paWl4eHibm5uU
lJSSkpJ6enqpqamCgoJra2uPj4+oqKhzc3N3d3efn5+ZmZl6enpubm6goKCfn5+NjY13d3erq6un
p6dra2uPj4+GhoaoqKhtbW2AgIBubm5tbW19fX1ra2uOjo6qqqqdnZ2WlpapqamIiIiAgICqqqqQ
kJBsbGxzc3OkpKRtbW1+fn6bm5urq6uIiIiWlpZ1dXWkpKSgoKCPj49ra2tsbGyMjIyGhoZ+fn6o
qKiKioqhoaF8fHyEhISTk5OioqJ3d3d7e3uVlZVxcXFwcHCkpKSsrKxvb2+hoaFubm6Hh4dvb2+q
qqqJiYmfn5+goKCDg4OTk5Nzc3OioqKRkZFubm6qqqp2dnZvb2+EhISmpqaDg4P///9eXl7d3d0u
Li7t7e1ubm5NTU3Nzc0NDQ2pqan0crR+fn6NjY329vZVVVXV1dUmJiZ1dXUYGBg4ODixsbGVlZXl
5eW9vb1lZWVERETFxcWFhYUGBgahoaH8brQ/Pz+1tbX4+PhaWlrZ2dn8ZrQqKirkgrSZmZnp6elq
ampJSUnJyckICAilpaXUiqwWFhY3Nzd5eXmJiYnx8fFSUlLR0dHUdqQhISGsrKxxcXGRkZHh4eG5
ublhYWFBQUGdnZ3BwcGBgYEAAAAixRikAAAAdHRSTlPRYq8yo8l02cFKgbMUs89M6d2H5Y/nXhIu
z8n568uNTvHBw2iPXKH7KKPNMLH7XI/r3d1sMI+xs07rZI9K3Vh004n1aLnp9XLx1aPn0SjPhfvJ
sde7y8dcg05eg7/xjcvTsQKPcBKBMOWF6fH1ZErT+2KhBLKdFtgAAAjiSURBVGiBtZqNt9xEFcCj
BUTko1hFoUWhUJHiBx+VioAotQgKpaBYkGJlQapCFdmw7iOdk6zL1mRTk85pSg4n+xrn1KTkdDbJ
I8n+fd6Z7Nvvr+5m7znvnfPeeW9+ez/mzp17RyiVF5QHjt3wwfXP7XwDY/zuzj/u/dU7x06WFv1n
YaE//PYPX9qNBoUQArT79n7txwuRFqD85CAQKKWqxSS2VJVuozBOnF/c8425a8yj/O0gENQ4NVxJ
klwjTVNdj2MdvlkMBqAkcb745Tkazaa8/SSlVuoGddu264GUxiqo0CGIxnoKxNjqgpxb75nJmUV5
+zBVU6leAakHrqGraktshpoktjBGqpWrxDUCzmO/nMGZQTlMLSOoRFGlLhnMQIioVKmhCpLrkYa5
p8BVca4Q4/x+6lrTKCdfQlYa2FHFDgwdXACCsOaHVV/8V4OIYcIoubBoYBRH+903p6w2hfJzQmNw
B7NTrKr5aigJUTP0xP8MUVhQg0AMACb8y2SzTabsR6puuLmzex+aJKiqZNmAxTgEO5rGCOybo93+
3UkLTqTstnS3FqmfXRAjLSGoRzFEUUTg/Sbu/RZUEUXJ1JpikDigkPbeTyesOIHyB6pLQdCytcua
X00d3LdNojHpaFoy8EtHcUTTDj6L4RPBLtXCb41bbZxyUDXsqJ66EhYveWlF6y/IfAwLdTAmPTtC
SKSi0RZxh4hMb/gk4aNjmDHKfsuttCKXGlIibp0ZpLC8QtiuHPAVDzyz6ohnL+YhwTFH/lSaTdlv
SVGrGcTYkPxa/GlrwGLb0hn8AWFVU6rEptshMREzQgFIsxUFOsVGoJCaqA94fwrFYt7/d9QLCYZR
RjDDlBwi6SoLUAhO7fyHY5BhySPZuxL2Q4Jjrh3yzRDl4DaEdtM6uHo2hIcExufgqx8SHPPyIGaI
orpRDsldzaR9fjaF/93WRYSGQoIkofL4FAo1Kj1IT06TORg64imOwU7o/6A0iYJ0G6JrBEKdrbmQ
RmNcQ6wpz/STTZ+yP663WvVUnbDM1QtzjX9zzzV9iuo2W7ZhFQLhmSf0XxyjgL2adgGa9IocUMY8
UBqhWEFU1ymZsz3mM1hgwx4AAWVeGaFQw7Z14jh4NQzPLyFP3ZqjKWY3zrqUw3G94rpwfJCxtHV1
lATDIpZZEWtI00L/z3kAdCnUrdTPJNXMHDzQlxA4mUXF8+KqGV++ooEy1w1QDlv1ZkB9UawoyQK7
cDZFjExb37okUg08s4crk1OoEUUGUbKLouqsRIEKJMuqup2dyYCSOIp5qEd5Ug2adkxC36l98vlq
FDjU/Cb2WmZccxKchOZDTBlOoWklklRcF8VA2+q0V6KkcNx8wrxPIV6x42dP9ChSVEnBpo7mwEl0
/rSzPIUop/8HUQzBzDYF5Gbzpi4FWfUoiCnfUGy7kLPLU9BWku9KdtwgZsCjcGxySlqpGNuXkqUB
25i+5HVUdiinsM0ymvALkq7JgLJbDSpSUbl4RBAOzaOlElAQZBdjParwyJZf45TUhmy8JmGOuZdR
IB1DhK1JWDK4Ayi7qWu7a3ILp5heSXgAUclel1u4Y0zvgHAMqUE9XRckd/9twg3ICoK1OZ+535df
FT5AcbA+5/Mgk+8XrgeKZBWQW4Yl79Wwdg1Q7haeQ3rgQu1CCsXk9zYu4JcvCTuBYqA8iRZIYcdI
yARKDHmX8AbSpZTgy/Xx69AqFMwKIh1uUKJjys8KGMWSjkkUjF/tVqI4YVgx1aqcmabcYBS30+k0
nE4uhUD4Ss6VzllRjOWMUyxXh+t0oBWsi2EoiilrIpK9tvAuUl0oXY16wRbDF5j/TadGM+8uiDFq
6AS7RXvfuuAkTp3dnzPvr8JvCE2hfhnsRxRB6Zb+oI5ieruEvZxSRGExROFtDn7Phsx/XPgOQTov
YApkdDn8tsQy/zXCOxBkhd3zJsCA0nhdOIaRmq4vJ0MRkzX2CScxOGaNlETJ2juE0n0ExWuq+Wh+
vLRZDQOOWRsFEc33TnAKofq63M9qy8ZbjAKbPl4bhbnlFkaBBKbGazIZ1BZem9fJoAxdE4XvluP5
zQJMZq3HZGAwuX0qp7Ccbw2msvFO1MLLosbQyAkM9v6NOYUpo9Lt+x492/GWh5B250PeimSdZ7gj
ZY03t2+vcNEkvPENOP/cR8trwkcXn59rsNIl1BwHNgtEWJdyK6ubaI119a98vDSDOTuxqz7r+YcZ
68SEStZ4uHffL7NxQ033q9p//VVOADjt7apcCTxXD6tZXFPgyH+k3yF5TAuRaH7kr1hiQOCiqifi
RiJK/sVMTBobDw70YcqhgsRL/xzq6i+nC6M4QLHVTz8WnY3NpwY7V79Wwlo8NAdZikISWs3AYoFt
VTOr5m1+fag/VlZ8Uhua6SwlBKuXFfB+k3tf29z8wlCvr3xEURRtVQjdHg9AFQ6lS3tTKA1Tyt8P
tVWblnxX8gEzG1353sbmjtEebDlcWZOc051lQ5rc+Op41/r2QihdFj+In5/QGy+/VxiG9cWy9tMv
TOjzF2WzHAL22jdxZlGYa3Kn/GjalOfRIjB50brxvamzpPKR1TEMAkF85/S5GNucK2JYox/2o3Dj
jBlfjsHLXwC4472N54ch47PXa5Vw6RzADnoWXXeOQCbMkV9WuHOW4LAsBqfjxlfmz5HL5cd9ZZmU
hvgsTG5DCC8wEwd5xr9qdRBXBPz+9L4JK05+q3Czn3tnYQ5jhL4MLnlh0oJT3l28aHbNtgiHN5A0
JfPakIWv4t0FyCuck8zvaHFbaWCsxsaJHVNWm/4e5h97TGa3BM8AofwlDByMcqP94Kmp725mve25
bo9pQhw4Cc4HEKOA/PGQpviZB4ynlnvbA3LooYwpxEgMRUj/YRfpdiZ8kzEefmTpd0pMnrjpaGbm
JPbgpdsl5O9fQqWLeP/NW1Z6c5Ur9NujcsZQvtIXHwCZDIj28VOj+WQpCshr997hebIMsFxk2fMa
QDjx1jwtrobC5MBtr95/9993PQur37XrZ8eveX3fjoXf9f0ftqCXMIzXg8gAAAAASUVORK5CYII="><img class="pointer" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGUAAABlBAMAAACmUjD8AAAAGFBMVEUAAAAAAACvr68AAAAAAAD7
+/v///8w/wBT0ZSsAAAABnRSTlNIJAIwGAJbm9I6AAAAWElEQVRYhe3WwQmAMAwF0M4idJFO0Is9
K+7g/F3ACs2hiLx/DY8PuSQp77OpiWE+Ycpo8mLOgLkYhmEY5r+mHtu0aXdZ0hPaQeTWR36KYRiG
YRiGYZgH0wE4cpP+NNw9cwAAAABJRU5ErkJggg==">
cocco
  • 16,442
  • 7
  • 62
  • 77
  • If it works well, you might as well mark it as the answer. If the answers I pointed to helped you, it would be appreciated if you could give the appropriate one an up-vote :) – Andrew Morton Aug 13 '13 at 20:47
  • it's not a good solution ... like mine... i don't accept it for now. i hope for better answers.there must be away to remove the while loop. – cocco Aug 13 '13 at 20:55
  • As there is no direct mapping from the input value to the output value, you need to iterate over the elements. It will be very fast. The only change you might make is to break out of the loop when a value is found in the if statement, if that makes you happier. – Andrew Morton Aug 13 '13 at 21:03
  • how you break out the while function? this will be part of a bigger function... so i can't use return. – cocco Aug 13 '13 at 21:10
  • break stops the loop. – cocco Aug 13 '13 at 21:25