info@gabrieleferri.it :: mobile: +39 346 8642134
home » laboratorio » Label nel grafico radar delle pChart
Uno dei grafici con un utilizzo più particolare e mirato è il grafico di tipo "radar"; quando capita di doverlo utilizzare per particolari applicazioni php, ci si trova sempre di fronte ad un dilemma: o scriverselo da zero utilizzando le librerie GD
oppure andare alla ricerca di librerie (preferibilmente a costo zero) che ti possano fare il grafico radar.
Dopo il sostanziale fallimento del package Pear Image_Graph, la mia ricerca si è fermata (almeno per ora) quando ho scoperto le librerie pChart.
Ho scelto pChart perché innanzi tutto sono facilmente configurabili e permettono di fare grafici eleganti, grazie alle varie personalizzazioni nella configurazione.
Le label proposte nella documentazione relativa agli esempi di base, si limitano a segnare il livelli del grafico senza definire i valori dei vertici del radar disegnato.
La documentazione offre il metodo writeValues per scrivere i valori per cui, dopo aver disegnato il radar, aggiungo la seguente parte di codice all'esempio mostrasto nel tutorial:
$Test->setFontProperties(LIBS_PATH."/Fonts/tahoma.ttf",8);
$Test->writeValues($DataSet->GetData(),$DataSet->GetDataDescription(),array("Serie1", "Serie2"),20,$MaxVal);
Il risultato è il seguente:
Per i grafici radar non vengono gestite le posizioni delle label nei vertici per cui è necessario ridefinire quantomeno il metodo writeValues nella classe pChart.class
Ho chiamato l'estensione della classe pChart, LabelRadarpChart ridefinendo i metodi drawRadarAxis e writeValues.
Al metodo drawRadarAxis ho aggiunto il passaggio di un altro parametro che ho chiamato $writeValues e che mi serve per gestire la scrittura o meno dei valori dei livelli della ragnatela, questo perché l'eventuale scrittura dei valori sui vertici potrebbe produrre un grafico illeggibile.
Le modifiche sostanziali sono:
function drawadarAxis($Data,$DataDescription,$Mosaic=TRUE,$BorderOffset=10,$A_R=60,$A_G=60,$A_B=60,$S_R=200,$S_G=200,$S_B=200,$MaxValue=-1,$writeValues=TRUE) {
[....]
if($writeValues){
for ( $t=1; $t<=$MaxValue; $t++) {
$TRadius = ( $Radius / $MaxValue ) * $t;
$Angle = -90 + 360 / $Points;
$X1 = $XCenter;
$Y1 = $YCenter - $TRadius;
$X2 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;
$Y2 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;
$XPos = floor(($X2-$X1)/2) + $X1;
$YPos = floor(($Y2-$Y1)/2) + $Y1;
$Positions = imagettfbbox($this->FontSize,0,$this->FontName,$t);
$X = $XPos - ( $X+$Positions[2] - $X+$Positions[6] ) / 2;
$Y = $YPos + $this->FontSize;
$this->drawFilledRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,240,240,240);
$this->drawRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,220,220,220);
imagettftext($this->Picture,$this->FontSize,0,$X,$Y,$C_TextColor,$this->FontName,$t);
}
}
}
Il metodo writeValues è stato ridefinito prevedendo la gestione di $BorderOffset, così com'è previsto nel metodo drawadarAxis, e di $MaxValue
nel caso in cui si voglia definire in modo autonomo il valore massimo di rappresentazione del radar.
Da notare anche il settaggio del parametro $C_SetTextColor, se vero, scrive i valori delle label con lo stesso colore dell'area che viene rappresentata;
i valori risultano poco leggibili ed è per questo che preferisco non utilizzare tale settaggio. Tuttavia se si pensa di voler impostare un colore specifico per ogni serie rappresentata,
sarà opportuno ripensare al parametro come un array e non più una variabile booleana.
Il metodo risulta così definito:
function writeValues($Data,$DataDescription,$Series,$BorderOffset=10,$MaxValue=-1,$C_SetTextColor=FALSE) {
/* Validate the Data and DataDescription array */
$this->validateDataDescription("writeValues",$DataDescription);
$this->validateData("writeValues",$Data);
$Points = count($Data);
$Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;
$XCenter = ( ( $this->GArea_X2 - $this->GArea_X1 ) / 2 ) + $this->GArea_X1;
$YCenter = ( ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 ) + $this->GArea_Y1;
if ( !is_array($Series) ) { $Series = array($Series); }
/* Search for the max value */
if ( $MaxValue == -1 ) {
foreach ( $DataDescription["Values"] as $Key2 => $ColName ) {
foreach ( $Data as $Key => $Values ) {
if ( isset($Data[$Key][$ColName]))
if ( $Data[$Key][$ColName] > $MaxValue && is_numeric($Data[$Key][$ColName])) { $MaxValue = $Data[$Key][$ColName]; }
}
}
}
foreach($Series as $Key => $Serie) {
$ID = 0;
foreach ( $DataDescription["Description"] as $keyI => $ValueI ) { if ( $keyI == $Serie ) { $ColorID = $ID; }; $ID++; }
$Angle = -90;
$XLast = -1;
foreach ( $Data as $Key => $Values ) {
if ( isset($Data[$Key][$Serie]) && is_numeric($Data[$Key][$Serie])) {
$Value = $Data[$Key][$Serie];
$Strength = ( $Radius / $MaxValue ) * $Value;
$XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter;
$YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter;
$Angle = $Angle + (360/$Points);
$Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Value);
$Width = $Positions[2] - $Positions[6];
$Height = $Positions[3] - $Positions[7];
$XOffset = $XPos - ($Width/2);
$YOffset = $YPos + ($Height/2);
if ($C_SetTextColor) $C_TextColor =$this->AllocateColor($this->Picture,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);
imagettftext($this->Picture,$this->FontSize,0,$XOffset,$YOffset,$C_TextColor,$this->FontName,$Value);
}
$XPos = $XPos + $this->DivisionWidth;
}
}
}
La classe estesa LabelRadarpChart è pronta per essere utilizzata tenendo presente che ora sarà necessario includere nello script php la nostra classe e si dovrà istanziare la classe estesa:
include_once(LIBS_PATH."/pChart/LabelRadarpChart.class");
[...]
$Test = new LabelRadarpChart(500,333);
[...]
$Test->drawRadarAxis($DataSet->GetData(),$DataSet->GetDataDescription(),TRUE,20,120,120,120,230,230,230,$MaxVal,FALSE);
Il risultato è il seguente: