root/cleversvg/trunk/container/csElementsContainer.class.php

Revision 336, 7.2 kB (checked in by nperriault, 10 months ago)

Clever Svg:

  • refs #40: more elements tests
  • Removed depth management, as svg handle it natively

Warning: breaks BC from 0.5.

Line 
1 <?php
2 class csElementsContainer extends csBaseElement
3 {
4
5   /**
6    * Definitions container
7    * @var array
8    */
9   protected $definitions = array();
10
11   /**
12    * Elements container
13    * @var array
14    */
15   protected $elements = array();
16
17   /**
18    * Used definitions
19    * @var array
20    */
21   protected $used_definitions = array();
22
23   /**
24    * DOM ids
25    * @var array
26    */
27   protected $dom_ids = array();
28
29   /**
30    * Adds a definition to current SVG Document
31    *
32    * @param  mixed  $definition  SVG definition to add
33    * @param  string $id          Override element DOM id
34    * TODO: implement definitions and references
35    */
36   public function addAsDefinition($definition, $id = null)
37   {
38     $is_element = is_callable(array($definition, 'setId'));
39     if (is_string($id) && trim($id) != '' && $is_element)
40     {
41       $definition->setId($id);
42     }
43     $id = $definition->getId();
44     if (is_null($id))
45     {
46       throw new csException(
47                   sprintf('A definition must have an id specified'));
48     }
49     elseif ($this->hasId($id))
50     {
51       throw new csException(
52                   sprintf('The DOM id "%s" has been already defined', $id));
53     }
54     else
55     {
56       $this->definitions[$id] = $definition;
57       $this->dom_ids[] = $id;
58     }
59   }
60
61   /**
62    * Adds a SVG shape or group to current SVG Document at a certain depth
63    *
64    * @param  mixed    $element  SVG element to add
65    * @throws csException
66    */
67   public function addElement($element)
68   {
69     // Add DOM id to document list, if any
70     $id = $element->getId();
71     if (!is_null($id))
72     {
73       if ($this->hasId($id))
74       {
75         throw new csException(
76           sprintf('Document has already an element with id "%s"', $id));
77       }
78       $this->dom_ids[] = $id;
79     }
80     $this->elements[] = $element;
81   }
82
83   /**
84    * Create an svg element and returns its instance
85    *
86    * @param  string $name
87    * @return csBaseElement
88    */
89   public function createElement($name)
90   {
91     $class_name = sprintf('cs%s', ucfirst($name));
92     if (!class_exists($class_name))
93     {
94       throw new csException(sprintf('Element class "%s" does not exist',
95                                    $class_name));
96     }
97     return new $class_name;
98   }
99
100   /**
101    * Drop an element from container by its DOM id
102    *
103    * @param  string  $id
104    * @throws csException
105    */
106   public function dropElementById($id)
107   {
108     foreach ($this->getElements() as $index => $element)
109     {
110       if ($element->getId() == $id)
111       {
112         foreach ($this->dom_ids as $dom_index => $dom_id)
113         {
114           if ($dom_id == $id)
115           {
116             unset($this->dom_ids[$dom_index]);
117           }
118         }
119         unset($this->elements[$index]);
120         return;
121       }
122     }
123   }
124
125   /**
126    * Returns a defined element alias (a &lt;use/&gt; tag)
127    *
128    * @param  string  $id
129    * @return array
130    * @throws csException
131    */
132   public function getDefinition($id)
133   {
134     if (!isset($this->definitions[$id]))
135     {
136       throw new csException(
137                   sprintf('Unable to find id "%s" in current document.'));
138     }
139     else
140     {
141       return $this->definitions[$id];
142     }
143   }
144
145   /**
146    * Retrieves container definitions
147    *
148    * @return array
149    */
150   public function getDefinitions()
151   {
152     return $this->definitions;
153   }
154
155   /**
156    * Retrieve an element instance by its DOM id
157    *
158    * @param  string  $id
159    * @return csBaseElement
160    */
161   public function getElementById($id)
162   {
163     $container_types = array('elements', 'definitions');
164     $found_element = null;
165     foreach ($container_types as $container_type)
166     {
167       if (!property_exists($this, $container_type))
168       {
169         return;
170       }
171       foreach ($this->$container_type as $element)
172       {
173         if ($element->getId() == $id)
174         {
175           $found_element = $element;
176           break;
177         }
178         elseif ($element instanceof csElementsContainer)
179         {
180           $found_element = $element->getElementById($id);
181           if (!is_null($found_element))
182           {
183             break;
184           }
185         }
186       }
187     }
188     return $found_element;
189   }
190
191   /**
192    * Rerieves container elements
193    *
194    * @return array
195    */
196   public function getElements()
197   {
198     return $this->elements;
199   }
200
201   /**
202    * Returns an array containing used definitions for current document
203    *
204    * @return array
205    */
206   public function getUsedDefinitions()
207   {
208     return $this->used_definitions;
209   }
210
211   /**
212    * Checks if container has an element with given id in it
213    *
214    * @param  string  $id
215    * @return boolean
216    */
217   public function hasId($id)
218   {
219     return !is_null($this->getElementById($id));
220   }
221
222   /**
223    * Process definitions if any
224    *
225    * @param  DOMDocument  $dom
226    */
227   public function processDefinitions(DOMDocument $dom)
228   {
229     if (count($this->getDefinitions()) > 0)
230     {
231       // Definitions declaration
232       $defs_node = $dom->createElement(csDocument::getNodeNS().'defs');
233       foreach ($this->getDefinitions() as $definition)
234       {
235         // Define elements
236         $definition_node = $definition->compile(csDocument::getIsEmbedded());
237         $def_node = $dom->importNode($definition_node, true);
238         $defs_node->appendChild($def_node);
239       }
240       $dom->documentElement->appendChild($defs_node);
241     }
242   }
243
244   /**
245    * Process Document elements
246    *
247    * @param  DOMDocument  $dom
248    */
249   public function processElements(DOMDocument $dom)
250   {
251     foreach ($this->getElements() as $element)
252     {
253       $element_node = $element->compile(csDocument::getIsEmbedded());
254       $node_element = $dom->importNode($element_node, true);
255       $dom->documentElement->appendChild($node_element);
256     }
257   }
258
259   /**
260    * Process used definitions, if any
261    *
262    * @param  DOMDocument  $dom
263    */
264   public function processUsedDefinitions(DOMDocument $dom)
265   {
266     if (count($this->getUsedDefinitions()) > 0)
267     {
268       foreach ($this->getUsedDefinitions() as $used_definition)
269       {
270         $element = $used_definition[0];
271         $attributes = $used_definition[1];
272         $use_node = $dom->createElement(csDocument::getNodeNS().'use');
273         $use_node->setAttribute('xlink:href', '#'.$element->getId());
274         foreach ($attributes as $attr_name => $attr_value)
275         {
276           $use_node->setAttribute($attr_name, $attr_value);
277         }
278         $dom->documentElement->appendChild($use_node);
279       }
280     }
281   }
282
283   /**
284    * Swap respective depths of two elements. Both elements are retrieved by
285    * their DOM id.
286    *
287    * @param  string $id1
288    * @param  string $id2
289    * @throws csException
290    */
291   public function swapDepths($id1, $id2)
292   {
293     if ($id1 == $id2)
294     {
295       return;
296     }
297     $e1 = $this->getElementById($id1);
298     $e2 = $this->getElementById($id2);
299     $e1depth = $e1->getDepth();
300     $e2depth = $e2->getDepth();
301     $e2->setDepth($e1depth);
302     $e1->setDepth($e2depth);
303     $this->dropElementById($id1);
304     $this->dropElementById($id2);
305     $this->addElement($e1, $e1depth, true);
306     $this->addElement($e2, $e2depth, true);
307   }
308
309   /**
310    * Uses a definition in current SVG Document
311    *
312    * @param  mixed  $element
313    * @param  array  $attrs    More atributes to add to &lt;use/&gt; tag
314    */
315   public function useDefinition($id, $attrs = array())
316   {
317     $this->used_definitions[] = array($this->getDefinition($id), $attrs);
318   }
319
320 }
Note: See TracBrowser for help on using the browser.