setId($id); } $id = $definition->getId(); if (is_null($id)) { throw new csException( sprintf('A definition must have an id specified')); } elseif ($this->hasId($id)) { throw new csException( sprintf('The DOM id "%s" has been already defined', $id)); } else { $this->definitions[$id] = $definition; $this->dom_ids[] = $id; } } /** * Adds a SVG shape or group to current SVG Document at a certain depth * * @param mixed $element SVG element to add * @throws csException */ public function addElement($element) { // Add DOM id to document list, if any $id = $element->getId(); if (!is_null($id)) { if ($this->hasId($id)) { throw new csException( sprintf('Document has already an element with id "%s"', $id)); } $this->dom_ids[] = $id; } $this->elements[] = $element; } /** * Create an svg element and returns its instance * * @param string $name * @return csBaseElement */ public function createElement($name) { $class_name = sprintf('cs%s', ucfirst($name)); if (!class_exists($class_name)) { throw new csException(sprintf('Element class "%s" does not exist', $class_name)); } return new $class_name; } /** * Drop an element from container by its DOM id * * @param string $id * @throws csException */ public function dropElementById($id) { foreach ($this->getElements() as $index => $element) { if ($element->getId() == $id) { foreach ($this->dom_ids as $dom_index => $dom_id) { if ($dom_id == $id) { unset($this->dom_ids[$dom_index]); } } unset($this->elements[$index]); return; } } } /** * Returns a defined element alias (a <use/> tag) * * @param string $id * @return array * @throws csException */ public function getDefinition($id) { if (!isset($this->definitions[$id])) { throw new csException( sprintf('Unable to find id "%s" in current document.')); } else { return $this->definitions[$id]; } } /** * Retrieves container definitions * * @return array */ public function getDefinitions() { return $this->definitions; } /** * Retrieve an element instance by its DOM id * * @param string $id * @return csBaseElement */ public function getElementById($id) { $container_types = array('elements', 'definitions'); $found_element = null; foreach ($container_types as $container_type) { if (!property_exists($this, $container_type)) { return; } foreach ($this->$container_type as $element) { if ($element->getId() == $id) { $found_element = $element; break; } elseif ($element instanceof csElementsContainer) { $found_element = $element->getElementById($id); if (!is_null($found_element)) { break; } } } } return $found_element; } /** * Rerieves container elements * * @return array */ public function getElements() { return $this->elements; } /** * Returns an array containing used definitions for current document * * @return array */ public function getUsedDefinitions() { return $this->used_definitions; } /** * Checks if container has an element with given id in it * * @param string $id * @return boolean */ public function hasId($id) { return !is_null($this->getElementById($id)); } /** * Process definitions if any * * @param DOMDocument $dom */ public function processDefinitions(DOMDocument $dom) { if (count($this->getDefinitions()) > 0) { // Definitions declaration $defs_node = $dom->createElement(csDocument::getNodeNS().'defs'); foreach ($this->getDefinitions() as $definition) { // Define elements $definition_node = $definition->compile(csDocument::getIsEmbedded()); $def_node = $dom->importNode($definition_node, true); $defs_node->appendChild($def_node); } $dom->documentElement->appendChild($defs_node); } } /** * Process Document elements * * @param DOMDocument $dom */ public function processElements(DOMDocument $dom) { foreach ($this->getElements() as $element) { $element_node = $element->compile(csDocument::getIsEmbedded()); $node_element = $dom->importNode($element_node, true); $dom->documentElement->appendChild($node_element); } } /** * Process used definitions, if any * * @param DOMDocument $dom */ public function processUsedDefinitions(DOMDocument $dom) { if (count($this->getUsedDefinitions()) > 0) { foreach ($this->getUsedDefinitions() as $used_definition) { $element = $used_definition[0]; $attributes = $used_definition[1]; $use_node = $dom->createElement(csDocument::getNodeNS().'use'); $use_node->setAttribute('xlink:href', '#'.$element->getId()); foreach ($attributes as $attr_name => $attr_value) { $use_node->setAttribute($attr_name, $attr_value); } $dom->documentElement->appendChild($use_node); } } } /** * Swap respective depths of two elements. Both elements are retrieved by * their DOM id. * * @param string $id1 * @param string $id2 * @throws csException */ public function swapDepths($id1, $id2) { if ($id1 == $id2) { return; } $e1 = $this->getElementById($id1); $e2 = $this->getElementById($id2); $e1depth = $e1->getDepth(); $e2depth = $e2->getDepth(); $e2->setDepth($e1depth); $e1->setDepth($e2depth); $this->dropElementById($id1); $this->dropElementById($id2); $this->addElement($e1, $e1depth, true); $this->addElement($e2, $e2depth, true); } /** * Uses a definition in current SVG Document * * @param mixed $element * @param array $attrs More atributes to add to <use/> tag */ public function useDefinition($id, $attrs = array()) { $this->used_definitions[] = array($this->getDefinition($id), $attrs); } }