/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.puregwt.client.map.gfx;
import org.geomajas.puregwt.client.Geomajas;
import org.geomajas.puregwt.client.map.layer.TilePresenter.TileView;
import org.vaadin.gwtgraphics.client.Group;
import org.vaadin.gwtgraphics.client.VectorObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
/**
* Vector object that represents a tile for a vector layer. As this class is an extension of the {@link VectorObject}
* super class, it can be add to a VectorObjectContainer for rendering. The <code>setContent</code> method will provide
* the actual content for this tile in the form of an SVG or VML string.
*
* @author Pieter De Graef
*/
public class VectorTileObject extends VectorObject implements TileView {
/**
* XLINK name-space. Used in attributes, referencing other elements.
*/
public static final String NS_XLINK = "http://www.w3.org/1999/xlink";
/**
* General SVG name-space.
*/
public static final String NS_SVG = "http://www.w3.org/2000/svg";
/**
* General VML name-space.
*/
public static final String NS_VML = "vml";
/**
* General HTML name-space.
*/
public static final String NS_HTML = "html";
/**
* Set the actual tile contents. This string will probably come from the server which has the capability to create
* SVG/VML string representing a tile.
*
* @param content
* The actual SVG or VML string to be parsed and applied in this tile. It contains the actual rendering.
*/
public void setContent(String content) {
if (Geomajas.isIE()) {
throw new RuntimeException("VectorTileGroup - rendering VML tiles: Not implemented.");
} else {
setInnerSvg(getElement(), content);
}
}
protected Class<? extends VectorObject> getType() {
return Group.class;
}
/**
* Similar method to the "setInnerHTML", but specified for setting SVG. Using the regular setInnerHTML, it is not
* possible to set a string of SVG on an object. This method can do that. On the other hand, this method is better
* not used for setting normal HTML as an element's innerHTML.
*
* @param element
* The element onto which to set the SVG string.
* @param svg
* The string of SVG to set on the element.
*/
public static void setInnerSvg(Element element, String svg) {
if (Geomajas.isFireFox()) {
setFireFoxInnerHTML(element,
"<g xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" + svg
+ "</g>");
} else if (Geomajas.isWebkit()) {
setWebkitInnerHTML(element,
"<g xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" + svg
+ "</g>");
}
}
private static native void setFireFoxInnerHTML(Element element, String svg)
/*-{
var fragment = new DOMParser().parseFromString(svg, "text/xml");
if(fragment) {
var children = fragment.childNodes;
for(var i=0; i < children.length; i++) {
element.appendChild (children[i]);
}
}
}-*/;
private static native void setWebkitInnerHTML(Element element, String svg)
/*-{
var fragment = new DOMParser().parseFromString(svg,"text/xml");
if(fragment) {
var children = fragment.childNodes;
for(var i=0; i < children.length; i++) {
var node = @org.geomajas.puregwt.client.map.gfx.VectorTileObject::clone(Lcom/google/gwt/user/client/Element;)
(children[i]);
element.appendChild (node);
}
}
}-*/;
/**
* Clone a single SVG element.
*
* @param source
* The source SVG element.
* @return Returns the clone.
*/
private static Element clone(Element source) {
if (source == null || source.getNodeName() == null) {
return null;
}
if ("#text".equals(source.getNodeName())) {
return Document.get().createTextNode(source.getNodeValue()).cast();
}
Element clone = createElementNS(NS_SVG, source.getNodeName());
cloneAttributes(source, clone);
for (int i = 0; i < source.getChildCount(); i++) {
Element child = source.getChild(i).cast();
clone.appendChild(clone(child));
}
return clone;
}
/**
* <p>
* Creates a new DOM element in the given name-space. If the name-space is HTML, a normal element will be created.
* </p>
* <p>
* There is an exception when using Internet Explorer! For Internet Explorer a new element will be created of type
* "namespace:tag".
* </p>
*
* @param ns
* The name-space to be used in the element creation.
* @param tag
* The tag-name to be used in the element creation.
* @return Returns a newly created DOM element in the given name-space.
*/
public static Element createElementNS(String ns, String tag) {
if (ns.equals(NS_HTML)) {
return DOM.createElement(tag);
} else {
if (Geomajas.isIE()) {
return DOM.createElement(ns + ":" + tag);
} else {
return createNameSpaceElement(ns, tag);
}
}
}
private static native Element createNameSpaceElement(String ns, String tag)
/*-{
return $doc.createElementNS(ns, tag);
}-*/;
private static native void cloneAttributes(Element source, Element target)
/*-{
if (source != null && target != null) {
for (var i=0; i<source.attributes.length; i++) {
var attribute = source.attributes.item(i);
if (attribute.value != null && attribute.value.length > 0) {
var atClone = null;
try {
atClone = $doc.createAttributeNS(attribute.namespaceURI, attribute.name);
} catch (e) {
atClone = $doc.createAttribute(attribute.name);
}
atClone.value = attribute.value;
target.setAttributeNode(atClone);
}
}
}
}-*/;
}