source: trunk/xgraph/jpgraph/jpgraph_plotmark.inc.php @ 42

Last change on this file since 42 was 42, checked in by marrucho, 10 years ago
File size: 17.7 KB
Line 
1<?php
2//=======================================================================
3// File:        JPGRAPH_PLOTMARK.PHP
4// Description: Class file. Handles plotmarks
5// Created:     2003-03-21
6// Ver:         $Id: jpgraph_plotmark.inc.php 1106 2009-02-22 20:16:35Z ljp $
7//
8// Copyright (c) Asial Corporation. All rights reserved.
9//========================================================================
10
11
12//===================================================
13// CLASS PlotMark
14// Description: Handles the plot marks in graphs
15//===================================================
16
17class PlotMark {
18    public $title, $show=true;
19    public $type,$weight=1;
20    public $iFormatCallback="", $iFormatCallback2="";
21    public $fill_color="blue";
22    public $color="black", $width=4;
23    private $yvalue,$xvalue='',$csimtarget,$csimwintarget='',$csimalt,$csimareas;
24    private $markimg='',$iScale=1.0;
25    private $oldfilename='',$iFileName='';
26    private $imgdata_balls = null;
27    private $imgdata_diamonds = null;
28    private $imgdata_squares = null;
29    private $imgdata_bevels = null;
30    private $imgdata_stars = null;
31    private $imgdata_pushpins = null;
32
33    //--------------
34    // CONSTRUCTOR
35    function __construct() {
36        $this->title = new Text();
37        $this->title->Hide();
38        $this->csimareas = '';
39        $this->type=-1;
40    }
41    //---------------
42    // PUBLIC METHODS
43    function SetType($aType,$aFileName='',$aScale=1.0) {
44        $this->type = $aType;
45        if( $aType == MARK_IMG && $aFileName=='' ) {
46            JpGraphError::RaiseL(23003);//('A filename must be specified if you set the mark type to MARK_IMG.');
47        }
48        $this->iFileName = $aFileName;
49        $this->iScale = $aScale;
50    }
51
52    function SetCallback($aFunc) {
53        $this->iFormatCallback = $aFunc;
54    }
55
56    function SetCallbackYX($aFunc) {
57        $this->iFormatCallback2 = $aFunc;
58    }
59
60    function GetType() {
61        return $this->type;
62    }
63
64    function SetColor($aColor) {
65        $this->color=$aColor;
66    }
67
68    function SetFillColor($aFillColor) {
69        $this->fill_color = $aFillColor;
70    }
71
72    function SetWeight($aWeight) {
73        $this->weight = $aWeight;
74    }
75
76    // Synonym for SetWidth()
77    function SetSize($aWidth) {
78        $this->width=$aWidth;
79    }
80
81    function SetWidth($aWidth) {
82        $this->width=$aWidth;
83    }
84
85    function SetDefaultWidth() {
86        switch( $this->type ) {
87            case MARK_CIRCLE:
88            case MARK_FILLEDCIRCLE:
89                $this->width=4;
90                break;
91            default:
92                $this->width=7;
93        }
94    }
95
96    function GetWidth() {
97        return $this->width;
98    }
99
100    function Hide($aHide=true) {
101        $this->show = !$aHide;
102    }
103
104    function Show($aShow=true) {
105        $this->show = $aShow;
106    }
107
108    function SetCSIMAltVal($aY,$aX='') {
109        $this->yvalue=$aY;
110        $this->xvalue=$aX;
111    }
112
113    function SetCSIMTarget($aTarget,$aWinTarget='') {
114        $this->csimtarget=$aTarget;
115        $this->csimwintarget=$aWinTarget;
116    }
117
118    function SetCSIMAlt($aAlt) {
119        $this->csimalt=$aAlt;
120    }
121
122    function GetCSIMAreas(){
123        return $this->csimareas;
124    }
125
126    function AddCSIMPoly($aPts) {
127        $coords = round($aPts[0]).", ".round($aPts[1]);
128        $n = count($aPts)/2;
129        for( $i=1; $i < $n; ++$i){
130            $coords .= ", ".round($aPts[2*$i]).", ".round($aPts[2*$i+1]);
131        }
132        $this->csimareas="";
133        if( !empty($this->csimtarget) ) {
134            $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".htmlentities($this->csimtarget)."\"";
135
136            if( !empty($this->csimwintarget) ) {
137                $this->csimareas .= " target=\"".$this->csimwintarget."\" ";
138            }
139
140            if( !empty($this->csimalt) ) {
141                $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
142                $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\"";
143            }
144            $this->csimareas .= " />\n";
145        }
146    }
147
148    function AddCSIMCircle($x,$y,$r) {
149        $x = round($x); $y=round($y); $r=round($r);
150        $this->csimareas="";
151        if( !empty($this->csimtarget) ) {
152            $this->csimareas .= "<area shape=\"circle\" coords=\"$x,$y,$r\" href=\"".htmlentities($this->csimtarget)."\"";
153
154            if( !empty($this->csimwintarget) ) {
155                $this->csimareas .= " target=\"".$this->csimwintarget."\" ";
156            }
157
158            if( !empty($this->csimalt) ) {
159                $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
160                $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
161            }
162            $this->csimareas .= " />\n";
163        }
164    }
165     
166    function Stroke($img,$x,$y) {
167        if( !$this->show ) return;
168
169        if( $this->iFormatCallback != '' || $this->iFormatCallback2 != '' ) {
170
171            if( $this->iFormatCallback != '' ) {
172                $f = $this->iFormatCallback;
173                list($width,$color,$fcolor) = call_user_func($f,$this->yvalue);
174                $filename = $this->iFileName;
175                $imgscale = $this->iScale;
176            }
177            else {
178                $f = $this->iFormatCallback2;
179                list($width,$color,$fcolor,$filename,$imgscale) = call_user_func($f,$this->yvalue,$this->xvalue);
180                if( $filename=="" ) $filename = $this->iFileName;
181                if( $imgscale=="" ) $imgscale = $this->iScale;
182            }
183
184            if( $width=="" ) $width = $this->width;
185            if( $color=="" ) $color = $this->color;
186            if( $fcolor=="" ) $fcolor = $this->fill_color;
187
188        }
189        else {
190            $fcolor = $this->fill_color;
191            $color = $this->color;
192            $width = $this->width;
193            $filename = $this->iFileName;
194            $imgscale = $this->iScale;
195        }
196
197        if( $this->type == MARK_IMG ||
198        ($this->type >= MARK_FLAG1 && $this->type <= MARK_FLAG4 ) ||
199        $this->type >= MARK_IMG_PUSHPIN ) {
200
201            // Note: For the builtin images we use the "filename" parameter
202            // to denote the color
203            $anchor_x = 0.5;
204            $anchor_y = 0.5;
205            switch( $this->type ) {
206                case MARK_FLAG1:
207                case MARK_FLAG2:
208                case MARK_FLAG3:
209                case MARK_FLAG4:
210                    $this->markimg = FlagCache::GetFlagImgByName($this->type-MARK_FLAG1+1,$filename);
211                    break;
212
213                case MARK_IMG :
214                    // Load an image and use that as a marker
215                    // Small optimization, if we have already read an image don't
216                    // waste time reading it again.
217                    if( $this->markimg == '' || !($this->oldfilename === $filename) ) {
218                        $this->markimg = Graph::LoadBkgImage('',$filename);
219                        $this->oldfilename = $filename ;
220                    }
221                    break;
222
223                case MARK_IMG_PUSHPIN:
224                case MARK_IMG_SPUSHPIN:
225                case MARK_IMG_LPUSHPIN:
226                    if( $this->imgdata_pushpins == null ) {
227                        require_once 'imgdata_pushpins.inc.php';
228                        $this->imgdata_pushpins = new ImgData_PushPins();
229                    }
230                    $this->markimg = $this->imgdata_pushpins->GetImg($this->type,$filename);
231                    list($anchor_x,$anchor_y) = $this->imgdata_pushpins->GetAnchor();
232                    break;
233
234                case MARK_IMG_SQUARE:
235                    if( $this->imgdata_squares == null ) {
236                        require_once 'imgdata_squares.inc.php';
237                        $this->imgdata_squares = new ImgData_Squares();
238                    }
239                    $this->markimg = $this->imgdata_squares->GetImg($this->type,$filename);
240                    list($anchor_x,$anchor_y) = $this->imgdata_squares->GetAnchor();
241                    break;
242
243                case MARK_IMG_STAR:
244                    if( $this->imgdata_stars == null ) {
245                        require_once 'imgdata_stars.inc.php';
246                        $this->imgdata_stars = new ImgData_Stars();
247                    }
248                    $this->markimg = $this->imgdata_stars->GetImg($this->type,$filename);
249                    list($anchor_x,$anchor_y) = $this->imgdata_stars->GetAnchor();
250                    break;
251
252                case MARK_IMG_BEVEL:
253                    if( $this->imgdata_bevels == null ) {
254                        require_once 'imgdata_bevels.inc.php';
255                        $this->imgdata_bevels = new ImgData_Bevels();
256                    }
257                    $this->markimg = $this->imgdata_bevels->GetImg($this->type,$filename);
258                    list($anchor_x,$anchor_y) = $this->imgdata_bevels->GetAnchor();
259                    break;
260
261                case MARK_IMG_DIAMOND:
262                    if( $this->imgdata_diamonds == null ) {
263                        require_once 'imgdata_diamonds.inc.php';
264                        $this->imgdata_diamonds = new ImgData_Diamonds();
265                    }
266                    $this->markimg = $this->imgdata_diamonds->GetImg($this->type,$filename);
267                    list($anchor_x,$anchor_y) = $this->imgdata_diamonds->GetAnchor();
268                    break;
269
270                case MARK_IMG_BALL:
271                case MARK_IMG_SBALL:
272                case MARK_IMG_MBALL:
273                case MARK_IMG_LBALL:
274                    if( $this->imgdata_balls == null ) {
275                        require_once 'imgdata_balls.inc.php';
276                        $this->imgdata_balls = new ImgData_Balls();
277                    }
278                    $this->markimg = $this->imgdata_balls->GetImg($this->type,$filename);
279                    list($anchor_x,$anchor_y) = $this->imgdata_balls->GetAnchor();
280                    break;
281            }
282
283            $w = $img->GetWidth($this->markimg);
284            $h = $img->GetHeight($this->markimg);
285             
286            $dw = round($imgscale * $w );
287            $dh = round($imgscale * $h );
288
289            // Do potential rotation
290            list($x,$y) = $img->Rotate($x,$y);
291
292            $dx = round($x-$dw*$anchor_x);
293            $dy = round($y-$dh*$anchor_y);
294             
295            $this->width = max($dx,$dy);
296             
297            $img->Copy($this->markimg,$dx,$dy,0,0,$dw,$dh,$w,$h);
298            if( !empty($this->csimtarget) ) {
299                $this->csimareas = "<area shape=\"rect\" coords=\"".
300                $dx.','.$dy.','.round($dx+$dw).','.round($dy+$dh).'" '.
301      "href=\"".htmlentities($this->csimtarget)."\"";
302
303                if( !empty($this->csimwintarget) ) {
304                    $this->csimareas .= " target=\"".$this->csimwintarget."\" ";
305                }
306
307                if( !empty($this->csimalt) ) {
308                    $tmp=sprintf($this->csimalt,$this->yvalue,$this->xvalue);
309                    $this->csimareas .= " title=\"$tmp\" alt=\"$tmp\" ";
310                }
311                $this->csimareas .= " />\n";
312            }
313             
314            // Stroke title
315            $this->title->Align("center","top");
316            $this->title->Stroke($img,$x,$y+round($dh/2));
317            return;
318        }
319
320        $weight = $this->weight;
321        $dx=round($width/2,0);
322        $dy=round($width/2,0);
323        $pts=0;
324
325        switch( $this->type ) {
326            case MARK_SQUARE:
327                $c[]=$x-$dx;$c[]=$y-$dy;
328                $c[]=$x+$dx;$c[]=$y-$dy;
329                $c[]=$x+$dx;$c[]=$y+$dy;
330                $c[]=$x-$dx;$c[]=$y+$dy;
331                $c[]=$x-$dx;$c[]=$y-$dy;
332                $pts=5;
333                break;
334            case MARK_UTRIANGLE:
335                ++$dx;++$dy;
336                $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
337                $c[]=$x;$c[]=$y-0.87*$dy;
338                $c[]=$x+$dx;$c[]=$y+0.87*$dy;
339                $c[]=$x-$dx;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
340                $pts=4;
341                break;
342            case MARK_DTRIANGLE:
343                ++$dx;++$dy;
344                $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
345                $c[]=$x-$dx;$c[]=$y-0.87*$dy;
346                $c[]=$x+$dx;$c[]=$y-0.87*$dy;
347                $c[]=$x;$c[]=$y+0.87*$dy; // tan(60)/2*$dx
348                $pts=4;
349                break;
350            case MARK_DIAMOND:
351                $c[]=$x;$c[]=$y+$dy;
352                $c[]=$x-$dx;$c[]=$y;
353                $c[]=$x;$c[]=$y-$dy;
354                $c[]=$x+$dx;$c[]=$y;
355                $c[]=$x;$c[]=$y+$dy;
356                $pts=5;
357                break;
358            case MARK_LEFTTRIANGLE:
359                $c[]=$x;$c[]=$y;
360                $c[]=$x;$c[]=$y+2*$dy;
361                $c[]=$x+$dx*2;$c[]=$y;
362                $c[]=$x;$c[]=$y;
363                $pts=4;
364                break;
365            case MARK_RIGHTTRIANGLE:
366                $c[]=$x-$dx*2;$c[]=$y;
367                $c[]=$x;$c[]=$y+2*$dy;
368                $c[]=$x;$c[]=$y;
369                $c[]=$x-$dx*2;$c[]=$y;
370                $pts=4;
371                break;
372            case MARK_FLASH:
373                $dy *= 2;
374                $c[]=$x+$dx/2; $c[]=$y-$dy;
375                $c[]=$x-$dx+$dx/2; $c[]=$y+$dy*0.7-$dy;
376                $c[]=$x+$dx/2; $c[]=$y+$dy*1.3-$dy;
377                $c[]=$x-$dx+$dx/2; $c[]=$y+2*$dy-$dy;
378                $img->SetLineWeight($weight);
379                $img->SetColor($color);
380                $img->Polygon($c);
381                $img->SetLineWeight(1);
382                $this->AddCSIMPoly($c);
383                break;
384        }
385
386        if( $pts>0 ) {
387            $this->AddCSIMPoly($c);
388            $img->SetLineWeight($weight);
389            $img->SetColor($fcolor);
390            $img->FilledPolygon($c);
391            $img->SetColor($color);
392            $img->Polygon($c);
393            $img->SetLineWeight(1);
394        }
395        elseif( $this->type==MARK_CIRCLE ) {
396            $img->SetColor($color);
397            $img->Circle($x,$y,$width);
398            $this->AddCSIMCircle($x,$y,$width);
399        }
400        elseif( $this->type==MARK_FILLEDCIRCLE ) {
401            $img->SetColor($fcolor);
402            $img->FilledCircle($x,$y,$width);
403            $img->SetColor($color);
404            $img->Circle($x,$y,$width);
405            $this->AddCSIMCircle($x,$y,$width);
406        }
407        elseif( $this->type==MARK_CROSS ) {
408            // Oversize by a pixel to match the X
409            $img->SetColor($color);
410            $img->SetLineWeight($weight);
411            $img->Line($x,$y+$dy+1,$x,$y-$dy-1);
412            $img->Line($x-$dx-1,$y,$x+$dx+1,$y);
413            $this->AddCSIMCircle($x,$y,$dx);
414        }
415        elseif( $this->type==MARK_X ) {
416            $img->SetColor($color);
417            $img->SetLineWeight($weight);
418            $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);
419            $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);
420            $this->AddCSIMCircle($x,$y,$dx+$dy);
421        }
422        elseif( $this->type==MARK_STAR ) {
423            $img->SetColor($color);
424            $img->SetLineWeight($weight);
425            $img->Line($x+$dx,$y+$dy,$x-$dx,$y-$dy);
426            $img->Line($x-$dx,$y+$dy,$x+$dx,$y-$dy);
427            // Oversize by a pixel to match the X
428            $img->Line($x,$y+$dy+1,$x,$y-$dy-1);
429            $img->Line($x-$dx-1,$y,$x+$dx+1,$y);
430            $this->AddCSIMCircle($x,$y,$dx+$dy);
431        }
432
433        // Stroke title
434        $this->title->Align("center","center");
435        $this->title->Stroke($img,$x,$y);
436    }
437} // Class
438
439
440
441//========================================================================
442// CLASS ImgData
443// Description: Base class for all image data classes that contains the
444// real image data.
445//========================================================================
446class ImgData {
447    protected $name = '';  // Each subclass gives a name
448    protected $an = array();  // Data array names
449    protected $colors = array(); // Available colors
450    protected $index  = array(); // Index for colors
451    protected $maxidx = 0 ;  // Max color index
452    protected $anchor_x=0.5, $anchor_y=0.5 ;    // Where is the center of the image
453   
454    function __construct() {
455        // Empty
456    }
457   
458    // Create a GD image from the data and return a GD handle
459    function GetImg($aMark,$aIdx) {
460        $n = $this->an[$aMark];
461        if( is_string($aIdx) ) {
462            if( !in_array($aIdx,$this->colors) ) {
463                JpGraphError::RaiseL(23001,$this->name,$aIdx);//('This marker "'.($this->name).'" does not exist in color: '.$aIdx);
464            }
465            $idx = $this->index[$aIdx];
466        }
467        elseif( !is_integer($aIdx) ||
468        (is_integer($aIdx) && $aIdx > $this->maxidx ) ) {
469            JpGraphError::RaiseL(23002,$this->name);//('Mark color index too large for marker "'.($this->name).'"');
470        }
471        else
472        $idx = $aIdx ;
473        return Image::CreateFromString(base64_decode($this->{$n}[$idx][1]));
474    }
475   
476    function GetAnchor() {
477        return array($this->anchor_x,$this->anchor_y);
478    }
479}
480
481
482// Keep a global flag cache to reduce memory usage
483$_gFlagCache=array(
4841 => null,
4852 => null,
4863 => null,
4874 => null,
488);
489// Only supposed to b called as statics
490class FlagCache {
491   
492    static function GetFlagImgByName($aSize,$aName) {
493        global $_gFlagCache;
494        require_once('jpgraph_flags.php');
495        if( $_gFlagCache[$aSize] === null ) {
496            $_gFlagCache[$aSize] = new FlagImages($aSize);
497        }
498        $f = $_gFlagCache[$aSize];
499        $idx = $f->GetIdxByName($aName,$aFullName);
500        return $f->GetImgByIdx($idx);
501    }
502}
503
504?>
Note: See TracBrowser for help on using the repository browser.