2 //=======================================================================
\r
3 // File: JPGRAPH_PLOTMARK.PHP
\r
4 // Description: Class file. Handles plotmarks
\r
5 // Created: 2003-03-21
\r
6 // Author: Johan Persson (johanp@aditus.nu)
\r
7 // Ver: $Id: jpgraph_plotmark.inc,v 1.1 2006/07/07 13:37:14 powles Exp $
\r
9 // Copyright (c) Aditus Consulting. All rights reserved.
\r
10 //========================================================================
\r
13 //========================================================================
\r
15 // Description: Base class for all image data classes that contains the
\r
17 //========================================================================
\r
19 var $name = ''; // Each subclass gives a name
\r
20 var $an = array(); // Data array names
\r
21 var $colors = array(); // Available colors
\r
22 var $index = array(); // Index for colors
\r
23 var $maxidx = 0 ; // Max color index
\r
24 var $anchor_x=0.5, $anchor_y=0.5 ; // Where is the center of the image
\r
25 // Create a GD image from the data and return a GD handle
\r
26 function GetImg($aMark,$aIdx) {
\r
27 $n = $this->an[$aMark];
\r
28 if( is_string($aIdx) ) {
\r
29 if( !in_array($aIdx,$this->colors) ) {
\r
30 JpGraphError::RaiseL(23001,$this->name,$aIdx); //('This marker "'.($this->name).'" does not exist in color: '.$aIdx);
\r
32 $idx = $this->index[$aIdx];
\r
34 elseif( !is_integer($aIdx) ||
\r
35 (is_integer($aIdx) && $aIdx > $this->maxidx ) ) {
\r
36 JpGraphError::RaiseL(23002,$this->name);
\r
37 //('Mark color index too large for marker "'.($this->name).'"');
\r
41 return Image::CreateFromString(base64_decode($this->{$n}[$idx][1]));
\r
43 function GetAnchor() {
\r
44 return array($this->anchor_x,$this->anchor_y);
\r
49 // Keep a global flag cache to reduce memory usage
\r
56 // Only supposed to b called as statics
\r
58 function GetFlagImgByName($aSize,$aName) {
\r
59 global $_gFlagCache;
\r
60 require_once('jpgraph_flags.php');
\r
61 if( $_gFlagCache[$aSize] === null ) {
\r
62 $_gFlagCache[$aSize] = new FlagImages($aSize);
\r
64 $f =& $_gFlagCache[$aSize];
\r
65 $idx = $f->GetIdxByName($aName,$aFullName);
\r
66 return $f->GetImgByIdx($idx);
\r
70 //===================================================
\r
72 // Description: Handles the plot marks in graphs
\r
73 //===================================================
\r
75 var $title, $show=true;
\r
76 var $type,$weight=1;
\r
77 var $color="black", $width=4, $fill_color="blue";
\r
78 var $yvalue,$xvalue='',$csimtarget,$csimalt,$csimareas;
\r
79 var $iFormatCallback="";
\r
80 var $iFormatCallback2="";
\r
81 var $markimg='',$iScale=1.0;
\r
82 var $oldfilename='',$iFileName='';
\r
83 var $imgdata_balls = null;
\r
84 var $imgdata_diamonds = null;
\r
85 var $imgdata_squares = null;
\r
86 var $imgdata_bevels = null;
\r
87 var $imgdata_stars = null;
\r
88 var $imgdata_pushpins = null;
\r
92 function __construct() {
\r
93 $this->title = new Text();
\r
94 $this->title->Hide();
\r
95 $this->csimareas = '';
\r
96 $this->csimalt = '';
\r
101 function SetType($aType,$aFileName='',$aScale=1.0) {
\r
102 $this->type = $aType;
\r
103 if( $aType == MARK_IMG && $aFileName=='' ) {
\r
104 JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.');
\r
106 $this->iFileName = $aFileName;
\r
107 $this->iScale = $aScale;
\r
110 function SetCallback($aFunc) {
\r
111 $this->iFormatCallback = $aFunc;
\r
114 function SetCallbackYX($aFunc) {
\r
115 $this->iFormatCallback2 = $aFunc;
\r
118 function GetType() {
\r
119 return $this->type;
\r
122 function SetColor($aColor) {
\r
123 $this->color=$aColor;
\r
126 function SetFillColor($aFillColor) {
\r
127 $this->fill_color = $aFillColor;
\r
130 function SetWeight($aWeight) {
\r
131 $this->weight = $aWeight;
\r
134 // Synonym for SetWidth()
\r
135 function SetSize($aWidth) {
\r
136 $this->width=$aWidth;
\r
139 function SetWidth($aWidth) {
\r
140 $this->width=$aWidth;
\r
143 function SetDefaultWidth() {
\r
144 switch( $this->type ) {
\r
146 case MARK_FILLEDCIRCLE:
\r
154 function GetWidth() {
\r
155 return $this->width;
\r
158 function Hide($aHide=true) {
\r
159 $this->show = !$aHide;
\r
162 function Show($aShow=true) {
\r
163 $this->show = $aShow;
\r
166 function SetCSIMAltVal($aY,$aX='') {
\r
167 $this->yvalue=$aY;
\r
168 $this->xvalue=$aX;
\r
171 function SetCSIMTarget($aTarget) {
\r
172 $this->csimtarget=$aTarget;
\r
175 function SetCSIMAlt($aAlt) {
\r
176 $this->csimalt=$aAlt;
\r
179 function GetCSIMAreas(){
\r
180 return $this->csimareas;
\r
183 function AddCSIMPoly($aPts) {
\r
184 $coords = round($aPts[0]).", ".round($aPts[1]);
\r
185 $n = count($aPts)/2;
\r
186 for( $i=1; $i < $n; ++$i){
\r
187 $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]);
\r
189 $this->csimareas="";
\r
190 if( !empty($this->csimtarget) ) {
\r
191 $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtarget."\"";
\r
192 if( !empty($this->csimalt) ) {
\r
193 $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
\r
194 $this->csimareas .= " title=\"$tmp\"";
\r
196 $this->csimareas .= " alt=\"$tmp\" />\n";
\r
200 function AddCSIMCircle($x,$y,$r) {
\r
201 $x = round($x); $y=round($y); $r=round($r);
\r
202 $this->csimareas="";
\r
203 if( !empty($this->csimtarget) ) {
\r
204 $this->csimareas .= "<area shape=\"circle\" coords=\"$x,$y,$r\" href=\"".$this->csimtarget."\"";
\r
205 if( !empty($this->csimalt) ) {
\r
206 $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
\r
207 $this->csimareas .= " title=\"$tmp\"";
\r
209 $this->csimareas .= " alt=\"$tmp\" />\n";
\r
213 function Stroke(&$img,$x,$y) {
\r
214 if( !$this->show ) return;
\r
216 if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) {
\r
218 if( $this->iFormatCallback != '' ) {
\r
219 $f = $this->iFormatCallback;
\r
220 list($width,$color,$fcolor) = call_user_func($f,$this->yvalue);
\r
221 $filename = $this->iFileName;
\r
222 $imgscale = $this->iScale;
\r
225 $f = $this->iFormatCallback2;
\r
226 list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue);
\r
227 if( $filename=="" ) $filename = $this->iFileName;
\r
228 if( $imgscale=="" ) $imgscale = $this->iScale;
\r
231 if( $width=="" ) $width = $this->width;
\r
232 if( $color=="" ) $color = $this->color;
\r
233 if( $fcolor=="" ) $fcolor = $this->fill_color;
\r
237 $fcolor = $this->fill_color;
\r
238 $color = $this->color;
\r
239 $width = $this->width;
\r
240 $filename = $this->iFileName;
\r
241 $imgscale = $this->iScale;
\r
244 if( $this->type == MARK_IMG ||
\r
245 ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) ||
\r
246 $this->type >= MARK_IMG_PUSHPIN ) {
\r
248 // Note: For the builtin images we use the "filename" parameter
\r
249 // to denote the color
\r
252 switch( $this->type ) {
\r
257 $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename);
\r
261 // Load an image and use that as a marker
\r
262 // Small optimization, if we have already read an image don't
\r
263 // waste time reading it again.
\r
264 if( $this->markimg == '' || !($this->oldfilename === $filename) ) {
\r
265 $this->markimg = Graph::LoadBkgImage('',$filename);
\r
266 $this->oldfilename = $filename ;
\r
270 case MARK_IMG_PUSHPIN:
\r
271 case MARK_IMG_SPUSHPIN:
\r
272 case MARK_IMG_LPUSHPIN:
\r
273 if( $this->imgdata_pushpins == null ) {
\r
274 require_once 'imgdata_pushpins.inc';
\r
275 $this->imgdata_pushpins = new ImgData_PushPins();
\r
277 $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename);
\r
278 list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor();
\r
281 case MARK_IMG_SQUARE:
\r
282 if( $this->imgdata_squares == null ) {
\r
283 require_once 'imgdata_squares.inc';
\r
284 $this->imgdata_squares = new ImgData_Squares();
\r
286 $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename);
\r
287 list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor();
\r
290 case MARK_IMG_STAR:
\r
291 if( $this->imgdata_stars == null ) {
\r
292 require_once 'imgdata_stars.inc';
\r
293 $this->imgdata_stars = new ImgData_Stars();
\r
295 $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename);
\r
296 list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor();
\r
299 case MARK_IMG_BEVEL:
\r
300 if( $this->imgdata_bevels == null ) {
\r
301 require_once 'imgdata_bevels.inc';
\r
302 $this->imgdata_bevels = new ImgData_Bevels();
\r
304 $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename);
\r
305 list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor();
\r
308 case MARK_IMG_DIAMOND:
\r
309 if( $this->imgdata_diamonds == null ) {
\r
310 require_once 'imgdata_diamonds.inc';
\r
311 $this->imgdata_diamonds = new ImgData_Diamonds();
\r
313 $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename);
\r
314 list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor();
\r
317 case MARK_IMG_BALL:
\r
318 case MARK_IMG_SBALL:
\r
319 case MARK_IMG_MBALL:
\r
320 case MARK_IMG_LBALL:
\r
321 if( $this->imgdata_balls == null ) {
\r
322 require_once 'imgdata_balls.inc';
\r
323 $this->imgdata_balls = new ImgData_Balls();
\r
325 $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename);
\r
326 list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor();
\r
330 $w = $img->GetWidth($this->markimg);
\r
331 $h = $img->GetHeight($this->markimg);
\r
333 $dw = round($imgscale * $w );
\r
334 $dh = round($imgscale * $h );
\r
336 // Do potential rotation
\r
337 list($x,$y) = $img->Rotate($x,$y);
\r
339 $dx = round($x-$dw*$anchor_x);
\r
340 $dy = round($y-$dh*$anchor_y);
\r
342 $this->width = max($dx,$dy);
\r
344 $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h);
\r
345 if( !empty($this->csimtarget) ) {
\r
346 $this->csimareas = "<area shape=\"rect\" coords=\"".
\r
347 $dx.','.$dy.','.round($dx+$dw).','.round($dy+$dh).'" '.
\r
348 "href=\"".$this->csimtarget."\"";
\r
349 if( !empty($this->csimalt) ) {
\r
350 $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
\r
351 $this->csimareas .= " title=\"$tmp\"";
\r
353 $this->csimareas .= " alt=\"$tmp\" />\n";
\r
357 $this->title->Align("center","top");
\r
358 $this->title->Stroke($img,$x,$y+round($dh/2));
\r
362 $weight = $this->weight;
\r
363 $dx=round($width/2,0);
\r
364 $dy=round($width/2,0);
\r
367 switch( $this->type ) {
\r
369 $c[]=$x-$dx;$c[]=$y-$dy;
\r
370 $c[]=$x+$dx;$c[]=$y-$dy;
\r
371 $c[]=$x+$dx;$c[]=$y+$dy;
\r
372 $c[]=$x-$dx;$c[]=$y+$dy;
\r
373 $c[]=$x-$dx;$c[]=$y-$dy;
\r
376 case MARK_UTRIANGLE:
\r
378 $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
\r
379 $c[]=$x;$c[]=$y-0.87*$dy;
\r
380 $c[]=$x+$dx;$c[]=$y+0.87*$dy;
\r
381 $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
\r
384 case MARK_DTRIANGLE:
\r
386 $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
\r
387 $c[]=$x-$dx;$c[]=$y-0.87*$dy;
\r
388 $c[]=$x+$dx;$c[]=$y-0.87*$dy;
\r
389 $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
\r
393 $c[]=$x;$c[]=$y+$dy;
\r
394 $c[]=$x-$dx;$c[]=$y;
\r
395 $c[]=$x;$c[]=$y-$dy;
\r
396 $c[]=$x+$dx;$c[]=$y;
\r
397 $c[]=$x;$c[]=$y+$dy;
\r
400 case MARK_LEFTTRIANGLE:
\r
402 $c[]=$x;$c[]=$y+2*$dy;
\r
403 $c[]=$x+$dx*2;$c[]=$y;
\r
407 case MARK_RIGHTTRIANGLE:
\r
408 $c[]=$x-$dx*2;$c[]=$y;
\r
409 $c[]=$x;$c[]=$y+2*$dy;
\r
411 $c[]=$x-$dx*2;$c[]=$y;
\r
416 $c[]=$x+$dx/2; $c[]=$y-$dy;
\r
417 $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy;
\r
418 $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy;
\r
419 $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy;
\r
420 $img->SetLineWeight($weight);
\r
421 $img->SetColor($color);
\r
423 $img->SetLineWeight(1);
\r
424 $this->AddCSIMPoly($c);
\r
429 $this->AddCSIMPoly($c);
\r
430 $img->SetLineWeight($weight);
\r
431 $img->SetColor($fcolor);
\r
432 $img->FilledPolygon($c);
\r
433 $img->SetColor($color);
\r
435 $img->SetLineWeight(1);
\r
437 elseif( $this->type==MARK_CIRCLE ) {
\r
438 $img->SetColor($color);
\r
439 $img->Circle($x,$y,$width);
\r
440 $this->AddCSIMCircle($x,$y,$width);
\r
442 elseif( $this->type==MARK_FILLEDCIRCLE ) {
\r
443 $img->SetColor($fcolor);
\r
444 $img->FilledCircle($x,$y,$width);
\r
445 $img->SetColor($color);
\r
446 $img->Circle($x,$y,$width);
\r
447 $this->AddCSIMCircle($x,$y,$width);
\r
449 elseif( $this->type==MARK_CROSS ) {
\r
450 // Oversize by a pixel to match the X
\r
451 $img->SetColor($color);
\r
452 $img->SetLineWeight($weight);
\r
453 $img->Line($x,$y+$dy+1,$x,$y-$dy-1);
\r
454 $img->Line($x-$dx-1,$y,$x+$dx+1,$y);
\r
455 $this->AddCSIMCircle($x,$y,$dx);
\r
457 elseif( $this->type==MARK_X ) {
\r
458 $img->SetColor($color);
\r
459 $img->SetLineWeight($weight);
\r
460 $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);
\r
461 $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);
\r
462 $this->AddCSIMCircle($x,$y,$dx+$dy);
\r
464 elseif( $this->type==MARK_STAR ) {
\r
465 $img->SetColor($color);
\r
466 $img->SetLineWeight($weight);
\r
467 $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);
\r
468 $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);
\r
469 // Oversize by a pixel to match the X
\r
470 $img->Line($x,$y+$dy+1,$x,$y-$dy-1);
\r
471 $img->Line($x-$dx-1,$y,$x+$dx+1,$y);
\r
472 $this->AddCSIMCircle($x,$y,$dx+$dy);
\r
476 $this->title->Align("center","center");
\r
477 $this->title->Stroke($img,$x,$y);
\r