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
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
42
43
44
45
46
47
48
49
50
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta name="generator" content="PSPad editor, www.pspad.com">
    <title> Test della progress bar V-meter style </title>
  <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>
  </head>
  <body>
  <script type="text/javascript" language="javascript">
  getPage();
  </script>
      <h1>Test della progress bar V-meter style</h1>   
      <div>
 
        <img id="myProgBar" src="./black.png" alt="progress bar" />
      </div>
  </body>  
</html>

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: