LayoutVisitor.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 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\visitor;
12 
16 
17 /**
18  * LayoutVisitor is used to position a tree of objects on a plane (the objects must implement the getParent()).
19  * It uses a simple algorithm that positions the objects on a discrete array with distance 1 so
20  * that all leaves are equal distant from their neighbours.
21  * The positions are stored in a map that is provided by the getMap() method.
22  *
23  * @author ingo herwig <ingo@wemove.com>
24  */
25 class LayoutVisitor extends Visitor
26 {
27  const MAPTYPE_HORIZONTAL = 0;
28  const MAPTYPE_VERTICAL = 1;
29 
30  private $map = [];
31 
32  /**
33  * Constructor.
34  */
35  public function __construct() {
36  // set default maptype
37  $this->map["type"] = self::MAPTYPE_HORIZONTAL;
38  }
39 
40  /**
41  * Visit the current object in iteration and position it on the map.
42  * @param $obj PersistentObject instance
43  */
44  public function visit($obj) {
45  $this->map[$obj->getOID()] = $this->calculatePosition($obj);
46  }
47 
48  /**
49  * Visit the current object in iteration and position it on the map.
50  * @return The object map as assioziative array (key: object Id, value: Position).
51  * map["type"] = MAPTYPE_HORIZONTAL | MAPTYPE_VERTICAL
52  */
53  public function getMap() {
54  return $this->map;
55  }
56 
57  /**
58  * Flip layout (x <-> y).
59  */
60  public function flip() {
61  foreach($this->map as $key => $position) {
62  $temp = $position->x;
63  $position->x = $position->y;
64  $position->y = $temp;
65  $this->map[$key] = $position;
66  }
67  // switch map type
68  $this->map["type"] = 1-$this->map["type"];
69  }
70 
71  /**
72  * Calculate the object's position using the described algorithm.
73  * @param $obj PersistentObject instance
74  */
75  private function calculatePosition($obj) {
76  $parent = & $obj->getParent();
77  if (!$parent) {
78  // start here
79  $position = new Position(0, 0, 0);
80  }
81  else {
82  $position = new Position(0, 0, 0);
83  $parentPos = $this->map[$parent->getOID()];
84  $position->y = $parentPos->y + 1;
85  $position->z = $parentPos->z + 1;
86 
87  $siblings = $parent->getChildren();
88  if ($siblings[0]->getOID() == $obj->getOID()) {
89  $position->x = $parentPos->x;
90  }
91  else {
92  // find leftmost sibling of object
93  for ($i=0; $i<sizeOf($siblings); $i++) {
94  if ($siblings[$i]->getOID() == $obj->getOID()) {
95  $leftSibling = & $siblings[$i-1];
96  }
97  }
98  // find x-coordinate of rightmost descendant of leftmost sibling
99  $maxX = 0;
100  $nIter = new NodeIterator($leftSibling);
101  foreach($nIter as $oid => $curObject) {
102  $curPosition = $this->map[$curObject->getOID()];
103  if ($curPosition->x >= $maxX) {
104  $maxX = $curPosition->x;
105  }
106  }
107  $position->x = $maxX+2;
108  // reposition parents
109  while ($parent != null) {
110  $this->map[$parent->getOID()]->x += 1;
111  $parent = $parent->getParent();
112  }
113  }
114  }
115  return $position;
116  }
117 }
118 ?>
getMap()
Visit the current object in iteration and position it on the map.
The Position class stores a coordinate tuple for use with the LayoutVisitor.
Definition: Position.php:19
Visitor is used to extend an object's functionality by not extending its interface.
Definition: Visitor.php:26
NodeIterator is used to iterate over a tree/list built of Nodes using a Depth-First-Algorithm.
LayoutVisitor is used to position a tree of objects on a plane (the objects must implement the getPar...
visit($obj)
Visit the current object in iteration and position it on the map.