2 //=======================================================================
3 // File: JPGRAPH_PLOTMARK.PHP
4 // Description: Class file. Handles plotmarks
6 // Author: Johan Persson (johanp@aditus.nu)
7 // Ver: $Id: jpgraph_plotmark.inc,v 1.9.2.4 2003/08/16 00:31:06 aditus Exp $
9 // License: This code is released under QPL 1.0
10 // Copyright (C) 2003 Johan Persson
11 //========================================================================
14 //========================================================================
16 // Description: Base class for all image data classes that contains the
18 //========================================================================
20 var $name = ''; // Each subclass gives a name
21 var $an = array(); // Data array names
22 var $colors = array(); // Available colors
23 var $index = array(); // Index for colors
24 var $maxidx = 0 ; // Max color index
25 var $anchor_x=0.5, $anchor_y=0.5 ; // Where is the center of the image
26 // Create a GD image from the data and return a GD handle
27 function GetImg($aMark,$aIdx) {
28 $n = $this->an[$aMark];
29 if( is_string($aIdx) ) {
30 if( !in_array($aIdx,$this->colors) ) {
31 JpGraphError::Raise('This marker "'.($this->name).'" does not exist in color: '.$aIdx);
34 $idx = $this->index[$aIdx];
36 elseif( !is_integer($aIdx) ||
37 (is_integer($aIdx) && $aIdx > $this->maxidx ) ) {
38 JpGraphError::Raise('Mark color index too large for marker "'.($this->name).'"');
42 return Image::CreateFromString(base64_decode($this->{$n}[$idx][1]));
44 function GetAnchor() {
45 return array($this->anchor_x,$this->anchor_y);
50 // Keep a global flag cache to reduce memory usage
57 // Only supposed to b called as statics
59 function GetFlagImgByName($aSize,$aName) {
61 require_once('jpgraph_flags.php');
62 if( $_gFlagCache[$aSize] === null ) {
63 $_gFlagCache[$aSize] =& new FlagImages($aSize);
65 $f =& $_gFlagCache[$aSize];
66 $idx = $f->GetIdxByName($aName,$aFullName);
67 return $f->GetImgByIdx($idx);
71 //===================================================
73 // Description: Handles the plot marks in graphs
74 //===================================================
76 var $title, $show=true;
78 var $color="black", $width=4, $fill_color="blue";
79 var $yvalue,$xvalue='',$csimtarget,$csimalt,$csimareas;
80 var $iFormatCallback="";
81 var $iFormatCallback2="";
82 var $markimg='',$iScale=1.0;
83 var $oldfilename='',$iFileName='';
84 var $imgdata_balls = null;
85 var $imgdata_diamonds = null;
86 var $imgdata_squares = null;
87 var $imgdata_bevels = null;
88 var $imgdata_stars = null;
89 var $imgdata_pushpins = null;
94 $this->title = new Text();
96 $this->csimareas = '';
102 function SetType($aType,$aFileName='',$aScale=1.0) {
103 $this->type = $aType;
104 if( $aType == MARK_IMG && $aFileName=='' ) {
105 JpGraphError::Raise('A filename must be specified if you set the mark type to MARK_IMG.');
107 $this->iFileName = $aFileName;
108 $this->iScale = $aScale;
111 function SetCallback($aFunc) {
112 $this->iFormatCallback = $aFunc;
115 function SetCallbackYX($aFunc) {
116 $this->iFormatCallback2 = $aFunc;
123 function SetColor($aColor) {
124 $this->color=$aColor;
127 function SetFillColor($aFillColor) {
128 $this->fill_color = $aFillColor;
131 function SetWeight($aWeight) {
132 $this->weight = $aWeight;
135 // Synonym for SetWidth()
136 function SetSize($aWidth) {
137 $this->width=$aWidth;
140 function SetWidth($aWidth) {
141 $this->width=$aWidth;
144 function SetDefaultWidth() {
145 switch( $this->type ) {
147 case MARK_FILLEDCIRCLE:
155 function GetWidth() {
159 function Hide($aHide=true) {
160 $this->show = !$aHide;
163 function Show($aShow=true) {
164 $this->show = $aShow;
167 function SetCSIMAltVal($aY,$aX='') {
172 function SetCSIMTarget($aTarget) {
173 $this->csimtarget=$aTarget;
176 function SetCSIMAlt($aAlt) {
177 $this->csimalt=$aAlt;
180 function GetCSIMAreas(){
181 return $this->csimareas;
184 function AddCSIMPoly($aPts) {
185 $coords = round($aPts[0]).", ".round($aPts[1]);
187 for( $i=1; $i < $n; ++$i){
188 $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]);
191 if( !empty($this->csimtarget) ) {
192 $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtarget."\"";
193 if( !empty($this->csimalt) ) {
194 $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
195 $this->csimareas .= " alt=\"$tmp\" title=\"$tmp\"";
197 $this->csimareas .= ">\n";
201 function AddCSIMCircle($x,$y,$r) {
202 $x = round($x); $y=round($y); $r=round($r);
204 if( !empty($this->csimtarget) ) {
205 $this->csimareas .= "<area shape=\"circle\" coords=\"$x,$y,$r\" href=\"".$this->csimtarget."\"";
206 if( !empty($this->csimalt) ) {
207 $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
208 $this->csimareas .= " alt=\"$tmp\" title=\"$tmp\"";
210 $this->csimareas .= ">\n";
214 function Stroke($img,$x,$y) {
215 if( !$this->show ) return;
217 if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) {
219 if( $this->iFormatCallback != '' ) {
220 $f = $this->iFormatCallback;
221 list($width,$color,$fcolor) = call_user_func($f,$this->yvalue);
222 $filename = $this->iFileName;
223 $imgscale = $this->iScale;
226 $f = $this->iFormatCallback2;
227 list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue);
228 if( $filename=="" ) $filename = $this->iFileName;
229 if( $imgscale=="" ) $imgscale = $this->iScale;
232 if( $width=="" ) $width = $this->width;
233 if( $color=="" ) $color = $this->color;
234 if( $fcolor=="" ) $fcolor = $this->fill_color;
238 $fcolor = $this->fill_color;
239 $color = $this->color;
240 $width = $this->width;
241 $filename = $this->iFileName;
242 $imgscale = $this->iScale;
245 if( $this->type == MARK_IMG ||
246 ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) ||
247 $this->type >= MARK_IMG_PUSHPIN ) {
249 // Note: For the builtin images we use the "filename" parameter
250 // to denote the color
253 switch( $this->type ) {
258 $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename);
262 // Load an image and use that as a marker
263 // Small optimization, if we have already read an image don't
264 // waste time reading it again.
265 if( $this->markimg == '' || !($this->oldfilename === $filename) ) {
266 $this->markimg = Graph::LoadBkgImage('',$filename);
267 $this->oldfilename = $filename ;
271 case MARK_IMG_PUSHPIN:
272 case MARK_IMG_SPUSHPIN:
273 case MARK_IMG_LPUSHPIN:
274 if( $this->imgdata_pushpins == null ) {
275 require_once 'imgdata_pushpins.inc';
276 $this->imgdata_pushpins = new ImgData_PushPins();
278 $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename);
279 list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor();
282 case MARK_IMG_SQUARE:
283 if( $this->imgdata_squares == null ) {
284 require_once 'imgdata_squares.inc';
285 $this->imgdata_squares = new ImgData_Squares();
287 $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename);
288 list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor();
292 if( $this->imgdata_stars == null ) {
293 require_once 'imgdata_stars.inc';
294 $this->imgdata_stars = new ImgData_Stars();
296 $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename);
297 list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor();
301 if( $this->imgdata_bevels == null ) {
302 require_once 'imgdata_bevels.inc';
303 $this->imgdata_bevels = new ImgData_Bevels();
305 $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename);
306 list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor();
309 case MARK_IMG_DIAMOND:
310 if( $this->imgdata_diamonds == null ) {
311 require_once 'imgdata_diamonds.inc';
312 $this->imgdata_diamonds = new ImgData_Diamonds();
314 $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename);
315 list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor();
322 if( $this->imgdata_balls == null ) {
323 require_once 'imgdata_balls.inc';
324 $this->imgdata_balls = new ImgData_Balls();
326 $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename);
327 list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor();
331 $w = $img->GetWidth($this->markimg);
332 $h = $img->GetHeight($this->markimg);
334 $dw = round($imgscale * $w );
335 $dh = round($imgscale * $h );
337 $dx = round($x-$dw*$anchor_x);
338 $dy = round($y-$dh*$anchor_y);
340 $this->width = max($dx,$dy);
342 $cp = $GLOBALS['copyfunc'] ;
343 $cp($img->img,$this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h);
344 if( !empty($this->csimtarget) ) {
345 $this->csimareas = "<area shape=\"rect\" coords=\"".
346 $dx.','.$dy.','.round($dx+$dw).','.round($dy+$dh).'" '.
347 "href=\"".$this->csimtarget."\"";
348 if( !empty($this->csimalt) ) {
349 $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
350 $this->csimareas .= " alt=\"$tmp\" title=\"$tmp\"";
352 $this->csimareas .= ">\n";
356 $this->title->Align("center","top");
357 $this->title->Stroke($img,$x,$y+round($dh/2));
361 $weight = $this->weight;
362 $dx=round($width/2,0);
363 $dy=round($width/2,0);
366 switch( $this->type ) {
368 $c[]=$x-$dx;$c[]=$y-$dy;
369 $c[]=$x+$dx;$c[]=$y-$dy;
370 $c[]=$x+$dx;$c[]=$y+$dy;
371 $c[]=$x-$dx;$c[]=$y+$dy;
372 $c[]=$x-$dx;$c[]=$y-$dy;
377 $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
378 $c[]=$x;$c[]=$y-0.87*$dy;
379 $c[]=$x+$dx;$c[]=$y+0.87*$dy;
380 $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
385 $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
386 $c[]=$x-$dx;$c[]=$y-0.87*$dy;
387 $c[]=$x+$dx;$c[]=$y-0.87*$dy;
388 $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
399 case MARK_LEFTTRIANGLE:
401 $c[]=$x;$c[]=$y+2*$dy;
402 $c[]=$x+$dx*2;$c[]=$y;
406 case MARK_RIGHTTRIANGLE:
407 $c[]=$x-$dx*2;$c[]=$y;
408 $c[]=$x;$c[]=$y+2*$dy;
410 $c[]=$x-$dx*2;$c[]=$y;
415 $c[]=$x+$dx/2; $c[]=$y-$dy;
416 $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy;
417 $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy;
418 $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy;
419 $img->SetLineWeight($weight);
420 $img->SetColor($color);
422 $img->SetLineWeight(1);
423 $this->AddCSIMPoly($c);
428 $this->AddCSIMPoly($c);
429 $img->SetLineWeight($weight);
430 $img->SetColor($fcolor);
431 $img->FilledPolygon($c);
432 $img->SetColor($color);
434 $img->SetLineWeight(1);
436 elseif( $this->type==MARK_CIRCLE ) {
437 $img->SetColor($color);
438 $img->Circle($x,$y,$width);
439 $this->AddCSIMCircle($x,$y,$width);
441 elseif( $this->type==MARK_FILLEDCIRCLE ) {
442 $img->SetColor($fcolor);
443 $img->FilledCircle($x,$y,$width);
444 $img->SetColor($color);
445 $img->Circle($x,$y,$width);
446 $this->AddCSIMCircle($x,$y,$width);
448 elseif( $this->type==MARK_CROSS ) {
449 // Oversize by a pixel to match the X
450 $img->SetColor($color);
451 $img->SetLineWeight($weight);
452 $img->Line($x,$y+$dy+1,$x,$y-$dy-1);
453 $img->Line($x-$dx-1,$y,$x+$dx+1,$y);
454 $this->AddCSIMCircle($x,$y,$dx);
456 elseif( $this->type==MARK_X ) {
457 $img->SetColor($color);
458 $img->SetLineWeight($weight);
459 $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);
460 $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);
461 $this->AddCSIMCircle($x,$y,$dx+$dy);
463 elseif( $this->type==MARK_STAR ) {
464 $img->SetColor($color);
465 $img->SetLineWeight($weight);
466 $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);
467 $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);
468 // Oversize by a pixel to match the X
469 $img->Line($x,$y+$dy+1,$x,$y-$dy-1);
470 $img->Line($x-$dx-1,$y,$x+$dx+1,$y);
471 $this->AddCSIMCircle($x,$y,$dx+$dy);
475 $this->title->Align("center","center");
476 $this->title->Stroke($img,$x,$y);