ImageOutputStrategy.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2015 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\model\output;
12 
16 
17 /**
18  * ImageOutputStrategy outputs a tree of objects into an image file. It must be configured
19  * with a map that was calculated by a LayoutVisitor.
20  *
21  * @author ingo herwig <ingo@wemove.com>
22  */
24 
25  const LINETYPE_DIRECT = 0;
26  const LINETYPE_ROUTED = 0;
27 
28  protected $_format = null;
29  protected $_file = '';
30  protected $_map = null;
31  protected $_img = null;
32  protected $_width = 0;
33  protected $_height = 0;
34  protected $_xscale = 0;
35  protected $_yscale = 0;
36  protected $_border = 0;
37  protected $_bgColor = null;
38  protected $_txtColor = null;
39  protected $_lineColor = null;
40  protected $_labelDim = null;
41  protected $_textPos = null;
42  protected $_usemap = '';
43 
44  /**
45  * Constructor.
46  * @param $format Image format name [IMG_GIF | IMG_JPG | IMG_PNG | IMG_WBMP].
47  * @param $file The output file name.
48  * @param $map The position map provided by LayoutVisitor.
49  * @param $lineType The linetype to use [LINETYPE_DIRECT|LINETYPE_ROUTED] DEFAULT LINETYPE_DIRECT.
50  * @param $scale The image scale (will be xscale) DEFAULT 100.
51  * @param $aspect The image aspect (aspect = xscale/yscale) DEFAULT 0.5.
52  * @param $border The image border [px] DEFAULT 50.
53  * @param $usemap Name of the HTML ImageMap to write to stdout ['' means no map] DEFAULT ''.
54  */
55  public function __construct($format, $file, $map, $lineType=self::LINETYPE_DIRECT,
56  $scale=100, $aspect=0.5, $border=50, $usemap='') {
57 
58  if (!(ImageTypes() & $format)) {
59  IllegalArgumentException($format." image support is disabled.");
60  }
61  if (!is_array($map)) {
62  IllegalArgumentException("Parameter map is no array.");
63  }
64  $this->_format = $format;
65  $this->_file = $file;
66  $this->_map = $map;
67  $this->_lineType = $lineType;
68  $this->_xscale = $scale;
69  $this->_yscale = $scale/$aspect;
70  $this->_border = $border;
71  $this->_usemap = $usemap;
72  // define label dimensions relative to connector position
73  $this->_labelDim['left'] = -10;
74  $this->_labelDim['top'] = -10;
75  $this->_labelDim['right'] = 80;
76  $this->_labelDim['bottom'] = 20;
77  // define text position relative to connector position
78  $this->_textPos['left'] = -5;
79  $this->_textPos['top'] = -8;
80  }
81 
82  /**
83  * @see OutputStrategy::writeHeader
84  */
85  public function writeHeader() {
86  // calculate bounding box
87  while (list ($key, $val) = each ($this->_map)) {
88  if($val->x >= $this->_width) {
89  $this->_width = $val->x;
90  }
91  if($val->y >= $this->_height) {
92  $this->_height = $val->y;
93  }
94  }
95  $this->_width = $this->_width * $this->_xscale + $this->_labelDim['right'] - $this->_labelDim['left'] + 2*$this->_border;
96  $this->_height = $this->_height * $this->_yscale + $this->_labelDim['bottom'] - $this->_labelDim['top'] + 2*$this->_border;
97  $this->_img = ImageCreate($this->_width,$this->_height);
98  $this->_bgColor = ImageColorAllocate($this->_img,255,255,255);
99  $this->_txtColor = ImageColorAllocate($this->_img,0,128,192);
100  $this->_lineColor = $this->_txtColor;
101  ImageFilledRectangle($this->_img,0,0,$this->_width,$this->_height,$this->_bgColor);
102 
103  if ($this->_usemap != '') {
104  echo "\n".'<map name="'.$this->_usemap.'">'."\n";
105  }
106  }
107 
108  /**
109  * @see OutputStrategy::writeFooter
110  */
111  public function writeFooter() {
112  ImageString($this->_img,1,$this->_width-350,$this->_height-10,'wemove digital solutions. '.date ("l dS of F Y h:i:s A"),$this->_txtColor);
113  if ($this->_format & IMG_GIF) {
114  ImageGIF($this->_img, $this->_file);
115  }
116  if ($this->_format & IMG_PNG) {
117  ImagePNG($this->_img, $this->_file);
118  }
119  if ($this->_format & IMG_JPEG) {
120  ImageJPEG($this->_img, $this->_file);
121  }
122  if ($this->_format & IMG_WBMP) {
123  ImageWBMP($this->_img, $this->_file);
124  }
125  if ($this->_usemap != '') {
126  echo "\n".'</map>'."\n";
127  }
128  }
129 
130  /**
131  * @see OutputStrategy::writeObject
132  */
133  public function writeObject(PersistentObject $obj) {
134  $oid = $obj->getOID();
135  $x = $this->_map[$oid]->x * $this->_xscale - $this->_labelDim['left'] + $this->_border;
136  $y = $this->_map[$oid]->y * $this->_yscale - $this->_labelDim['top'] + $this->_border;
137 
138  $statusStr = '';
139  if ($obj->getState() == PersistentObject::STATE_DIRTY) {
140  $statusStr = 'M';
141  }
142  if ($obj->getState() == PersistentObject::STATE_NEW) {
143  $statusStr = 'N';
144  }
145  if ($obj->getState() == PersistentObject::STATE_DELETED) {
146  $statusStr = 'D';
147  }
148 
149  // print label
150  ImageRectangle($this->_img,
151  $x + $this->_labelDim['left'],
152  $y + $this->_labelDim['top'],
153  $x + $this->_labelDim['right'],
154  $y + $this->_labelDim['bottom'],
155  $this->_txtColor);
156  // write text
157  ImageString($this->_img,1,
158  $x + $this->_textPos['left'],
159  $y + $this->_textPos['top'],
160  $obj->getType(),
162  if (strlen($oid) > 7) {
163  $idStr = "...".subStr($oid, strlen($oid)-4, 4);
164  }
165  else {
166  $idStr = $oid;
167  }
168  ImageString($this->_img,5,
169  $x + $this->_textPos['left'],
170  $y + $this->_textPos['top']+14,
171  $idStr.' '.$statusStr,
172  $this->_txtColor);
173 
174  // draw line
175  $parent = $obj->getParent();
176  if ($parent) {
177  $this->drawConnectionLine($parent->getOID(), $oid);
178  }
179  // print map
180  if ($this->_usemap != '')
181  {
182  echo '<area shape="rect" coords="'.
183  ($x + $this->_labelDim['left']).','.
184  ($y + $this->_labelDim['top']).','.
185  ($x + $this->_labelDim['right']).','.
186  ($y + $this->_labelDim['bottom'] + 8*$this->_map[$oid]->z).
187  '" onclick="javascript:if (nodeClicked) nodeClicked(\''.$obj->getOID().'\')" alt="'.$obj->getOID().'">'."\n";
188  }
189  }
190 
191  /**
192  * Draw connection line.
193  * @param $poid The parent object's object id.
194  * @param $oid The object's object id.
195  */
196  protected function drawConnectionLine($poid, $oid) {
197  list($start, $end) = $this->calculateEndPoints($poid, $oid);
198  if($this->_lineType == self::LINETYPE_DIRECT) {
199  $this->drawDirectLine($start, $end);
200  }
201  else if($this->_lineType == self::LINETYPE_ROUTED) {
202  $this->drawRoutedLine($start, $end);
203  }
204  }
205 
206  /**
207  * Draw direct line.
208  * @param $start The start point (Position).
209  * @param $end The end point (Position).
210  */
211  protected function drawDirectLine($start, $end) {
212  ImageLine($this->_img,
213  $start->x,
214  $start->y,
215  $end->x,
216  $end->y,
217  $this->_lineColor);
218  }
219 
220  /**
221  * Draw routed line.
222  * @param $start The start point (Position).
223  * @param $end The end point (Position).
224  */
225  protected function drawRoutedLine($start, $end) {
226  if ($this->_map["type"] == MAPTYPE_HORIZONTAL) {
227  ImageLine($this->_img,
228  $start->x,
229  $start->y,
230  $start->x,
231  $start->y-($start->y-$end->y)/2,
232  $this->_lineColor);
233  ImageLine($this->_img,
234  $start->x,
235  $start->y-($start->y-$end->y)/2,
236  $end->x,
237  $start->y-($start->y-$end->y)/2,
238  $this->_lineColor);
239  ImageLine($this->_img,
240  $end->x,
241  $start->y-($start->y-$end->y)/2,
242  $end->x,
243  $end->y,
244  $this->_lineColor);
245  }
246  else {
247  ImageLine($this->_img,
248  $start->x,
249  $start->y,
250  $start->x+($end->x-$start->x)/2,
251  $start->y,
252  $this->_lineColor);
253  ImageLine($this->_img,
254  $start->x+($end->x-$start->x)/2,
255  $start->y,
256  $start->x+($end->x-$start->x)/2,
257  $end->y,
258  $this->_lineColor);
259  ImageLine($this->_img,
260  $start->x+($end->x-$start->x)/2,
261  $end->y,
262  $end->x,
263  $end->y,
264  $this->_lineColor);
265  }
266  }
267 
268  /**
269  * Calculate line end points.
270  * @param $poid The parent object's object id.
271  * @param $oid The object's object id.
272  * @return Array containing start and end position
273  */
274  private function calculateEndPoints($poid, $oid) {
275  // from child...
276  if ($this->_map["type"] == MAPTYPE_HORIZONTAL) {
277  // connect from mid top...
278  $x1 = $this->_map[$oid]->x * $this->_xscale + ($this->_labelDim['right'] - $this->_labelDim['left'])/2 + $this->_border;
279  $y1 = $this->_map[$oid]->y * $this->_yscale + $this->_border - 1;
280  }
281  else {
282  // connect from mid left...
283  $x1 = $this->_map[$oid]->x * $this->_xscale + $this->_border - 1;
284  $y1 = $this->_map[$oid]->y * $this->_yscale + ($this->_labelDim['bottom'] - $this->_labelDim['top'])/2 + $this->_border;
285  }
286  // ...to parent
287  if ($this->_map["type"] == MAPTYPE_HORIZONTAL) {
288  // ...to mid bottom
289  $x2 = $this->_map[$poid]->x * $this->_xscale + ($this->_labelDim['right'] - $this->_labelDim['left'])/2 + $this->_border;
290  $y2 = $this->_map[$poid]->y * $this->_yscale + ($this->_labelDim['bottom'] - $this->_labelDim['top']) + $this->_border + 1;
291  }
292  else {
293  // ...to mid right
294  $x2 = $this->_map[$poid]->x * $this->_xscale + $this->_labelDim['right'] - $this->_labelDim['left'] + $this->_border + 1;
295  $y2 = $this->_map[$poid]->y * $this->_yscale + ($this->_labelDim['bottom'] - $this->_labelDim['top'])/2 + $this->_border;
296  }
297  return array(new Position($x1,$y1,0), new Position($x2,$y2,0));
298  }
299 }
300 ?>
getType()
Get the type of the object.
getOID()
Get the object id of the PersistentObject.
OutputStrategy defines the interface for classes that write an object's content to a destination (cal...
IllegalArgumentException signals an exception in method arguments.
drawConnectionLine($poid, $oid)
Draw connection line.
__construct($format, $file, $map, $lineType=self::LINETYPE_DIRECT, $scale=100, $aspect=0.5, $border=50, $usemap='')
Constructor.
ImageOutputStrategy outputs a tree of objects into an image file.
getState()
Get the object's state:
PersistentObject defines the interface of all persistent objects.