Kaj je progress bar?
Progress bar je prikazovanje napredka programa. Uporablja se pri programih, katerih izvajanje lahko traja dalj casa. Primer progress bara je recimo v vašem priljubljenem brskalniku, kjer kaže koliko procentov spletne strani je naloženo. Seveda pa ga nikakor ne uporabjamo le za prikaz upload-a ali download-a, pac pa lahko povsod, kjer vemo število korakov, ki jih mora program izvesti.
Slika pove vec kot tisoc besed o tem kaj bom opisal v tem clanku...

Zakaj pa bi naredili svojega, saj ga ima že sam brskalnik?
Zato, ker brskalnik ne ve poteka izvajanja skripte. Od strežnika dobi le podatek o velikosti strani in potem ko postopoma prenaša košcek za košckom spletne strani preracuna koliko spletne strani se je naložilo. Prav tako vcasih ko delamo z ajax-om ne zahtevamo nove strani in tako se z brskalnikovim progress barom ne dogaja nic.
Kdaj lahko in kdaj ne moremo narediti progress bara?
Lahko ga naredimo takrt ko poznamo deloto in lahko spremljamo kdaj je doloceno število korakov opravljeno. Ce recimo pomanjšujemo sliko z phpjem ne moramo spremlljati poteka izvajanja kode, kajti php nadaljuje izvajanje kode šele takrat ko je slika že pomanjšana, tako bi lahko prikazali le nic in sto procentov izvedene kode.
Primer ko pa lahko naredimo progress bar je ko imamo naprimer 100 slik in vsako pomanjšamo z phpjem. Ker je potrebno pomanjšati vsako posebej, lahko spremljamo kdaj se je en korak koncal - torej ena slika je pomanjšana. Za celoto lahko vzamemo 100 slik in vsaka slika bo tocno 1% celote. Seveda je to prelahko da bi delovalo kot bi moralo. Vse slike se ne izvedejo enako hitro, to je namrec odvisno od števila barv, dimenzij itd. Dober rezultat lahko dobimo ce vzamemo za celoto vsota velikosti vseh slik (v bajtih) in nato del te celote predstavlja velikost posamezne slike. Torej vcasih je lahko vec nacinov kako ugotoviti kolikšen del kode (korakov) se je izvedel, seveda se pri takih situacijah odlocimo za najbolj natancno možnost.
Progress bar v PHP-ju
No, pa se lotimo izdelave progress bara v phpju. Problem ki ga opazimo je, da se spletna stran pošlje brskalniku šele ko se izvede celotna php koda, kar pomeni, da ne moremo sproti spreminjati vrednosti progress bara. Kako poslati podatke iz phpja "ven" tako da jih bo lahko brala kakšna druga skripta? Za to je vec nacinov, tukaj vam bom opisal dva, ki sem jih sam že veckrat uporabil in preizkušeno delujeta.
Primer kode, kateri bomo dodali progress bar:
<?php
for($i=1; $i<2000; $i++)
{
for($j=1; $j<1700; $j++)
{
$a=sin($i*$j)+cos($i/$j)+tan($i+$j);
$b=sin($i*$a)+cos($a/$j)+tan($i+$a);
$c=pow($a,$b)/cos($i-$j);
}
} ?>
Koda za izvajanje porabi okoli 20 sekund, kar ni vec tako malo da bi kar preskocili, in morda bi bilo uporabniku prijazneje, ce bi pokazali koliko kode se je že izvedlo.
Torej kako narediti progress bar na tej kodi? Najprej moramo poznati število korakov ki se izvedejo. V našem primeru je ta številka velika - 2000*1700 = 3.400.000. V tem primeru bi en korak pomenil 1/3400000 kar je 0,000003%. Nikakor nebi bilo smotrno sporocati tako majhne spremembe, saj se taka sprememba zgodi zelo hitro - v šestih miljoninkah sekunde. Tako preracunavanje pa nebi bilo smotrno tudi zato, ker vsako preracunavanje delno upocasni kodo. Pri majhnem številu korakov se to nebi poznalo, v našem primeru pa bi se celotna koda lahko upocasnila za 5 sekund in vec kar pa vsekakor ni zanemarljivo.
Optimalno pri tej kodi je, da izracunamo napredek kode za 1% kar se zgodi vsakic, ko se spremenljivka $i poveca za 20. Kako pa bomo ugotovil da se je spremenljivka povecala za 20? Preprosto, kadar je številka deljiva z 20 - to se zgodi kadar je ostanek deljenja nic - $i%20==0.
Ce to dodamo kodi, bo izgledala takole:
<?php
for($i=1; $i<2000; $i++)
{
for($j=1; $j<1700; $j++)
{
$a=sin($i*$j)+cos($i/$j)+tan($i+$j);
$b=sin($i*$a)+cos($a/$j)+tan($i+$a);
$c=pow($a,$b)/cos($i-$j);
}
if($i%20==0) $pct=round($i/2000*100);
}
?>
In napredek kode je shranjen v spremenljivki $pct... samo kaj nam to koristi ko pa tega ne moremo videti? Lahko uporabimo echo... AMPAK vse kar izpišemo z echo se izvede šele po tem ko je vsa koda že izvedena. Na sreco obstaja funkcija flush() ki pošlje vsebino brskalniku, ko se koda še vedno izvaja in tako lahko dobimo podatke iz php-ja v brskalnik.
Po tem ko to dodamo v kodo....
<?php
for($i=1; $i<2000; $i++)
{
for($j=1; $j<1700; $j++)
{
$a=sin($i*$j)+cos($i/$j)+tan($i+$j);
$b=sin($i*$a)+cos($a/$j)+tan($i+$a);
$c=pow($a,$b)/cos($i-$j);
}
if($i%20==0)
{
$pct=round($i/2000*100);
echo($pct."%<br>");
flush();
}
}
?>
Tale koda pa ni kaj prevec prijazna uporabniku... izpiše namrec nekaj takega:
13%
14%
15%
16%
17%.....
Seveda pa se da to prav lepo spremeniti... ce uporabimo malo javascripta. Lepo je, ce se zraven pojavi tudi progress bar... to o cemer govori clanek.
No pa se lotimo dela... namesto echo($pct."%<br>"); napišemo echo("<script>pg(".$pct.")</script>"); nato pa se lotimo pisanja javascript funkcije pg() ki bo spreminjala progress bar. Kratko ime funkcije sem izbral le zato, ker se na koncu nabere veliko tega v izvorni kodi kar pa ni najboljše.
Torej kako bi sploh ustvarili izgled progress bara? En div v drugem :) Prvi ima fiksno širino, v našem primeru 250 pikslov, drugemu pa se širina spreminja glede na to koliko procentov kode se je izvedlo. Da bo progress bar izgledal "lepše" bomo drugemu divu za ozadje nastavili tole sliko: No da ne bom prevec zakompliciral vsega, to dosežemo s to kodo:
<div style='padding-left:0px; width:250; height:16px; border:1px solid navy;' id='ldiv'>
<div style='padding-left:0px; padding-top:1px; position:absolute;width:250;text-align:center; font-family:verdana;font-size:12px;' id='ldiv3'>0%</div>
<div style='padding-left:0px;width:0; height:16px; background:url(progress-bar.gif);text-align:right;font-family:verdana;' id='ldiv2'>
</div>
</div>
Do konca še <span id='do_konca'>neznano</span> sekund.
ldiv - Glavni div z modro obrobo
ldiv2 - Div, ki spreminja širino in tako kaže napredek kode
ldiv3 - Div na sredini, ki z številko kaže napredek
do_konca - Span, ki kaže ocenjen preostali cas izvajanja kode
seveda lahko zgornjo kodo po želji spremenite, tako da bo izgled drugacen... samo naj bo v principu enaka. No sedaj pa javascript funkcije...
<script language='javascript'>
<!--
function pg(pct) { sirina=Math.floor(pct/100*250); //izracunamo širino glede na procente document.getElementById('ldiv2').style.width=sirina; //Nastavimo širino divu
document.getElementById('ldiv3').innerHTML=pct; //Pokažemo procente z številko }
//--> </script>
Tako... progress bar deluje... kaj pa racunanje preostalega casa? Hmm...
Vsekakor moramo meriti cas, ki ga potrebuje koda da opravi 1%. Cas bomo merili kar z javascriptom, saj ni potrebe da bi to delal php, pa še lažje bo dostopen.
Preostali cas bomo izracunali po sledecem algoritmu:
- Ko se nalaganje zacne zacnemo meriti cas
- Vsakic ko se procenti spremenijo izracunamo koliko casa koda potrebuje za 1%
- Glede na razmerje med casom in procenti (procenti na sekundo) izracunamo cas do konca
Da bo izracun casa cim bolj natancen, moramo zaceti meriti cas ko se koda zacne izvajati, tako da na zacetek kode dodamo:
echo("<script>start_progress()</script>"); flush();
<script language='javascript'>
<!--
cas=0; //definiramo spremenljivko cas
//Funkcijo klicemo na zacetku nalaganja, da zacnemo meriti cas function start_progress() { date=new Date(); cas=date.getTime(); }
function pg(pct) { sirina=Math.floor(pct/100*250); //izracunamo širino glede na procente document.getElementById('ldiv2').style.width=sirina; //Nastavimo širino divu document.getElementById('ldiv3').innerHTML=pct; //Pokažemo procente z številko
date=new Date(); razlika=date.getTime()-cas; //Porabljen cas na_sekundo=pct/razlika; //Izracunamo procente na sekundo
//Deljimo s 1000 ker javascript sporoca cas v milisekundah do_konca=Math.round((100-pct)/na_sekundo/1000); //Ocenjen cas do konca v sekundah document.getElementById('do_konca').innerHTML=do_konca; //Pokažemo cas do konca }
//--> </script>
Celotno kodo primera dobite TUKAJ
Obstaja še en nacin, ki ga uporabimo takrat ko zgoraj opisanega iz takšnih ali drugacnih razlogov ne moremo. To storimo tako, da z phpjem procente zapišemo v datoteko, te pa se nato preberejo v brskalniku z AJAX-om. |