2150 |
mathias |
1 |
<?php
|
|
|
2 |
/*=======================================================================
|
|
|
3 |
// File: JPGRAPH_PIE.PHP
|
|
|
4 |
// Description: Pie plot extension for JpGraph
|
|
|
5 |
// Created: 2001-02-14
|
|
|
6 |
// Ver: $Id: jpgraph_pie.php 781 2006-10-08 08:07:47Z ljp $
|
|
|
7 |
//
|
|
|
8 |
// Copyright (c) Aditus Consulting. All rights reserved.
|
|
|
9 |
//========================================================================
|
|
|
10 |
*/
|
|
|
11 |
|
|
|
12 |
|
|
|
13 |
// Defines for PiePlot::SetLabelType()
|
|
|
14 |
DEFINE("PIE_VALUE_ABS",1);
|
|
|
15 |
DEFINE("PIE_VALUE_PER",0);
|
|
|
16 |
DEFINE("PIE_VALUE_PERCENTAGE",0);
|
|
|
17 |
DEFINE("PIE_VALUE_ADJPERCENTAGE",2);
|
|
|
18 |
DEFINE("PIE_VALUE_ADJPER",2);
|
|
|
19 |
|
|
|
20 |
//===================================================
|
|
|
21 |
// CLASS PiePlot
|
|
|
22 |
// Description: Draws a pie plot
|
|
|
23 |
//===================================================
|
|
|
24 |
class PiePlot {
|
|
|
25 |
public $posx=0.5,$posy=0.5;
|
|
|
26 |
protected $radius=0.3;
|
|
|
27 |
protected $explode_radius=array(),$explode_all=false,$explode_r=20;
|
|
|
28 |
protected $labels=null, $legends=null;
|
|
|
29 |
protected $csimtargets=null; // Array of targets for CSIM
|
|
|
30 |
protected $csimareas=''; // Generated CSIM text
|
|
|
31 |
protected $csimalts=null; // ALT tags for corresponding target
|
|
|
32 |
protected $data=null;
|
|
|
33 |
public $title;
|
|
|
34 |
protected $startangle=0;
|
|
|
35 |
protected $weight=1, $color="black";
|
|
|
36 |
protected $legend_margin=6,$show_labels=true;
|
|
|
37 |
protected $themearr = array(
|
|
|
38 |
"earth" => array(136,34,40,45,46,62,63,134,74,10,120,136,141,168,180,77,209,218,346,395,89,430),
|
|
|
39 |
"pastel" => array(27,415,128,59,66,79,105,110,42,147,152,230,236,240,331,337,405,38),
|
|
|
40 |
"water" => array(8,370,24,40,335,56,213,237,268,14,326,387,10,388),
|
|
|
41 |
"sand" => array(27,168,34,170,19,50,65,72,131,209,46,393));
|
|
|
42 |
protected $theme="earth";
|
|
|
43 |
protected $setslicecolors=array();
|
|
|
44 |
protected $labeltype=0; // Default to percentage
|
|
|
45 |
protected $pie_border=true,$pie_interior_border=true;
|
|
|
46 |
public $value;
|
|
|
47 |
protected $ishadowcolor='',$ishadowdrop=4;
|
|
|
48 |
protected $ilabelposadj=1;
|
|
|
49 |
protected $legendcsimtargets = array();
|
|
|
50 |
protected $legendcsimalts = array();
|
|
|
51 |
protected $adjusted_data = array();
|
|
|
52 |
public $guideline = null;
|
|
|
53 |
protected $guidelinemargin=10,$iShowGuideLineForSingle = false;
|
|
|
54 |
protected $iGuideLineCurve = false,$iGuideVFactor=1.4,$iGuideLineRFactor=0.8;
|
|
|
55 |
|
|
|
56 |
//---------------
|
|
|
57 |
// CONSTRUCTOR
|
|
|
58 |
function PiePlot($data) {
|
|
|
59 |
$this->data = array_reverse($data);
|
|
|
60 |
$this->title = new Text("");
|
|
|
61 |
$this->title->SetFont(FF_FONT1,FS_BOLD);
|
|
|
62 |
$this->value = new DisplayValue();
|
|
|
63 |
$this->value->Show();
|
|
|
64 |
$this->value->SetFormat('%.1f%%');
|
|
|
65 |
$this->guideline = new LineProperty();
|
|
|
66 |
}
|
|
|
67 |
|
|
|
68 |
//---------------
|
|
|
69 |
// PUBLIC METHODS
|
|
|
70 |
function SetCenter($x,$y=0.5) {
|
|
|
71 |
$this->posx = $x;
|
|
|
72 |
$this->posy = $y;
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
// Enable guideline and set drwaing policy
|
|
|
76 |
function SetGuideLines($aFlg=true,$aCurved=true,$aAlways=false) {
|
|
|
77 |
$this->guideline->Show($aFlg);
|
|
|
78 |
$this->iShowGuideLineForSingle = $aAlways;
|
|
|
79 |
$this->iGuideLineCurve = $aCurved;
|
|
|
80 |
}
|
|
|
81 |
|
|
|
82 |
// Adjuste the distance between labels and labels and pie
|
|
|
83 |
function SetGuideLinesAdjust($aVFactor,$aRFactor=0.8) {
|
|
|
84 |
$this->iGuideVFactor=$aVFactor;
|
|
|
85 |
$this->iGuideLineRFactor=$aRFactor;
|
|
|
86 |
}
|
|
|
87 |
|
|
|
88 |
function SetColor($aColor) {
|
|
|
89 |
$this->color = $aColor;
|
|
|
90 |
}
|
|
|
91 |
|
|
|
92 |
function SetSliceColors($aColors) {
|
|
|
93 |
$this->setslicecolors = $aColors;
|
|
|
94 |
}
|
|
|
95 |
|
|
|
96 |
function SetShadow($aColor='darkgray',$aDropWidth=4) {
|
|
|
97 |
$this->ishadowcolor = $aColor;
|
|
|
98 |
$this->ishadowdrop = $aDropWidth;
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
function SetCSIMTargets($targets,$alts=null) {
|
|
|
102 |
$this->csimtargets=array_reverse($targets);
|
|
|
103 |
if( is_array($alts) )
|
|
|
104 |
$this->csimalts=array_reverse($alts);
|
|
|
105 |
}
|
|
|
106 |
|
|
|
107 |
function GetCSIMareas() {
|
|
|
108 |
return $this->csimareas;
|
|
|
109 |
}
|
|
|
110 |
|
|
|
111 |
function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) {
|
|
|
112 |
//Slice number, ellipse centre (x,y), height, width, start angle, end angle
|
|
|
113 |
while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
|
|
|
114 |
while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
|
|
|
115 |
|
|
|
116 |
$sa = 2*M_PI - $sa;
|
|
|
117 |
$ea = 2*M_PI - $ea;
|
|
|
118 |
|
|
|
119 |
// Special case when we have only one slice since then both start and end
|
|
|
120 |
// angle will be == 0
|
|
|
121 |
if( abs($sa - $ea) < 0.0001 ) {
|
|
|
122 |
$sa=2*M_PI; $ea=0;
|
|
|
123 |
}
|
|
|
124 |
|
|
|
125 |
//add coordinates of the centre to the map
|
|
|
126 |
$xc = floor($xc);$yc=floor($yc);
|
|
|
127 |
$coords = "$xc, $yc";
|
|
|
128 |
|
|
|
129 |
//add coordinates of the first point on the arc to the map
|
|
|
130 |
$xp = floor(($radius*cos($ea))+$xc);
|
|
|
131 |
$yp = floor($yc-$radius*sin($ea));
|
|
|
132 |
$coords.= ", $xp, $yp";
|
|
|
133 |
|
|
|
134 |
//add coordinates every 0.2 radians
|
|
|
135 |
$a=$ea+0.2;
|
|
|
136 |
|
|
|
137 |
// If we cross the 360-limit with a slice we need to handle
|
|
|
138 |
// the fact that end angle is smaller than start
|
|
|
139 |
if( $sa < $ea ) {
|
|
|
140 |
while ($a <= 2*M_PI) {
|
|
|
141 |
$xp = floor($radius*cos($a)+$xc);
|
|
|
142 |
$yp = floor($yc-$radius*sin($a));
|
|
|
143 |
$coords.= ", $xp, $yp";
|
|
|
144 |
$a += 0.2;
|
|
|
145 |
}
|
|
|
146 |
$a -= 2*M_PI;
|
|
|
147 |
}
|
|
|
148 |
|
|
|
149 |
|
|
|
150 |
while ($a < $sa) {
|
|
|
151 |
$xp = floor($radius*cos($a)+$xc);
|
|
|
152 |
$yp = floor($yc-$radius*sin($a));
|
|
|
153 |
$coords.= ", $xp, $yp";
|
|
|
154 |
$a += 0.2;
|
|
|
155 |
}
|
|
|
156 |
|
|
|
157 |
//Add the last point on the arc
|
|
|
158 |
$xp = floor($radius*cos($sa)+$xc);
|
|
|
159 |
$yp = floor($yc-$radius*sin($sa));
|
|
|
160 |
$coords.= ", $xp, $yp";
|
|
|
161 |
if( !empty($this->csimtargets[$i]) ) {
|
|
|
162 |
$this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
|
|
|
163 |
$tmp="";
|
|
|
164 |
if( !empty($this->csimalts[$i]) ) {
|
|
|
165 |
$tmp=sprintf($this->csimalts[$i],$this->data[$i]);
|
|
|
166 |
$this->csimareas .= " title=\"$tmp\"";
|
|
|
167 |
}
|
|
|
168 |
$this->csimareas .= " alt=\"$tmp\" />\n";
|
|
|
169 |
}
|
|
|
170 |
}
|
|
|
171 |
|
|
|
172 |
|
|
|
173 |
function SetTheme($aTheme) {
|
|
|
174 |
if( in_array($aTheme,array_keys($this->themearr)) )
|
|
|
175 |
$this->theme = $aTheme;
|
|
|
176 |
else
|
|
|
177 |
JpGraphError::RaiseL(15001,$aTheme);//("PiePLot::SetTheme() Unknown theme: $aTheme");
|
|
|
178 |
}
|
|
|
179 |
|
|
|
180 |
function ExplodeSlice($e,$radius=20) {
|
|
|
181 |
if( ! is_integer($e) )
|
|
|
182 |
JpGraphError::RaiseL(15002);//('Argument to PiePlot::ExplodeSlice() must be an integer');
|
|
|
183 |
$this->explode_radius[$e]=$radius;
|
|
|
184 |
}
|
|
|
185 |
|
|
|
186 |
function ExplodeAll($radius=20) {
|
|
|
187 |
$this->explode_all=true;
|
|
|
188 |
$this->explode_r = $radius;
|
|
|
189 |
}
|
|
|
190 |
|
|
|
191 |
function Explode($aExplodeArr) {
|
|
|
192 |
if( !is_array($aExplodeArr) ) {
|
|
|
193 |
JpGraphError::RaiseL(15003);
|
|
|
194 |
//("Argument to PiePlot::Explode() must be an array with integer distances.");
|
|
|
195 |
}
|
|
|
196 |
$this->explode_radius = $aExplodeArr;
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
function SetStartAngle($aStart) {
|
|
|
200 |
if( $aStart < 0 || $aStart > 360 ) {
|
|
|
201 |
JpGraphError::RaiseL(15004);//('Slice start angle must be between 0 and 360 degrees.');
|
|
|
202 |
}
|
|
|
203 |
$this->startangle = 360-$aStart;
|
|
|
204 |
$this->startangle *= M_PI/180;
|
|
|
205 |
}
|
|
|
206 |
|
|
|
207 |
function SetFont($family,$style=FS_NORMAL,$size=10) {
|
|
|
208 |
JpGraphError::RaiseL(15005);//('PiePlot::SetFont() is deprecated. Use PiePlot->value->SetFont() instead.');
|
|
|
209 |
}
|
|
|
210 |
|
|
|
211 |
// Size in percentage
|
|
|
212 |
function SetSize($aSize) {
|
|
|
213 |
if( ($aSize>0 && $aSize<=0.5) || ($aSize>10 && $aSize<1000) )
|
|
|
214 |
$this->radius = $aSize;
|
|
|
215 |
else
|
|
|
216 |
JpGraphError::RaiseL(15006);
|
|
|
217 |
//("PiePlot::SetSize() Radius for pie must either be specified as a fraction [0, 0.5] of the size of the image or as an absolute size in pixels in the range [10, 1000]");
|
|
|
218 |
}
|
|
|
219 |
|
|
|
220 |
function SetFontColor($aColor) {
|
|
|
221 |
JpGraphError::RaiseL(15007);
|
|
|
222 |
//('PiePlot::SetFontColor() is deprecated. Use PiePlot->value->SetColor() instead.');
|
|
|
223 |
}
|
|
|
224 |
|
|
|
225 |
// Set label arrays
|
|
|
226 |
function SetLegends($aLegend) {
|
|
|
227 |
$this->legends = $aLegend;
|
|
|
228 |
}
|
|
|
229 |
|
|
|
230 |
// Set text labels for slices
|
|
|
231 |
function SetLabels($aLabels,$aLblPosAdj="auto") {
|
|
|
232 |
$this->labels = array_reverse($aLabels);
|
|
|
233 |
$this->ilabelposadj=$aLblPosAdj;
|
|
|
234 |
}
|
|
|
235 |
|
|
|
236 |
function SetLabelPos($aLblPosAdj) {
|
|
|
237 |
$this->ilabelposadj=$aLblPosAdj;
|
|
|
238 |
}
|
|
|
239 |
|
|
|
240 |
// Should we display actual value or percentage?
|
|
|
241 |
function SetLabelType($t) {
|
|
|
242 |
if( $t < 0 || $t > 2 )
|
|
|
243 |
JpGraphError::RaiseL(15008,$t);
|
|
|
244 |
//("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t).");
|
|
|
245 |
$this->labeltype=$t;
|
|
|
246 |
}
|
|
|
247 |
|
|
|
248 |
// Deprecated.
|
|
|
249 |
function SetValueType($aType) {
|
|
|
250 |
$this->SetLabelType($aType);
|
|
|
251 |
}
|
|
|
252 |
|
|
|
253 |
// Should the circle around a pie plot be displayed
|
|
|
254 |
function ShowBorder($exterior=true,$interior=true) {
|
|
|
255 |
$this->pie_border = $exterior;
|
|
|
256 |
$this->pie_interior_border = $interior;
|
|
|
257 |
}
|
|
|
258 |
|
|
|
259 |
// Setup the legends
|
|
|
260 |
function Legend($graph) {
|
|
|
261 |
$colors = array_keys($graph->img->rgb->rgb_table);
|
|
|
262 |
sort($colors);
|
|
|
263 |
$ta=$this->themearr[$this->theme];
|
|
|
264 |
$n = count($this->data);
|
|
|
265 |
|
|
|
266 |
if( $this->setslicecolors==null ) {
|
|
|
267 |
$numcolors=count($ta);
|
|
|
268 |
if( class_exists('PiePlot3D',false) && ($this instanceof PiePlot3D) ) {
|
|
|
269 |
$ta = array_reverse(array_slice($ta,0,$n));
|
|
|
270 |
}
|
|
|
271 |
}
|
|
|
272 |
else {
|
|
|
273 |
$this->setslicecolors = array_slice($this->setslicecolors,0,$n);
|
|
|
274 |
$numcolors=count($this->setslicecolors);
|
|
|
275 |
if( $graph->pieaa && ($this instanceof PiePlot) ) {
|
|
|
276 |
$this->setslicecolors = array_reverse($this->setslicecolors);
|
|
|
277 |
}
|
|
|
278 |
}
|
|
|
279 |
|
|
|
280 |
$sum=0;
|
|
|
281 |
for($i=0; $i < $n; ++$i)
|
|
|
282 |
$sum += $this->data[$i];
|
|
|
283 |
|
|
|
284 |
// Bail out with error if the sum is 0
|
|
|
285 |
if( $sum==0 )
|
|
|
286 |
JpGraphError::RaiseL(15009);//("Illegal pie plot. Sum of all data is zero for Pie!");
|
|
|
287 |
|
|
|
288 |
// Make sure we don't plot more values than data points
|
|
|
289 |
// (in case the user added more legends than data points)
|
|
|
290 |
$n = min(count($this->legends),count($this->data));
|
|
|
291 |
if( $this->legends != "" ) {
|
|
|
292 |
$this->legends = array_reverse(array_slice($this->legends,0,$n));
|
|
|
293 |
}
|
|
|
294 |
for( $i=$n-1; $i >= 0; --$i ) {
|
|
|
295 |
$l = $this->legends[$i];
|
|
|
296 |
// Replace possible format with actual values
|
|
|
297 |
if( count($this->csimalts) > $i ) {
|
|
|
298 |
$fmt = $this->csimalts[$i];
|
|
|
299 |
}
|
|
|
300 |
else {
|
|
|
301 |
$fmt = "%d"; // Deafult Alt if no other has been specified
|
|
|
302 |
}
|
|
|
303 |
if( $this->labeltype==0 ) {
|
|
|
304 |
$l = sprintf($l,100*$this->data[$i]/$sum);
|
|
|
305 |
$alt = sprintf($fmt,$this->data[$i]);
|
|
|
306 |
|
|
|
307 |
}
|
|
|
308 |
elseif( $this->labeltype == 1) {
|
|
|
309 |
$l = sprintf($l,$this->data[$i]);
|
|
|
310 |
$alt = sprintf($fmt,$this->data[$i]);
|
|
|
311 |
|
|
|
312 |
}
|
|
|
313 |
else {
|
|
|
314 |
$l = sprintf($l,$this->adjusted_data[$i]);
|
|
|
315 |
$alt = sprintf($fmt,$this->adjusted_data[$i]);
|
|
|
316 |
}
|
|
|
317 |
|
|
|
318 |
if( $this->setslicecolors==null ) {
|
|
|
319 |
$graph->legend->Add($l,$colors[$ta[$i%$numcolors]],"",0,$this->csimtargets[$i],$alt);
|
|
|
320 |
}
|
|
|
321 |
else {
|
|
|
322 |
$graph->legend->Add($l,$this->setslicecolors[$i%$numcolors],"",0,$this->csimtargets[$i],$alt);
|
|
|
323 |
}
|
|
|
324 |
}
|
|
|
325 |
}
|
|
|
326 |
|
|
|
327 |
// Adjust the rounded percetage value so that the sum of
|
|
|
328 |
// of the pie slices are always 100%
|
|
|
329 |
// Using the Hare/Niemeyer method
|
|
|
330 |
function AdjPercentage($aData,$aPrec=0) {
|
|
|
331 |
$mul=100;
|
|
|
332 |
if( $aPrec > 0 && $aPrec < 3 ) {
|
|
|
333 |
if( $aPrec == 1 )
|
|
|
334 |
$mul=1000;
|
|
|
335 |
else
|
|
|
336 |
$mul=10000;
|
|
|
337 |
}
|
|
|
338 |
|
|
|
339 |
$tmp = array();
|
|
|
340 |
$result = array();
|
|
|
341 |
$quote_sum=0;
|
|
|
342 |
$n = count($aData) ;
|
|
|
343 |
for( $i=0, $sum=0; $i < $n; ++$i )
|
|
|
344 |
$sum+=$aData[$i];
|
|
|
345 |
foreach($aData as $index => $value) {
|
|
|
346 |
$tmp_percentage=$value/$sum*$mul;
|
|
|
347 |
$result[$index]=floor($tmp_percentage);
|
|
|
348 |
$tmp[$index]=$tmp_percentage-$result[$index];
|
|
|
349 |
$quote_sum+=$result[$index];
|
|
|
350 |
}
|
|
|
351 |
if( $quote_sum == $mul) {
|
|
|
352 |
if( $mul > 100 ) {
|
|
|
353 |
$tmp = $mul / 100;
|
|
|
354 |
for( $i=0; $i < $n; ++$i ) {
|
|
|
355 |
$result[$i] /= $tmp ;
|
|
|
356 |
}
|
|
|
357 |
}
|
|
|
358 |
return $result;
|
|
|
359 |
}
|
|
|
360 |
arsort($tmp,SORT_NUMERIC);
|
|
|
361 |
reset($tmp);
|
|
|
362 |
for($i=0; $i < $mul-$quote_sum; $i++)
|
|
|
363 |
{
|
|
|
364 |
$result[key($tmp)]++;
|
|
|
365 |
next($tmp);
|
|
|
366 |
}
|
|
|
367 |
if( $mul > 100 ) {
|
|
|
368 |
$tmp = $mul / 100;
|
|
|
369 |
for( $i=0; $i < $n; ++$i ) {
|
|
|
370 |
$result[$i] /= $tmp ;
|
|
|
371 |
}
|
|
|
372 |
}
|
|
|
373 |
return $result;
|
|
|
374 |
}
|
|
|
375 |
|
|
|
376 |
|
|
|
377 |
function Stroke($img,$aaoption=0) {
|
|
|
378 |
// aaoption is used to handle antialias
|
|
|
379 |
// aaoption == 0 a normal pie
|
|
|
380 |
// aaoption == 1 just the body
|
|
|
381 |
// aaoption == 2 just the values
|
|
|
382 |
|
|
|
383 |
// Explode scaling. If anti anti alias we scale the image
|
|
|
384 |
// twice and we also need to scale the exploding distance
|
|
|
385 |
$expscale = $aaoption === 1 ? 2 : 1;
|
|
|
386 |
|
|
|
387 |
if( $this->labeltype == 2 ) {
|
|
|
388 |
// Adjust the data so that it will add up to 100%
|
|
|
389 |
$this->adjusted_data = $this->AdjPercentage($this->data);
|
|
|
390 |
}
|
|
|
391 |
|
|
|
392 |
$colors = array_keys($img->rgb->rgb_table);
|
|
|
393 |
sort($colors);
|
|
|
394 |
$ta=$this->themearr[$this->theme];
|
|
|
395 |
$n = count($this->data);
|
|
|
396 |
|
|
|
397 |
if( $this->setslicecolors==null ) {
|
|
|
398 |
$numcolors=count($ta);
|
|
|
399 |
}
|
|
|
400 |
else {
|
|
|
401 |
// We need to create an array of colors as long as the data
|
|
|
402 |
// since we need to reverse it to get the colors in the right order
|
|
|
403 |
$numcolors=count($this->setslicecolors);
|
|
|
404 |
if( $n > $numcolors ) {
|
|
|
405 |
$i = 2*$numcolors;
|
|
|
406 |
while( $n > $i ) {
|
|
|
407 |
$this->setslicecolors = array_merge($this->setslicecolors,$this->setslicecolors);
|
|
|
408 |
$i += $n;
|
|
|
409 |
}
|
|
|
410 |
$tt = array_slice($this->setslicecolors,0,$n % $numcolors);
|
|
|
411 |
$this->setslicecolors = array_merge($this->setslicecolors,$tt);
|
|
|
412 |
$this->setslicecolors = array_reverse($this->setslicecolors);
|
|
|
413 |
}
|
|
|
414 |
}
|
|
|
415 |
|
|
|
416 |
// Draw the slices
|
|
|
417 |
$sum=0;
|
|
|
418 |
for($i=0; $i < $n; ++$i)
|
|
|
419 |
$sum += $this->data[$i];
|
|
|
420 |
|
|
|
421 |
// Bail out with error if the sum is 0
|
|
|
422 |
if( $sum==0 )
|
|
|
423 |
JpGraphError::RaiseL(15009);//("Sum of all data is 0 for Pie.");
|
|
|
424 |
|
|
|
425 |
// Set up the pie-circle
|
|
|
426 |
if( $this->radius <= 1 )
|
|
|
427 |
$radius = floor($this->radius*min($img->width,$img->height));
|
|
|
428 |
else {
|
|
|
429 |
$radius = $aaoption === 1 ? $this->radius*2 : $this->radius;
|
|
|
430 |
}
|
|
|
431 |
|
|
|
432 |
if( $this->posx <= 1 && $this->posx > 0 )
|
|
|
433 |
$xc = round($this->posx*$img->width);
|
|
|
434 |
else
|
|
|
435 |
$xc = $this->posx ;
|
|
|
436 |
|
|
|
437 |
if( $this->posy <= 1 && $this->posy > 0 )
|
|
|
438 |
$yc = round($this->posy*$img->height);
|
|
|
439 |
else
|
|
|
440 |
$yc = $this->posy ;
|
|
|
441 |
|
|
|
442 |
$n = count($this->data);
|
|
|
443 |
|
|
|
444 |
if( $this->explode_all )
|
|
|
445 |
for($i=0; $i < $n; ++$i)
|
|
|
446 |
$this->explode_radius[$i]=$this->explode_r;
|
|
|
447 |
|
|
|
448 |
if( $this->ishadowcolor != "" && $aaoption !== 2) {
|
|
|
449 |
$accsum=0;
|
|
|
450 |
$angle2 = $this->startangle;
|
|
|
451 |
$img->SetColor($this->ishadowcolor);
|
|
|
452 |
for($i=0; $sum > 0 && $i < $n; ++$i) {
|
|
|
453 |
$j = $n-$i-1;
|
|
|
454 |
$d = $this->data[$i];
|
|
|
455 |
$angle1 = $angle2;
|
|
|
456 |
$accsum += $d;
|
|
|
457 |
$angle2 = $this->startangle+2*M_PI*$accsum/$sum;
|
|
|
458 |
if( empty($this->explode_radius[$j]) )
|
|
|
459 |
$this->explode_radius[$j]=0;
|
|
|
460 |
|
|
|
461 |
$la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
|
|
|
462 |
|
|
|
463 |
$xcm = $xc + $this->explode_radius[$j]*cos($la)*$expscale;
|
|
|
464 |
$ycm = $yc - $this->explode_radius[$j]*sin($la)*$expscale;
|
|
|
465 |
|
|
|
466 |
$xcm += $this->ishadowdrop*$expscale;
|
|
|
467 |
$ycm += $this->ishadowdrop*$expscale;
|
|
|
468 |
|
|
|
469 |
$img->CakeSlice($xcm,$ycm,$radius,$radius,
|
|
|
470 |
$angle1*180/M_PI,$angle2*180/M_PI,$this->ishadowcolor);
|
|
|
471 |
|
|
|
472 |
}
|
|
|
473 |
}
|
|
|
474 |
|
|
|
475 |
$accsum=0;
|
|
|
476 |
$angle2 = $this->startangle;
|
|
|
477 |
$img->SetColor($this->color);
|
|
|
478 |
for($i=0; $sum>0 && $i < $n; ++$i) {
|
|
|
479 |
$j = $n-$i-1;
|
|
|
480 |
if( empty($this->explode_radius[$j]) )
|
|
|
481 |
$this->explode_radius[$j]=0;
|
|
|
482 |
$d = $this->data[$i];
|
|
|
483 |
$angle1 = $angle2;
|
|
|
484 |
$accsum += $d;
|
|
|
485 |
$angle2 = $this->startangle+2*M_PI*$accsum/$sum;
|
|
|
486 |
$this->la[$i] = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
|
|
|
487 |
|
|
|
488 |
if( $d == 0 ) continue;
|
|
|
489 |
|
|
|
490 |
if( $this->setslicecolors==null )
|
|
|
491 |
$slicecolor=$colors[$ta[$i%$numcolors]];
|
|
|
492 |
else
|
|
|
493 |
$slicecolor=$this->setslicecolors[$i%$numcolors];
|
|
|
494 |
|
|
|
495 |
if( $this->pie_interior_border && $aaoption===0 )
|
|
|
496 |
$img->SetColor($this->color);
|
|
|
497 |
else
|
|
|
498 |
$img->SetColor($slicecolor);
|
|
|
499 |
|
|
|
500 |
$arccolor = $this->pie_border && $aaoption===0 ? $this->color : "";
|
|
|
501 |
|
|
|
502 |
$xcm = $xc + $this->explode_radius[$j]*cos($this->la[$i])*$expscale;
|
|
|
503 |
$ycm = $yc - $this->explode_radius[$j]*sin($this->la[$i])*$expscale;
|
|
|
504 |
|
|
|
505 |
if( $aaoption !== 2 ) {
|
|
|
506 |
$img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,
|
|
|
507 |
$angle1*180/M_PI,$angle2*180/M_PI,$slicecolor,$arccolor);
|
|
|
508 |
}
|
|
|
509 |
|
|
|
510 |
if( $this->csimtargets && $aaoption !== 1 ) {
|
|
|
511 |
$this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2);
|
|
|
512 |
}
|
|
|
513 |
}
|
|
|
514 |
|
|
|
515 |
// Format the titles for each slice
|
|
|
516 |
if( $aaoption !== 2 ) {
|
|
|
517 |
for( $i=0; $i < $n; ++$i) {
|
|
|
518 |
if( $this->labeltype==0 ) {
|
|
|
519 |
if( $sum != 0 )
|
|
|
520 |
$l = 100.0*$this->data[$i]/$sum;
|
|
|
521 |
else
|
|
|
522 |
$l = 0.0;
|
|
|
523 |
}
|
|
|
524 |
elseif( $this->labeltype==1 ) {
|
|
|
525 |
$l = $this->data[$i]*1.0;
|
|
|
526 |
}
|
|
|
527 |
else {
|
|
|
528 |
$l = $this->adjusted_data[$i];
|
|
|
529 |
}
|
|
|
530 |
if( isset($this->labels[$i]) && is_string($this->labels[$i]) )
|
|
|
531 |
$this->labels[$i]=sprintf($this->labels[$i],$l);
|
|
|
532 |
else
|
|
|
533 |
$this->labels[$i]=$l;
|
|
|
534 |
}
|
|
|
535 |
}
|
|
|
536 |
|
|
|
537 |
if( $this->value->show && $aaoption !== 1 ) {
|
|
|
538 |
$this->StrokeAllLabels($img,$xc,$yc,$radius);
|
|
|
539 |
}
|
|
|
540 |
|
|
|
541 |
// Adjust title position
|
|
|
542 |
if( $aaoption !== 1 ) {
|
|
|
543 |
$this->title->SetPos($xc,
|
|
|
544 |
$yc-$this->title->GetFontHeight($img)-$radius-$this->title->margin,
|
|
|
545 |
"center","bottom");
|
|
|
546 |
$this->title->Stroke($img);
|
|
|
547 |
}
|
|
|
548 |
|
|
|
549 |
}
|
|
|
550 |
|
|
|
551 |
//---------------
|
|
|
552 |
// PRIVATE METHODS
|
|
|
553 |
|
|
|
554 |
function NormAngle($a) {
|
|
|
555 |
while( $a < 0 ) $a += 2*M_PI;
|
|
|
556 |
while( $a > 2*M_PI ) $a -= 2*M_PI;
|
|
|
557 |
return $a;
|
|
|
558 |
}
|
|
|
559 |
|
|
|
560 |
function Quadrant($a) {
|
|
|
561 |
$a=$this->NormAngle($a);
|
|
|
562 |
if( $a > 0 && $a <= M_PI/2 )
|
|
|
563 |
return 0;
|
|
|
564 |
if( $a > M_PI/2 && $a <= M_PI )
|
|
|
565 |
return 1;
|
|
|
566 |
if( $a > M_PI && $a <= 1.5*M_PI )
|
|
|
567 |
return 2;
|
|
|
568 |
if( $a > 1.5*M_PI )
|
|
|
569 |
return 3;
|
|
|
570 |
}
|
|
|
571 |
|
|
|
572 |
function StrokeGuideLabels($img,$xc,$yc,$radius) {
|
|
|
573 |
$n = count($this->labels);
|
|
|
574 |
|
|
|
575 |
//-----------------------------------------------------------------------
|
|
|
576 |
// Step 1 of the algorithm is to construct a number of clusters
|
|
|
577 |
// a cluster is defined as all slices within the same quadrant (almost)
|
|
|
578 |
// that has an angualr distance less than the treshold
|
|
|
579 |
//-----------------------------------------------------------------------
|
|
|
580 |
$tresh_hold=25 * M_PI/180; // 25 degrees difference to be in a cluster
|
|
|
581 |
$incluster=false; // flag if we are currently in a cluster or not
|
|
|
582 |
$clusters = array(); // array of clusters
|
|
|
583 |
$cidx=-1; // running cluster index
|
|
|
584 |
|
|
|
585 |
// Go through all the labels and construct a number of clusters
|
|
|
586 |
for($i=0; $i < $n-1; ++$i) {
|
|
|
587 |
// Calc the angle distance between two consecutive slices
|
|
|
588 |
$a1=$this->la[$i];
|
|
|
589 |
$a2=$this->la[$i+1];
|
|
|
590 |
$q1 = $this->Quadrant($a1);
|
|
|
591 |
$q2 = $this->Quadrant($a2);
|
|
|
592 |
$diff = abs($a1-$a2);
|
|
|
593 |
if( $diff < $tresh_hold ) {
|
|
|
594 |
if( $incluster ) {
|
|
|
595 |
$clusters[$cidx][1]++;
|
|
|
596 |
// Each cluster can only cover one quadrant
|
|
|
597 |
// Do we cross a quadrant ( and must break the cluster)
|
|
|
598 |
if( $q1 != $q2 ) {
|
|
|
599 |
// If we cross a quadrant boundary we normally start a
|
|
|
600 |
// new cluster. However we need to take the 12'a clock
|
|
|
601 |
// and 6'a clock positions into a special consideration.
|
|
|
602 |
// Case 1: WE go from q=1 to q=2 if the last slice on
|
|
|
603 |
// the cluster for q=1 is close to 12'a clock and the
|
|
|
604 |
// first slice in q=0 is small we extend the previous
|
|
|
605 |
// cluster
|
|
|
606 |
if( $q1 == 1 && $q2 == 0 && $a2 > (90-15)*M_PI/180 ) {
|
|
|
607 |
if( $i < $n-2 ) {
|
|
|
608 |
$a3 = $this->la[$i+2];
|
|
|
609 |
// If there isn't a cluster coming up with the next-next slice
|
|
|
610 |
// we extend the previous cluster to cover this slice as well
|
|
|
611 |
if( abs($a3-$a2) >= $tresh_hold ) {
|
|
|
612 |
$clusters[$cidx][1]++;
|
|
|
613 |
$i++;
|
|
|
614 |
}
|
|
|
615 |
}
|
|
|
616 |
}
|
|
|
617 |
elseif( $q1 == 3 && $q2 == 2 && $a2 > (270-15)*M_PI/180 ) {
|
|
|
618 |
if( $i < $n-2 ) {
|
|
|
619 |
$a3 = $this->la[$i+2];
|
|
|
620 |
// If there isn't a cluster coming up with the next-next slice
|
|
|
621 |
// we extend the previous cluster to cover this slice as well
|
|
|
622 |
if( abs($a3-$a2) >= $tresh_hold ) {
|
|
|
623 |
$clusters[$cidx][1]++;
|
|
|
624 |
$i++;
|
|
|
625 |
}
|
|
|
626 |
}
|
|
|
627 |
}
|
|
|
628 |
|
|
|
629 |
if( $q1==2 && $q2==1 && $a2 > (180-15)*M_PI/180 ) {
|
|
|
630 |
$clusters[$cidx][1]++;
|
|
|
631 |
$i++;
|
|
|
632 |
}
|
|
|
633 |
|
|
|
634 |
$incluster = false;
|
|
|
635 |
}
|
|
|
636 |
}
|
|
|
637 |
elseif( $q1 == $q2) {
|
|
|
638 |
$incluster = true;
|
|
|
639 |
// Now we have a special case for quadrant 0. If we previously
|
|
|
640 |
// have a cluster of one in quadrant 0 we just extend that
|
|
|
641 |
// cluster. If we don't do this then we risk that the label
|
|
|
642 |
// for the cluster of one will cross the guide-line
|
|
|
643 |
if( $q1 == 0 && $cidx > -1 &&
|
|
|
644 |
$clusters[$cidx][1] == 1 &&
|
|
|
645 |
$this->Quadrant($this->la[$clusters[$cidx][0]]) == 0 ) {
|
|
|
646 |
$clusters[$cidx][1]++;
|
|
|
647 |
}
|
|
|
648 |
else {
|
|
|
649 |
$cidx++;
|
|
|
650 |
$clusters[$cidx][0] = $i;
|
|
|
651 |
$clusters[$cidx][1] = 1;
|
|
|
652 |
}
|
|
|
653 |
}
|
|
|
654 |
else {
|
|
|
655 |
// Create a "cluster" of one since we are just crossing
|
|
|
656 |
// a quadrant
|
|
|
657 |
$cidx++;
|
|
|
658 |
$clusters[$cidx][0] = $i;
|
|
|
659 |
$clusters[$cidx][1] = 1;
|
|
|
660 |
}
|
|
|
661 |
}
|
|
|
662 |
else {
|
|
|
663 |
if( $incluster ) {
|
|
|
664 |
// Add the last slice
|
|
|
665 |
$clusters[$cidx][1]++;
|
|
|
666 |
$incluster = false;
|
|
|
667 |
}
|
|
|
668 |
else { // Create a "cluster" of one
|
|
|
669 |
$cidx++;
|
|
|
670 |
$clusters[$cidx][0] = $i;
|
|
|
671 |
$clusters[$cidx][1] = 1;
|
|
|
672 |
}
|
|
|
673 |
}
|
|
|
674 |
}
|
|
|
675 |
// Handle the very last slice
|
|
|
676 |
if( $incluster ) {
|
|
|
677 |
$clusters[$cidx][1]++;
|
|
|
678 |
}
|
|
|
679 |
else { // Create a "cluster" of one
|
|
|
680 |
$cidx++;
|
|
|
681 |
$clusters[$cidx][0] = $i;
|
|
|
682 |
$clusters[$cidx][1] = 1;
|
|
|
683 |
}
|
|
|
684 |
|
|
|
685 |
/*
|
|
|
686 |
if( true ) {
|
|
|
687 |
// Debug printout in labels
|
|
|
688 |
for( $i=0; $i <= $cidx; ++$i ) {
|
|
|
689 |
for( $j=0; $j < $clusters[$i][1]; ++$j ) {
|
|
|
690 |
$a = $this->la[$clusters[$i][0]+$j];
|
|
|
691 |
$aa = round($a*180/M_PI);
|
|
|
692 |
$q = $this->Quadrant($a);
|
|
|
693 |
$this->labels[$clusters[$i][0]+$j]="[$q:$aa] $i:$j";
|
|
|
694 |
}
|
|
|
695 |
}
|
|
|
696 |
}
|
|
|
697 |
*/
|
|
|
698 |
|
|
|
699 |
//-----------------------------------------------------------------------
|
|
|
700 |
// Step 2 of the algorithm is use the clusters and draw the labels
|
|
|
701 |
// and guidelines
|
|
|
702 |
//-----------------------------------------------------------------------
|
|
|
703 |
|
|
|
704 |
// We use the font height as the base factor for how far we need to
|
|
|
705 |
// spread the labels in the Y-direction.
|
|
|
706 |
$this->value->ApplyFont($img);
|
|
|
707 |
$fh = $img->GetFontHeight();
|
|
|
708 |
$origvstep=$fh*$this->iGuideVFactor;
|
|
|
709 |
$this->value->SetMargin(0);
|
|
|
710 |
|
|
|
711 |
// Number of clusters found
|
|
|
712 |
$nc = count($clusters);
|
|
|
713 |
|
|
|
714 |
// Walk through all the clusters
|
|
|
715 |
for($i=0; $i < $nc; ++$i) {
|
|
|
716 |
|
|
|
717 |
// Start angle and number of slices in this cluster
|
|
|
718 |
$csize = $clusters[$i][1];
|
|
|
719 |
$a = $this->la[$clusters[$i][0]];
|
|
|
720 |
$q = $this->Quadrant($a);
|
|
|
721 |
|
|
|
722 |
// Now set up the start and end conditions to make sure that
|
|
|
723 |
// in each cluster we walk through the all the slices starting with the slice
|
|
|
724 |
// closest to the equator. Since all slices are numbered clockwise from "3'a clock"
|
|
|
725 |
// we have different conditions depending on in which quadrant the slice lies within.
|
|
|
726 |
if( $q == 0 ) {
|
|
|
727 |
$start = $csize-1; $idx = $start; $step = -1; $vstep = -$origvstep;
|
|
|
728 |
}
|
|
|
729 |
elseif( $q == 1 ) {
|
|
|
730 |
$start = 0; $idx = $start; $step = 1; $vstep = -$origvstep;
|
|
|
731 |
}
|
|
|
732 |
elseif( $q == 2 ) {
|
|
|
733 |
$start = $csize-1; $idx = $start; $step = -1; $vstep = $origvstep;
|
|
|
734 |
}
|
|
|
735 |
elseif( $q == 3 ) {
|
|
|
736 |
$start = 0; $idx = $start; $step = 1; $vstep = $origvstep;
|
|
|
737 |
}
|
|
|
738 |
|
|
|
739 |
// Walk through all slices within this cluster
|
|
|
740 |
for($j=0; $j < $csize; ++$j) {
|
|
|
741 |
// Now adjust the position of the labels in each cluster starting
|
|
|
742 |
// with the slice that is closest to the equator of the pie
|
|
|
743 |
$a = $this->la[$clusters[$i][0]+$idx];
|
|
|
744 |
|
|
|
745 |
// Guide line start in the center of the arc of the slice
|
|
|
746 |
$r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];
|
|
|
747 |
$x = round($r*cos($a)+$xc);
|
|
|
748 |
$y = round($yc-$r*sin($a));
|
|
|
749 |
|
|
|
750 |
// The distance from the arc depends on chosen font and the "R-Factor"
|
|
|
751 |
$r += $fh*$this->iGuideLineRFactor;
|
|
|
752 |
|
|
|
753 |
// Should the labels be placed curved along the pie or in straight columns
|
|
|
754 |
// outside the pie?
|
|
|
755 |
if( $this->iGuideLineCurve )
|
|
|
756 |
$xt=round($r*cos($a)+$xc);
|
|
|
757 |
|
|
|
758 |
// If this is the first slice in the cluster we need some first time
|
|
|
759 |
// proessing
|
|
|
760 |
if( $idx == $start ) {
|
|
|
761 |
if( ! $this->iGuideLineCurve )
|
|
|
762 |
$xt=round($r*cos($a)+$xc);
|
|
|
763 |
$yt=round($yc-$r*sin($a));
|
|
|
764 |
|
|
|
765 |
// Some special consideration in case this cluster starts
|
|
|
766 |
// in quadrant 1 or 3 very close to the "equator" (< 20 degrees)
|
|
|
767 |
// and the previous clusters last slice is within the tolerance.
|
|
|
768 |
// In that case we add a font height to this labels Y-position
|
|
|
769 |
// so it doesn't collide with
|
|
|
770 |
// the slice in the previous cluster
|
|
|
771 |
$prevcluster = ($i + ($nc-1) ) % $nc;
|
|
|
772 |
$previdx=$clusters[$prevcluster][0]+$clusters[$prevcluster][1]-1;
|
|
|
773 |
if( $q == 1 && $a > 160*M_PI/180 ) {
|
|
|
774 |
// Get the angle for the previous clusters last slice
|
|
|
775 |
$diff = abs($a-$this->la[$previdx]);
|
|
|
776 |
if( $diff < $tresh_hold ) {
|
|
|
777 |
$yt -= $fh;
|
|
|
778 |
}
|
|
|
779 |
}
|
|
|
780 |
elseif( $q == 3 && $a > 340*M_PI/180 ) {
|
|
|
781 |
// We need to subtract 360 to compare angle distance between
|
|
|
782 |
// q=0 and q=3
|
|
|
783 |
$diff = abs($a-$this->la[$previdx]-360*M_PI/180);
|
|
|
784 |
if( $diff < $tresh_hold ) {
|
|
|
785 |
$yt += $fh;
|
|
|
786 |
}
|
|
|
787 |
}
|
|
|
788 |
|
|
|
789 |
}
|
|
|
790 |
else {
|
|
|
791 |
// The step is at minimum $vstep but if the slices are relatively large
|
|
|
792 |
// we make sure that we add at least a step that corresponds to the vertical
|
|
|
793 |
// distance between the centers at the arc on the slice
|
|
|
794 |
$prev_a = $this->la[$clusters[$i][0]+($idx-$step)];
|
|
|
795 |
$dy = abs($radius*(sin($a)-sin($prev_a))*1.2);
|
|
|
796 |
if( $vstep > 0 )
|
|
|
797 |
$yt += max($vstep,$dy);
|
|
|
798 |
else
|
|
|
799 |
$yt += min($vstep,-$dy);
|
|
|
800 |
}
|
|
|
801 |
|
|
|
802 |
$label = $this->labels[$clusters[$i][0]+$idx];
|
|
|
803 |
|
|
|
804 |
if( $csize == 1 ) {
|
|
|
805 |
// A "meta" cluster with only one slice
|
|
|
806 |
$r = $radius+$this->explode_radius[$n-1-($clusters[$i][0]+$idx)];
|
|
|
807 |
$rr = $r+$img->GetFontHeight()/2;
|
|
|
808 |
$xt=round($rr*cos($a)+$xc);
|
|
|
809 |
$yt=round($yc-$rr*sin($a));
|
|
|
810 |
$this->StrokeLabel($label,$img,$xc,$yc,$a,$r);
|
|
|
811 |
if( $this->iShowGuideLineForSingle )
|
|
|
812 |
$this->guideline->Stroke($img,$x,$y,$xt,$yt);
|
|
|
813 |
}
|
|
|
814 |
else {
|
|
|
815 |
$this->guideline->Stroke($img,$x,$y,$xt,$yt);
|
|
|
816 |
if( $q==1 || $q==2 ) {
|
|
|
817 |
// Left side of Pie
|
|
|
818 |
$this->guideline->Stroke($img,$xt,$yt,$xt-$this->guidelinemargin,$yt);
|
|
|
819 |
$lbladj = -$this->guidelinemargin-5;
|
|
|
820 |
$this->value->halign = "right";
|
|
|
821 |
$this->value->valign = "center";
|
|
|
822 |
}
|
|
|
823 |
else {
|
|
|
824 |
// Right side of pie
|
|
|
825 |
$this->guideline->Stroke($img,$xt,$yt,$xt+$this->guidelinemargin,$yt);
|
|
|
826 |
$lbladj = $this->guidelinemargin+5;
|
|
|
827 |
$this->value->halign = "left";
|
|
|
828 |
$this->value->valign = "center";
|
|
|
829 |
}
|
|
|
830 |
$this->value->Stroke($img,$label,$xt+$lbladj,$yt);
|
|
|
831 |
}
|
|
|
832 |
|
|
|
833 |
// Udate idx to point to next slice in the cluster to process
|
|
|
834 |
$idx += $step;
|
|
|
835 |
}
|
|
|
836 |
}
|
|
|
837 |
}
|
|
|
838 |
|
|
|
839 |
function StrokeAllLabels($img,$xc,$yc,$radius) {
|
|
|
840 |
// First normalize all angles for labels
|
|
|
841 |
$n = count($this->la);
|
|
|
842 |
for($i=0; $i < $n; ++$i) {
|
|
|
843 |
$this->la[$i] = $this->NormAngle($this->la[$i]);
|
|
|
844 |
}
|
|
|
845 |
if( $this->guideline->iShow ) {
|
|
|
846 |
$this->StrokeGuideLabels($img,$xc,$yc,$radius);
|
|
|
847 |
}
|
|
|
848 |
else {
|
|
|
849 |
$n = count($this->labels);
|
|
|
850 |
for($i=0; $i < $n; ++$i) {
|
|
|
851 |
$this->StrokeLabel($this->labels[$i],$img,$xc,$yc,
|
|
|
852 |
$this->la[$i],
|
|
|
853 |
$radius + $this->explode_radius[$n-1-$i]);
|
|
|
854 |
}
|
|
|
855 |
}
|
|
|
856 |
}
|
|
|
857 |
|
|
|
858 |
// Position the labels of each slice
|
|
|
859 |
function StrokeLabel($label,$img,$xc,$yc,$a,$r) {
|
|
|
860 |
|
|
|
861 |
// Default value
|
|
|
862 |
if( $this->ilabelposadj === 'auto' )
|
|
|
863 |
$this->ilabelposadj = 0.65;
|
|
|
864 |
|
|
|
865 |
// We position the values diferently depending on if they are inside
|
|
|
866 |
// or outside the pie
|
|
|
867 |
if( $this->ilabelposadj < 1.0 ) {
|
|
|
868 |
|
|
|
869 |
$this->value->SetAlign('center','center');
|
|
|
870 |
$this->value->margin = 0;
|
|
|
871 |
|
|
|
872 |
$xt=round($this->ilabelposadj*$r*cos($a)+$xc);
|
|
|
873 |
$yt=round($yc-$this->ilabelposadj*$r*sin($a));
|
|
|
874 |
|
|
|
875 |
$this->value->Stroke($img,$label,$xt,$yt);
|
|
|
876 |
}
|
|
|
877 |
else {
|
|
|
878 |
|
|
|
879 |
$this->value->halign = "left";
|
|
|
880 |
$this->value->valign = "top";
|
|
|
881 |
$this->value->margin = 0;
|
|
|
882 |
|
|
|
883 |
// Position the axis title.
|
|
|
884 |
// dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
|
|
|
885 |
// that intersects with the extension of the corresponding axis. The code looks a little
|
|
|
886 |
// bit messy but this is really the only way of having a reasonable position of the
|
|
|
887 |
// axis titles.
|
|
|
888 |
$this->value->ApplyFont($img);
|
|
|
889 |
$h=$img->GetTextHeight($label);
|
|
|
890 |
// For numeric values the format of the display value
|
|
|
891 |
// must be taken into account
|
|
|
892 |
if( is_numeric($label) ) {
|
|
|
893 |
if( $label > 0 )
|
|
|
894 |
$w=$img->GetTextWidth(sprintf($this->value->format,$label));
|
|
|
895 |
else
|
|
|
896 |
$w=$img->GetTextWidth(sprintf($this->value->negformat,$label));
|
|
|
897 |
}
|
|
|
898 |
else
|
|
|
899 |
$w=$img->GetTextWidth($label);
|
|
|
900 |
|
|
|
901 |
if( $this->ilabelposadj > 1.0 && $this->ilabelposadj < 5.0) {
|
|
|
902 |
$r *= $this->ilabelposadj;
|
|
|
903 |
}
|
|
|
904 |
|
|
|
905 |
$r += $img->GetFontHeight()/1.5;
|
|
|
906 |
|
|
|
907 |
$xt=round($r*cos($a)+$xc);
|
|
|
908 |
$yt=round($yc-$r*sin($a));
|
|
|
909 |
|
|
|
910 |
// Normalize angle
|
|
|
911 |
while( $a < 0 ) $a += 2*M_PI;
|
|
|
912 |
while( $a > 2*M_PI ) $a -= 2*M_PI;
|
|
|
913 |
|
|
|
914 |
if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
|
|
|
915 |
if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
|
|
|
916 |
if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
|
|
|
917 |
if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
|
|
|
918 |
|
|
|
919 |
if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
|
|
|
920 |
if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
|
|
|
921 |
if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
|
|
|
922 |
if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
|
|
|
923 |
if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
|
|
|
924 |
|
|
|
925 |
$this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h);
|
|
|
926 |
}
|
|
|
927 |
}
|
|
|
928 |
} // Class
|
|
|
929 |
|
|
|
930 |
|
|
|
931 |
//===================================================
|
|
|
932 |
// CLASS PiePlotC
|
|
|
933 |
// Description: Same as a normal pie plot but with a
|
|
|
934 |
// filled circle in the center
|
|
|
935 |
//===================================================
|
|
|
936 |
class PiePlotC extends PiePlot {
|
|
|
937 |
private $imidsize=0.5; // Fraction of total width
|
|
|
938 |
private $imidcolor='white';
|
|
|
939 |
public $midtitle='';
|
|
|
940 |
private $middlecsimtarget="",$middlecsimalt="";
|
|
|
941 |
|
|
|
942 |
function PiePlotC($data,$aCenterTitle='') {
|
|
|
943 |
parent::PiePlot($data);
|
|
|
944 |
$this->midtitle = new Text();
|
|
|
945 |
$this->midtitle->ParagraphAlign('center');
|
|
|
946 |
}
|
|
|
947 |
|
|
|
948 |
function SetMid($aTitle,$aColor='white',$aSize=0.5) {
|
|
|
949 |
$this->midtitle->Set($aTitle);
|
|
|
950 |
|
|
|
951 |
$this->imidsize = $aSize ;
|
|
|
952 |
$this->imidcolor = $aColor ;
|
|
|
953 |
}
|
|
|
954 |
|
|
|
955 |
function SetMidTitle($aTitle) {
|
|
|
956 |
$this->midtitle->Set($aTitle);
|
|
|
957 |
}
|
|
|
958 |
|
|
|
959 |
function SetMidSize($aSize) {
|
|
|
960 |
$this->imidsize = $aSize ;
|
|
|
961 |
}
|
|
|
962 |
|
|
|
963 |
function SetMidColor($aColor) {
|
|
|
964 |
$this->imidcolor = $aColor ;
|
|
|
965 |
}
|
|
|
966 |
|
|
|
967 |
function SetMidCSIM($aTarget,$aAlt) {
|
|
|
968 |
$this->middlecsimtarget = $aTarget;
|
|
|
969 |
$this->middlecsimalt = $aAlt;
|
|
|
970 |
}
|
|
|
971 |
|
|
|
972 |
function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) {
|
|
|
973 |
//Slice number, ellipse centre (x,y), radius, start angle, end angle
|
|
|
974 |
while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
|
|
|
975 |
while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
|
|
|
976 |
|
|
|
977 |
$sa = 2*M_PI - $sa;
|
|
|
978 |
$ea = 2*M_PI - $ea;
|
|
|
979 |
|
|
|
980 |
// Special case when we have only one slice since then both start and end
|
|
|
981 |
// angle will be == 0
|
|
|
982 |
if( abs($sa - $ea) < 0.0001 ) {
|
|
|
983 |
$sa=2*M_PI; $ea=0;
|
|
|
984 |
}
|
|
|
985 |
|
|
|
986 |
// Add inner circle first point
|
|
|
987 |
$xp = floor(($this->imidsize*$radius*cos($ea))+$xc);
|
|
|
988 |
$yp = floor($yc-($this->imidsize*$radius*sin($ea)));
|
|
|
989 |
$coords = "$xp, $yp";
|
|
|
990 |
|
|
|
991 |
//add coordinates every 0.25 radians
|
|
|
992 |
$a=$ea+0.25;
|
|
|
993 |
|
|
|
994 |
// If we cross the 360-limit with a slice we need to handle
|
|
|
995 |
// the fact that end angle is smaller than start
|
|
|
996 |
if( $sa < $ea ) {
|
|
|
997 |
while ($a <= 2*M_PI) {
|
|
|
998 |
$xp = floor($radius*cos($a)+$xc);
|
|
|
999 |
$yp = floor($yc-$radius*sin($a));
|
|
|
1000 |
$coords.= ", $xp, $yp";
|
|
|
1001 |
$a += 0.25;
|
|
|
1002 |
}
|
|
|
1003 |
$a -= 2*M_PI;
|
|
|
1004 |
}
|
|
|
1005 |
|
|
|
1006 |
while ($a < $sa) {
|
|
|
1007 |
$xp = floor(($this->imidsize*$radius*cos($a)+$xc));
|
|
|
1008 |
$yp = floor($yc-($this->imidsize*$radius*sin($a)));
|
|
|
1009 |
$coords.= ", $xp, $yp";
|
|
|
1010 |
$a += 0.25;
|
|
|
1011 |
}
|
|
|
1012 |
|
|
|
1013 |
// Make sure we end at the last point
|
|
|
1014 |
$xp = floor(($this->imidsize*$radius*cos($sa)+$xc));
|
|
|
1015 |
$yp = floor($yc-($this->imidsize*$radius*sin($sa)));
|
|
|
1016 |
$coords.= ", $xp, $yp";
|
|
|
1017 |
|
|
|
1018 |
// Straight line to outer circle
|
|
|
1019 |
$xp = floor($radius*cos($sa)+$xc);
|
|
|
1020 |
$yp = floor($yc-$radius*sin($sa));
|
|
|
1021 |
$coords.= ", $xp, $yp";
|
|
|
1022 |
|
|
|
1023 |
//add coordinates every 0.25 radians
|
|
|
1024 |
$a=$sa - 0.25;
|
|
|
1025 |
while ($a > $ea) {
|
|
|
1026 |
$xp = floor($radius*cos($a)+$xc);
|
|
|
1027 |
$yp = floor($yc-$radius*sin($a));
|
|
|
1028 |
$coords.= ", $xp, $yp";
|
|
|
1029 |
$a -= 0.25;
|
|
|
1030 |
}
|
|
|
1031 |
|
|
|
1032 |
//Add the last point on the arc
|
|
|
1033 |
$xp = floor($radius*cos($ea)+$xc);
|
|
|
1034 |
$yp = floor($yc-$radius*sin($ea));
|
|
|
1035 |
$coords.= ", $xp, $yp";
|
|
|
1036 |
|
|
|
1037 |
// Close the arc
|
|
|
1038 |
$xp = floor(($this->imidsize*$radius*cos($ea))+$xc);
|
|
|
1039 |
$yp = floor($yc-($this->imidsize*$radius*sin($ea)));
|
|
|
1040 |
$coords .= ", $xp, $yp";
|
|
|
1041 |
|
|
|
1042 |
if( !empty($this->csimtargets[$i]) ) {
|
|
|
1043 |
$this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".
|
|
|
1044 |
$this->csimtargets[$i]."\"";
|
|
|
1045 |
if( !empty($this->csimalts[$i]) ) {
|
|
|
1046 |
$tmp=sprintf($this->csimalts[$i],$this->data[$i]);
|
|
|
1047 |
$this->csimareas .= " title=\"$tmp\"";
|
|
|
1048 |
}
|
|
|
1049 |
$this->csimareas .= " alt=\"$tmp\" />\n";
|
|
|
1050 |
}
|
|
|
1051 |
}
|
|
|
1052 |
|
|
|
1053 |
|
|
|
1054 |
function Stroke($img,$aaoption=0) {
|
|
|
1055 |
|
|
|
1056 |
// Stroke the pie but don't stroke values
|
|
|
1057 |
$tmp = $this->value->show;
|
|
|
1058 |
$this->value->show = false;
|
|
|
1059 |
parent::Stroke($img,$aaoption);
|
|
|
1060 |
$this->value->show = $tmp;
|
|
|
1061 |
|
|
|
1062 |
$xc = round($this->posx*$img->width);
|
|
|
1063 |
$yc = round($this->posy*$img->height);
|
|
|
1064 |
|
|
|
1065 |
$radius = floor($this->radius * min($img->width,$img->height)) ;
|
|
|
1066 |
|
|
|
1067 |
|
|
|
1068 |
if( $this->imidsize > 0 && $aaoption !== 2 ) {
|
|
|
1069 |
|
|
|
1070 |
if( $this->ishadowcolor != "" ) {
|
|
|
1071 |
$img->SetColor($this->ishadowcolor);
|
|
|
1072 |
$img->FilledCircle($xc+$this->ishadowdrop,$yc+$this->ishadowdrop,
|
|
|
1073 |
round($radius*$this->imidsize));
|
|
|
1074 |
}
|
|
|
1075 |
|
|
|
1076 |
$img->SetColor($this->imidcolor);
|
|
|
1077 |
$img->FilledCircle($xc,$yc,round($radius*$this->imidsize));
|
|
|
1078 |
|
|
|
1079 |
if( $this->pie_border && $aaoption === 0 ) {
|
|
|
1080 |
$img->SetColor($this->color);
|
|
|
1081 |
$img->Circle($xc,$yc,round($radius*$this->imidsize));
|
|
|
1082 |
}
|
|
|
1083 |
|
|
|
1084 |
if( !empty($this->middlecsimtarget) )
|
|
|
1085 |
$this->AddMiddleCSIM($xc,$yc,round($radius*$this->imidsize));
|
|
|
1086 |
|
|
|
1087 |
}
|
|
|
1088 |
|
|
|
1089 |
if( $this->value->show && $aaoption !== 1) {
|
|
|
1090 |
$this->StrokeAllLabels($img,$xc,$yc,$radius);
|
|
|
1091 |
$this->midtitle->SetPos($xc,$yc,'center','center');
|
|
|
1092 |
$this->midtitle->Stroke($img);
|
|
|
1093 |
}
|
|
|
1094 |
|
|
|
1095 |
}
|
|
|
1096 |
|
|
|
1097 |
function AddMiddleCSIM($xc,$yc,$r) {
|
|
|
1098 |
$xc=round($xc);$yc=round($yc);$r=round($r);
|
|
|
1099 |
$this->csimareas .= "<area shape=\"circle\" coords=\"$xc,$yc,$r\" href=\"".
|
|
|
1100 |
$this->middlecsimtarget."\"";
|
|
|
1101 |
if( !empty($this->middlecsimalt) ) {
|
|
|
1102 |
$tmp = $this->middlecsimalt;
|
|
|
1103 |
$this->csimareas .= " title=\"$tmp\"";
|
|
|
1104 |
}
|
|
|
1105 |
$this->csimareas .= " alt=\"$tmp\" />\n";
|
|
|
1106 |
}
|
|
|
1107 |
|
|
|
1108 |
function StrokeLabel($label,$img,$xc,$yc,$a,$r) {
|
|
|
1109 |
|
|
|
1110 |
if( $this->ilabelposadj === 'auto' )
|
|
|
1111 |
$this->ilabelposadj = (1-$this->imidsize)/2+$this->imidsize;
|
|
|
1112 |
|
|
|
1113 |
parent::StrokeLabel($label,$img,$xc,$yc,$a,$r);
|
|
|
1114 |
|
|
|
1115 |
}
|
|
|
1116 |
|
|
|
1117 |
}
|
|
|
1118 |
|
|
|
1119 |
|
|
|
1120 |
//===================================================
|
|
|
1121 |
// CLASS PieGraph
|
|
|
1122 |
// Description:
|
|
|
1123 |
//===================================================
|
|
|
1124 |
class PieGraph extends Graph {
|
|
|
1125 |
private $posx, $posy, $radius;
|
|
|
1126 |
private $legends=array();
|
|
|
1127 |
public $plots=array();
|
|
|
1128 |
public $pieaa = false ;
|
|
|
1129 |
//---------------
|
|
|
1130 |
// CONSTRUCTOR
|
|
|
1131 |
function PieGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) {
|
|
|
1132 |
$this->Graph($width,$height,$cachedName,$timeout,$inline);
|
|
|
1133 |
$this->posx=$width/2;
|
|
|
1134 |
$this->posy=$height/2;
|
|
|
1135 |
$this->SetColor(array(255,255,255));
|
|
|
1136 |
}
|
|
|
1137 |
|
|
|
1138 |
//---------------
|
|
|
1139 |
// PUBLIC METHODS
|
|
|
1140 |
function Add($aObj) {
|
|
|
1141 |
|
|
|
1142 |
if( is_array($aObj) && count($aObj) > 0 )
|
|
|
1143 |
$cl = $aObj[0];
|
|
|
1144 |
else
|
|
|
1145 |
$cl = $aObj;
|
|
|
1146 |
|
|
|
1147 |
if( $cl instanceof Text )
|
|
|
1148 |
$this->AddText($aObj);
|
|
|
1149 |
elseif( class_exists('IconPlot',false) && ($cl instanceof IconPlot) )
|
|
|
1150 |
$this->AddIcon($aObj);
|
|
|
1151 |
else {
|
|
|
1152 |
if( is_array($aObj) ) {
|
|
|
1153 |
$n = count($aObj);
|
|
|
1154 |
for($i=0; $i < $n; ++$i ) {
|
|
|
1155 |
$this->plots[] = $aObj[$i];
|
|
|
1156 |
}
|
|
|
1157 |
}
|
|
|
1158 |
else {
|
|
|
1159 |
$this->plots[] = $aObj;
|
|
|
1160 |
}
|
|
|
1161 |
}
|
|
|
1162 |
}
|
|
|
1163 |
|
|
|
1164 |
function SetAntiAliasing($aFlg=true) {
|
|
|
1165 |
$this->pieaa = $aFlg;
|
|
|
1166 |
}
|
|
|
1167 |
|
|
|
1168 |
function SetColor($c) {
|
|
|
1169 |
$this->SetMarginColor($c);
|
|
|
1170 |
}
|
|
|
1171 |
|
|
|
1172 |
|
|
|
1173 |
function DisplayCSIMAreas() {
|
|
|
1174 |
$csim="";
|
|
|
1175 |
foreach($this->plots as $p ) {
|
|
|
1176 |
$csim .= $p->GetCSIMareas();
|
|
|
1177 |
}
|
|
|
1178 |
//$csim.= $this->legend->GetCSIMareas();
|
|
|
1179 |
if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
|
|
|
1180 |
$this->img->SetColor($this->csimcolor);
|
|
|
1181 |
$n = count($coords[0]);
|
|
|
1182 |
for ($i=0; $i < $n; $i++) {
|
|
|
1183 |
if ($coords[1][$i]=="poly") {
|
|
|
1184 |
preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
|
|
|
1185 |
$this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
|
|
|
1186 |
$m = count($pts[0]);
|
|
|
1187 |
for ($j=0; $j < $m; $j++) {
|
|
|
1188 |
$this->img->LineTo($pts[1][$j],$pts[2][$j]);
|
|
|
1189 |
}
|
|
|
1190 |
} else if ($coords[1][$i]=="rect") {
|
|
|
1191 |
$pts = preg_split('/,/', $coords[2][$i]);
|
|
|
1192 |
$this->img->SetStartPoint($pts[0],$pts[1]);
|
|
|
1193 |
$this->img->LineTo($pts[2],$pts[1]);
|
|
|
1194 |
$this->img->LineTo($pts[2],$pts[3]);
|
|
|
1195 |
$this->img->LineTo($pts[0],$pts[3]);
|
|
|
1196 |
$this->img->LineTo($pts[0],$pts[1]);
|
|
|
1197 |
|
|
|
1198 |
}
|
|
|
1199 |
}
|
|
|
1200 |
}
|
|
|
1201 |
}
|
|
|
1202 |
|
|
|
1203 |
// Method description
|
|
|
1204 |
function Stroke($aStrokeFileName="") {
|
|
|
1205 |
// If the filename is the predefined value = '_csim_special_'
|
|
|
1206 |
// we assume that the call to stroke only needs to do enough
|
|
|
1207 |
// to correctly generate the CSIM maps.
|
|
|
1208 |
// We use this variable to skip things we don't strictly need
|
|
|
1209 |
// to do to generate the image map to improve performance
|
|
|
1210 |
// a best we can. Therefor you will see a lot of tests !$_csim in the
|
|
|
1211 |
// code below.
|
|
|
1212 |
$_csim = ($aStrokeFileName===_CSIM_SPECIALFILE);
|
|
|
1213 |
|
|
|
1214 |
// We need to know if we have stroked the plot in the
|
|
|
1215 |
// GetCSIMareas. Otherwise the CSIM hasn't been generated
|
|
|
1216 |
// and in the case of GetCSIM called before stroke to generate
|
|
|
1217 |
// CSIM without storing an image to disk GetCSIM must call Stroke.
|
|
|
1218 |
$this->iHasStroked = true;
|
|
|
1219 |
|
|
|
1220 |
$n = count($this->plots);
|
|
|
1221 |
|
|
|
1222 |
if( $this->pieaa ) {
|
|
|
1223 |
|
|
|
1224 |
if( !$_csim ) {
|
|
|
1225 |
if( $this->background_image != "" ) {
|
|
|
1226 |
$this->StrokeFrameBackground();
|
|
|
1227 |
}
|
|
|
1228 |
else {
|
|
|
1229 |
$this->StrokeFrame();
|
|
|
1230 |
$this->StrokeBackgroundGrad();
|
|
|
1231 |
}
|
|
|
1232 |
}
|
|
|
1233 |
|
|
|
1234 |
|
|
|
1235 |
$w = $this->img->width;
|
|
|
1236 |
$h = $this->img->height;
|
|
|
1237 |
$oldimg = $this->img->img;
|
|
|
1238 |
|
|
|
1239 |
$this->img->CreateImgCanvas(2*$w,2*$h);
|
|
|
1240 |
|
|
|
1241 |
$this->img->SetColor( $this->margin_color );
|
|
|
1242 |
$this->img->FilledRectangle(0,0,2*$w-1,2*$h-1);
|
|
|
1243 |
|
|
|
1244 |
// Make all icons *2 i size since we will be scaling down the
|
|
|
1245 |
// imahe to do the anti aliasing
|
|
|
1246 |
$ni = count($this->iIcons);
|
|
|
1247 |
for($i=0; $i < $ni; ++$i) {
|
|
|
1248 |
$this->iIcons[$i]->iScale *= 2 ;
|
|
|
1249 |
if( $this->iIcons[$i]->iX > 1 )
|
|
|
1250 |
$this->iIcons[$i]->iX *= 2 ;
|
|
|
1251 |
if( $this->iIcons[$i]->iY > 1 )
|
|
|
1252 |
$this->iIcons[$i]->iY *= 2 ;
|
|
|
1253 |
}
|
|
|
1254 |
|
|
|
1255 |
$this->StrokeIcons();
|
|
|
1256 |
|
|
|
1257 |
for($i=0; $i < $n; ++$i) {
|
|
|
1258 |
if( $this->plots[$i]->posx > 1 )
|
|
|
1259 |
$this->plots[$i]->posx *= 2 ;
|
|
|
1260 |
if( $this->plots[$i]->posy > 1 )
|
|
|
1261 |
$this->plots[$i]->posy *= 2 ;
|
|
|
1262 |
|
|
|
1263 |
$this->plots[$i]->Stroke($this->img,1);
|
|
|
1264 |
|
|
|
1265 |
if( $this->plots[$i]->posx > 1 )
|
|
|
1266 |
$this->plots[$i]->posx /= 2 ;
|
|
|
1267 |
if( $this->plots[$i]->posy > 1 )
|
|
|
1268 |
$this->plots[$i]->posy /= 2 ;
|
|
|
1269 |
}
|
|
|
1270 |
|
|
|
1271 |
$indent = $this->doframe ? ($this->frame_weight + ($this->doshadow ? $this->shadow_width : 0 )) : 0 ;
|
|
|
1272 |
$indent += $this->framebevel ? $this->framebeveldepth + 1 : 0 ;
|
|
|
1273 |
$this->img->CopyCanvasH($oldimg,$this->img->img,$indent,$indent,$indent,$indent,
|
|
|
1274 |
$w-2*$indent,$h-2*$indent,2*($w-$indent),2*($h-$indent));
|
|
|
1275 |
|
|
|
1276 |
$this->img->img = $oldimg ;
|
|
|
1277 |
$this->img->width = $w ;
|
|
|
1278 |
$this->img->height = $h ;
|
|
|
1279 |
|
|
|
1280 |
for($i=0; $i < $n; ++$i) {
|
|
|
1281 |
$this->plots[$i]->Stroke($this->img,2); // Stroke labels
|
|
|
1282 |
$this->plots[$i]->Legend($this);
|
|
|
1283 |
}
|
|
|
1284 |
|
|
|
1285 |
}
|
|
|
1286 |
else {
|
|
|
1287 |
|
|
|
1288 |
if( !$_csim ) {
|
|
|
1289 |
if( $this->background_image != "" ) {
|
|
|
1290 |
$this->StrokeFrameBackground();
|
|
|
1291 |
}
|
|
|
1292 |
else {
|
|
|
1293 |
$this->StrokeFrame();
|
|
|
1294 |
}
|
|
|
1295 |
}
|
|
|
1296 |
|
|
|
1297 |
$this->StrokeIcons();
|
|
|
1298 |
|
|
|
1299 |
for($i=0; $i < $n; ++$i) {
|
|
|
1300 |
$this->plots[$i]->Stroke($this->img);
|
|
|
1301 |
$this->plots[$i]->Legend($this);
|
|
|
1302 |
}
|
|
|
1303 |
}
|
|
|
1304 |
|
|
|
1305 |
$this->legend->Stroke($this->img);
|
|
|
1306 |
$this->footer->Stroke($this->img);
|
|
|
1307 |
$this->StrokeTitles();
|
|
|
1308 |
|
|
|
1309 |
if( !$_csim ) {
|
|
|
1310 |
|
|
|
1311 |
// Stroke texts
|
|
|
1312 |
if( $this->texts != null ) {
|
|
|
1313 |
$n = count($this->texts);
|
|
|
1314 |
for($i=0; $i < $n; ++$i ) {
|
|
|
1315 |
$this->texts[$i]->Stroke($this->img);
|
|
|
1316 |
}
|
|
|
1317 |
}
|
|
|
1318 |
|
|
|
1319 |
if( _JPG_DEBUG ) {
|
|
|
1320 |
$this->DisplayCSIMAreas();
|
|
|
1321 |
}
|
|
|
1322 |
|
|
|
1323 |
// Should we do any final image transformation
|
|
|
1324 |
if( $this->iImgTrans ) {
|
|
|
1325 |
if( !class_exists('ImgTrans',false) ) {
|
|
|
1326 |
require_once('jpgraph_imgtrans.php');
|
|
|
1327 |
//JpGraphError::Raise('In order to use image transformation you must include the file jpgraph_imgtrans.php in your script.');
|
|
|
1328 |
}
|
|
|
1329 |
|
|
|
1330 |
$tform = new ImgTrans($this->img->img);
|
|
|
1331 |
$this->img->img = $tform->Skew3D($this->iImgTransHorizon,$this->iImgTransSkewDist,
|
|
|
1332 |
$this->iImgTransDirection,$this->iImgTransHighQ,
|
|
|
1333 |
$this->iImgTransMinSize,$this->iImgTransFillColor,
|
|
|
1334 |
$this->iImgTransBorder);
|
|
|
1335 |
}
|
|
|
1336 |
|
|
|
1337 |
|
|
|
1338 |
// If the filename is given as the special "__handle"
|
|
|
1339 |
// then the image handler is returned and the image is NOT
|
|
|
1340 |
// streamed back
|
|
|
1341 |
if( $aStrokeFileName == _IMG_HANDLER ) {
|
|
|
1342 |
return $this->img->img;
|
|
|
1343 |
}
|
|
|
1344 |
else {
|
|
|
1345 |
// Finally stream the generated picture
|
|
|
1346 |
$this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,
|
|
|
1347 |
$aStrokeFileName);
|
|
|
1348 |
}
|
|
|
1349 |
}
|
|
|
1350 |
}
|
|
|
1351 |
} // Class
|
|
|
1352 |
|
|
|
1353 |
/* EOF */
|
|
|
1354 |
?>
|