Ajax e PHP: una progress bar V-meter style

Progress bar V-meter styleEcco un’idea per una progress bar un po’ diversa dal solito. L’aspetto è quello dei V-meter digitali degli apparecchi audio. Solo che l’andamento della progressione non è logaritmico ma decimale e percentuale.
Può essere utilizzata come strumento di monitoraggio di operazioni lunghe eseguite sul server perché, grazie alla tecnologia Ajax, è possibile recuperare valori ad intervelli regolari da uno script PHP.

I requisiti per un corretto funzionamento sono:

  • Javascript abilitato
  • PHP con supporto GD 2.0.1 o successivi
  • FreeType library

La progress bar viene generata dinamicamente da uno script PHP che esegue l’eco di un’immagine in formato PNG. I valori passati in querystring servono per colorare le barre. La percentuale viene calcolata normalizzando il valore sul minimo e il massimo, con un’approssimazione per difetto alla decina inferiore. (p.e.: 52% accende 5 barre). Il default per il minimo e il massimo è rispettivamente 0 e 100

Ecco il codice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//==============================================================================
// PROGRESS BAR V-METER STYLE
//==============================================================================
if (!empty($_GET['value'])){
  $value = intval($_GET['value']);
  $min = empty($_GET['min']) ? 0 : intval($_GET['min']);
  $max = empty($_GET['max']) ? 100 : intval($_GET['max']);
}
else{
  $value = 0;
  $min = 0;
  $max = 100;
}
  $nValue = floor((($value-$min) / ($max-$min)) * 100);
  header("Content-type: image/png");
  $string = $nValue." %";
  $font = 'arial.ttf';
  $width  = 110; 
  $height = $width;
  $im = @imagecreatetruecolor ($width,$height);
  $width -=5;
  $height -=5;
  $background_color = imageColorAllocate($im, 0, 0, 0);
  $color = imageColorAllocate($im, 0, 255, 0);
  imagefill($im, 0, 0, $background_color);
  for($i=0;$i<10;$i++){
    $x1 = $width;
    $y1 = $height-2 - ($i*10);
    $x2 = $width-10 - ($i*10);
    $y2 = $height-10 - ($i*10);
    if ($i<(floor($nValue/10))){
      imageFilledRectangle($im, $x1, $y1, $x2,  $y2, $color);
    }
    else{
      imagerectangle($im, $x1, $y1, $x2,  $y2, $color);
    }
  }
  $text_color = imagecolorallocate ($im, 255, 255, 255);
  imagettftext($im, 14, 0, 5, $height-10, $text_color, $font, $string);
  imagepng($im);
  imagedestroy($im);

Volendo una più ampia compatibilità, è possibile evitare di utilizzare la funzione imagettftext() sostituendola con imagestring(), in questo caso vengono utilizzati i font interni con codifica latin2. Però non sono altrettanto belli e le dimensioni possibili sono solo 5. Il valore più grande restituisce una dimensione di carattere piuttosto piccola… ove possibile è preferibile usare i TTF

Questo è il codice di esempio per rappresentare la progress bar in una pagina web con un po’ di Ajax per rigenerare dinamicamente l’immagine ogni 2 secondi:

1
2
3
4
5
6
7
8
9
10
11
12
 
 
 
 
 
  <script type="text/javascript" language="javascript">
    <!-- var xml = ""; function getPage() { var url = "./randgen.php"; if (window.XMLHttpRequest) { xml = new XMLHttpRequest(); } else if (window.ActiveXObject) { xml = new ActiveXObject("Microsoft.XMLHTTP"); } else { alert("Your browser lacks the needed ability to use Ajax"); return false; } xml.onreadystatechange = processPage; xml.open("GET", url, true); xml.send(""); setTimeout('getPage()', 2*1000); } function processPage() { if (xml.readyState == 4) { if (xml.status == 200) { document.getElementById("myProgBar").src="./progbar.php?value=" + xml.responseText; } else { alert("There was a problem retrieving the XML data:\n" + xml.statusText); } } } //-->  
  </script>
 
  <script type="text/javascript" language="javascript">
  getPage();
  </script>

Test della progress bar V-meter style

 

progress bar

 

1
 

Lo script randgen.php genera dei numeri casuali da 0 a 100 solo a scopo dimostrativo, nella pratica dovrà generare il valore da rappresentare nella progress bar.

randgen.php:

1
2
3
4
5
6
7
8
$min = empty($_GET['min']) ? 0 : intval($_GET['min']);
$max = empty($_GET['max']) ? 100 : intval($_GET['max']);
// headers are sent to prevent browsers from caching
header('Expires: Fri, 25 Dec 1980 00:00:00 GMT'); // time in the past
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); 
header('Cache-Control: no-cache, must-revalidate'); 
header('Pragma: no-cache');
echo rand($min,$max);

Il pacchetto completo è scaricabile qui

Conclusioni:

Siccome adoro i V-meter analogici, per capirci quelli che si trovavano sui grandi amplificatori HiFi degli anni ’70, stavo pensando anche a qualcosa del genere per il futuro, peccato che con la grafica ho qualche difficoltà…!

Riferimenti ed approfondimenti: