1<?php 2 /* 3 pBubble - class to draw bubble charts 4 5 Version : 2.1.3 6 Made by : Jean-Damien POGOLOTTI 7 Last Update : 09/09/11 8 9 This file can be distributed under the license you can find at : 10 11 http://www.pchart.net/license 12 13 You can find the whole class documentation on the pChart web site. 14 */ 15 16 define("BUBBLE_SHAPE_ROUND" , 700001); 17 define("BUBBLE_SHAPE_SQUARE" , 700002); 18 19 /* pBubble class definition */ 20 class pBubble 21 { 22 var $pChartObject; 23 var $pDataObject; 24 25 /* Class creator */ 26 function pBubble($pChartObject,$pDataObject) 27 { 28 $this->pChartObject = $pChartObject; 29 $this->pDataObject = $pDataObject; 30 } 31 32 /* Prepare the scale */ 33 function bubbleScale($DataSeries,$WeightSeries) 34 { 35 if ( !is_array($DataSeries) ) { $DataSeries = array($DataSeries); } 36 if ( !is_array($WeightSeries) ) { $WeightSeries = array($WeightSeries); } 37 38 /* Parse each data series to find the new min & max boundaries to scale */ 39 $NewPositiveSerie = ""; $NewNegativeSerie = ""; $MaxValues = 0; $LastPositive = 0; $LastNegative = 0; 40 foreach($DataSeries as $Key => $SerieName) 41 { 42 $SerieWeightName = $WeightSeries[$Key]; 43 44 $this->pDataObject->setSerieDrawable($SerieWeightName,FALSE); 45 46 if ( count($this->pDataObject->Data["Series"][$SerieName]["Data"]) > $MaxValues ) { $MaxValues = count($this->pDataObject->Data["Series"][$SerieName]["Data"]); } 47 48 foreach($this->pDataObject->Data["Series"][$SerieName]["Data"] as $Key => $Value) 49 { 50 if ( $Value >= 0 ) 51 { 52 $BubbleBounds = $Value + $this->pDataObject->Data["Series"][$SerieWeightName]["Data"][$Key]; 53 54 if ( !isset($NewPositiveSerie[$Key]) ) 55 { $NewPositiveSerie[$Key] = $BubbleBounds; } 56 elseif ( $NewPositiveSerie[$Key] < $BubbleBounds ) 57 { $NewPositiveSerie[$Key] = $BubbleBounds; } 58 59 $LastPositive = $BubbleBounds; 60 } 61 else 62 { 63 $BubbleBounds = $Value - $this->pDataObject->Data["Series"][$SerieWeightName]["Data"][$Key]; 64 65 if ( !isset($NewNegativeSerie[$Key]) ) 66 { $NewNegativeSerie[$Key] = $BubbleBounds; } 67 elseif ( $NewNegativeSerie[$Key] > $BubbleBounds ) 68 { $NewNegativeSerie[$Key] = $BubbleBounds; } 69 70 $LastNegative = $BubbleBounds; 71 } 72 } 73 } 74 75 /* Check for missing values and all the fake positive serie */ 76 if ( $NewPositiveSerie != "" ) 77 { 78 for ($i=0; $i<$MaxValues; $i++) { if (!isset($NewPositiveSerie[$i])) { $NewPositiveSerie[$i] = $LastPositive; } } 79 80 $this->pDataObject->addPoints($NewPositiveSerie,"BubbleFakePositiveSerie"); 81 } 82 83 /* Check for missing values and all the fake negative serie */ 84 if ( $NewNegativeSerie != "" ) 85 { 86 for ($i=0; $i<$MaxValues; $i++) { if (!isset($NewNegativeSerie[$i])) { $NewNegativeSerie[$i] = $LastNegative; } } 87 88 $this->pDataObject->addPoints($NewNegativeSerie,"BubbleFakeNegativeSerie"); 89 } 90 } 91 92 function resetSeriesColors() 93 { 94 $Data = $this->pDataObject->getData(); 95 $Palette = $this->pDataObject->getPalette(); 96 97 $ID = 0; 98 foreach($Data["Series"] as $SerieName => $SeriesParameters) 99 { 100 if ( $SeriesParameters["isDrawable"] ) 101 { 102 $this->pDataObject->Data["Series"][$SerieName]["Color"]["R"] = $Palette[$ID]["R"]; 103 $this->pDataObject->Data["Series"][$SerieName]["Color"]["G"] = $Palette[$ID]["G"]; 104 $this->pDataObject->Data["Series"][$SerieName]["Color"]["B"] = $Palette[$ID]["B"]; 105 $this->pDataObject->Data["Series"][$SerieName]["Color"]["Alpha"] = $Palette[$ID]["Alpha"]; 106 $ID++; 107 } 108 } 109 } 110 111 /* Prepare the scale */ 112 function drawBubbleChart($DataSeries,$WeightSeries,$Format="") 113 { 114 $ForceAlpha = isset($Format["ForceAlpha"]) ? $Format["ForceAlpha"] : VOID; 115 $DrawBorder = isset($Format["DrawBorder"]) ? $Format["DrawBorder"] : TRUE; 116 $BorderWidth = isset($Format["BorderWidth"]) ? $Format["BorderWidth"] : 1; 117 $Shape = isset($Format["Shape"]) ? $Format["Shape"] : BUBBLE_SHAPE_ROUND; 118 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; 119 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 0; 120 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 0; 121 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 0; 122 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 30; 123 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; 124 125 if ( !is_array($DataSeries) ) { $DataSeries = array($DataSeries); } 126 if ( !is_array($WeightSeries) ) { $WeightSeries = array($WeightSeries); } 127 128 $Data = $this->pDataObject->getData(); 129 $Palette = $this->pDataObject->getPalette(); 130 131 if ( isset($Data["Series"]["BubbleFakePositiveSerie"] ) ) { $this->pDataObject->setSerieDrawable("BubbleFakePositiveSerie",FALSE); } 132 if ( isset($Data["Series"]["BubbleFakeNegativeSerie"] ) ) { $this->pDataObject->setSerieDrawable("BubbleFakeNegativeSerie",FALSE); } 133 134 $this->resetSeriesColors(); 135 136 list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); 137 138 foreach($DataSeries as $Key => $SerieName) 139 { 140 $AxisID = $Data["Series"][$SerieName]["Axis"]; 141 $Mode = $Data["Axis"][$AxisID]["Display"]; 142 $Format = $Data["Axis"][$AxisID]["Format"]; 143 $Unit = $Data["Axis"][$AxisID]["Unit"]; 144 145 if (isset($Data["Series"][$SerieName]["Description"])) { $SerieDescription = $Data["Series"][$SerieName]["Description"]; } else { $SerieDescription = $SerieName; } 146 147 $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; 148 149 $X = $this->pChartObject->GraphAreaX1 + $XMargin; 150 $Y = $this->pChartObject->GraphAreaY1 + $XMargin; 151 152 $Color = array("R"=>$Palette[$Key]["R"],"G"=>$Palette[$Key]["G"],"B"=>$Palette[$Key]["B"],"Alpha"=>$Palette[$Key]["Alpha"]); 153 154 if ( $ForceAlpha != VOID ) { $Color["Alpha"]=$ForceAlpha; } 155 156 if ( $DrawBorder ) 157 { 158 if ( $BorderWidth != 1 ) 159 { 160 if ( $Surrounding != NULL ) 161 { $BorderR = $Palette[$Key]["R"]+$Surrounding; $BorderG = $Palette[$Key]["G"]+$Surrounding; $BorderB = $Palette[$Key]["B"]+$Surrounding; } 162 else 163 { $BorderR = $BorderR; $BorderG = $BorderG; $BorderB = $BorderB; } 164 if ( $ForceAlpha != VOID ) { $BorderAlpha = $ForceAlpha/2; } 165 $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); 166 } 167 else 168 { 169 $Color["BorderAlpha"] = $BorderAlpha; 170 171 if ( $Surrounding != NULL ) 172 { $Color["BorderR"] = $Palette[$Key]["R"]+$Surrounding; $Color["BorderG"] = $Palette[$Key]["G"]+$Surrounding; $Color["BorderB"] = $Palette[$Key]["B"]+$Surrounding; } 173 else 174 { $Color["BorderR"] = $BorderR; $Color["BorderG"] = $BorderG; $Color["BorderB"] = $BorderB; } 175 if ( $ForceAlpha != VOID ) { $Color["BorderAlpha"] = $ForceAlpha/2; } 176 } 177 } 178 179 foreach($Data["Series"][$SerieName]["Data"] as $iKey => $Point) 180 { 181 $Weight = $Point + $Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]; 182 183 $PosArray = $this->pChartObject->scaleComputeY($Point,array("AxisID"=>$AxisID)); 184 $WeightArray = $this->pChartObject->scaleComputeY($Weight,array("AxisID"=>$AxisID)); 185 186 if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) 187 { 188 if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; } 189 $Y = floor($PosArray); $CircleRadius = floor(abs($PosArray - $WeightArray)/2); 190 191 if ( $Shape == BUBBLE_SHAPE_SQUARE ) 192 { 193 if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($X-$CircleRadius).",".floor($Y-$CircleRadius).",".floor($X+$CircleRadius).",".floor($Y+$CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } 194 195 if ( $BorderWidth != 1 ) 196 { 197 $this->pChartObject->drawFilledRectangle($X-$CircleRadius-$BorderWidth,$Y-$CircleRadius-$BorderWidth,$X+$CircleRadius+$BorderWidth,$Y+$CircleRadius+$BorderWidth,$BorderColor); 198 $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); 199 } 200 else 201 $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); 202 } 203 elseif ( $Shape == BUBBLE_SHAPE_ROUND ) 204 { 205 if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } 206 207 if ( $BorderWidth != 1 ) 208 { 209 $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius+$BorderWidth,$BorderColor); 210 $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); 211 } 212 else 213 $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); 214 } 215 216 $X = $X + $XStep; 217 } 218 elseif ( $Data["Orientation"] == SCALE_POS_TOPBOTTOM ) 219 { 220 if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; } 221 $X = floor($PosArray); $CircleRadius = floor(abs($PosArray - $WeightArray)/2); 222 223 if ( $Shape == BUBBLE_SHAPE_SQUARE ) 224 { 225 if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("RECT",floor($X-$CircleRadius).",".floor($Y-$CircleRadius).",".floor($X+$CircleRadius).",".floor($Y+$CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } 226 227 if ( $BorderWidth != 1 ) 228 { 229 $this->pChartObject->drawFilledRectangle($X-$CircleRadius-$BorderWidth,$Y-$CircleRadius-$BorderWidth,$X+$CircleRadius+$BorderWidth,$Y+$CircleRadius+$BorderWidth,$BorderColor); 230 $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); 231 } 232 else 233 $this->pChartObject->drawFilledRectangle($X-$CircleRadius,$Y-$CircleRadius,$X+$CircleRadius,$Y+$CircleRadius,$Color); 234 } 235 elseif ( $Shape == BUBBLE_SHAPE_ROUND ) 236 { 237 if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("CIRCLE",floor($X).",".floor($Y).",".floor($CircleRadius),$this->pChartObject->toHTMLColor($Palette[$Key]["R"],$Palette[$Key]["G"],$Palette[$Key]["B"]),$SerieDescription,$Data["Series"][$WeightSeries[$Key]]["Data"][$iKey]); } 238 239 if ( $BorderWidth != 1 ) 240 { 241 $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius+$BorderWidth,$BorderColor); 242 $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); 243 } 244 else 245 $this->pChartObject->drawFilledCircle($X,$Y,$CircleRadius,$Color); 246 } 247 248 $Y = $Y + $XStep; 249 } 250 } 251 } 252 } 253 254 function writeBubbleLabel($SerieName,$SerieWeightName,$Points,$Format="") 255 { 256 $OverrideTitle = isset($Format["OverrideTitle"]) ? $Format["OverrideTitle"] : NULL; 257 $DrawPoint = isset($Format["DrawPoint"]) ? $Format["DrawPoint"] : LABEL_POINT_BOX; 258 259 if ( !is_array($Points) ) { $Point = $Points; $Points = ""; $Points[] = $Point; } 260 261 $Data = $this->pDataObject->getData(); 262 $Palette = $this->pDataObject->getPalette(); 263 264 if ( !isset($Data["Series"][$SerieName]) || !isset($Data["Series"][$SerieWeightName]) ) 265 return(0); 266 267 list($XMargin,$XDivs) = $this->pChartObject->scaleGetXSettings(); 268 269 $AxisID = $Data["Series"][$SerieName]["Axis"]; 270 $AxisMode = $Data["Axis"][$AxisID]["Display"]; 271 $AxisFormat = $Data["Axis"][$AxisID]["Format"]; 272 $AxisUnit = $Data["Axis"][$AxisID]["Unit"]; 273 $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; 274 275 $X = $this->pChartObject->GraphAreaX1 + $XMargin; 276 $Y = $this->pChartObject->GraphAreaY1 + $XMargin; 277 278 $Color = array("R"=>$Data["Series"][$SerieName]["Color"]["R"],"G"=>$Data["Series"][$SerieName]["Color"]["G"],"B"=>$Data["Series"][$SerieName]["Color"]["B"],"Alpha"=>$Data["Series"][$SerieName]["Color"]["Alpha"]); 279 280 foreach($Points as $Key => $Point) 281 { 282 $Value = $Data["Series"][$SerieName]["Data"][$Point]; 283 $PosArray = $this->pChartObject->scaleComputeY($Value,array("AxisID"=>$AxisID)); 284 285 if ( isset($Data["Abscissa"]) && isset($Data["Series"][$Data["Abscissa"]]["Data"][$Point]) ) 286 $Abscissa = $Data["Series"][$Data["Abscissa"]]["Data"][$Point]." : "; 287 else 288 $Abscissa = ""; 289 290 $Value = $this->pChartObject->scaleFormat($Value,$AxisMode,$AxisFormat,$AxisUnit); 291 $Weight = $Data["Series"][$SerieWeightName]["Data"][$Point]; 292 $Caption = $Abscissa.$Value." / ".$Weight; 293 294 if ( isset($Data["Series"][$SerieName]["Description"]) ) 295 $Description = $Data["Series"][$SerieName]["Description"]; 296 else 297 $Description = "No description"; 298 299 $Series = ""; 300 $Series[] = array("Format"=>$Color,"Caption"=>$Caption); 301 302 if ( $Data["Orientation"] == SCALE_POS_LEFTRIGHT ) 303 { 304 if ( $XDivs == 0 ) { $XStep = 0; } else { $XStep = ($this->pChartObject->GraphAreaX2-$this->pChartObject->GraphAreaX1-$XMargin*2)/$XDivs; } 305 306 $X = floor($X + $Point * $XStep); 307 $Y = floor($PosArray); 308 } 309 else 310 { 311 if ( $XDivs == 0 ) { $YStep = 0; } else { $YStep = ($this->pChartObject->GraphAreaY2-$this->pChartObject->GraphAreaY1-$XMargin*2)/$XDivs; } 312 313 $X = floor($PosArray); 314 $Y = floor($Y + $Point * $YStep); 315 } 316 317 if ( $DrawPoint == LABEL_POINT_CIRCLE ) 318 $this->pChartObject->drawFilledCircle($X,$Y,3,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); 319 elseif ( $DrawPoint == LABEL_POINT_BOX ) 320 $this->pChartObject->drawFilledRectangle($X-2,$Y-2,$X+2,$Y+2,array("R"=>255,"G"=>255,"B"=>255,"BorderR"=>0,"BorderG"=>0,"BorderB"=>0)); 321 322 $this->pChartObject->drawLabelBox($X,$Y-3,$Description,$Series,$Format); 323 } 324 } 325 } 326?>