Merge remote branch 'upstream/master' into 2.12

This commit is contained in:
Éric Lemoine
2012-03-14 20:20:12 +01:00
13 changed files with 983 additions and 1080 deletions

View File

@@ -409,9 +409,7 @@ Group: OpenLayers {
File: Renderer (no auto-title, OpenLayers/Renderer.js)
File: Canvas (no auto-title, OpenLayers/Renderer/Canvas.js)
File: ElementsIndexer (no auto-title, OpenLayers/Renderer/Elements.js)
File: NG (no auto-title, OpenLayers/Renderer/NG.js)
File: SVG (no auto-title, OpenLayers/Renderer/SVG.js)
File: SVG2 (no auto-title, OpenLayers/Renderer/SVG2.js)
File: VML (no auto-title, OpenLayers/Renderer/VML.js)
} # Group: Renderer

View File

@@ -409,9 +409,7 @@ Group: OpenLayers {
File: Renderer (no auto-title, OpenLayers/Renderer.js)
File: Canvas (no auto-title, OpenLayers/Renderer/Canvas.js)
File: ElementsIndexer (no auto-title, OpenLayers/Renderer/Elements.js)
File: NG (no auto-title, OpenLayers/Renderer/NG.js)
File: SVG (no auto-title, OpenLayers/Renderer/SVG.js)
File: SVG2 (no auto-title, OpenLayers/Renderer/SVG2.js)
File: VML (no auto-title, OpenLayers/Renderer/VML.js)
} # Group: Renderer

View File

@@ -257,9 +257,7 @@
"OpenLayers/Geometry/MultiPolygon.js",
"OpenLayers/Renderer.js",
"OpenLayers/Renderer/Elements.js",
"OpenLayers/Renderer/NG.js",
"OpenLayers/Renderer/SVG.js",
"OpenLayers/Renderer/SVG2.js",
"OpenLayers/Renderer/Canvas.js",
"OpenLayers/Renderer/VML.js",
"OpenLayers/Layer/Vector.js",

View File

@@ -62,7 +62,6 @@ OpenLayers.Control.Zoom = OpenLayers.Class(OpenLayers.Control, {
links = this.getOrCreateLinks(div),
zoomIn = links.zoomIn,
zoomOut = links.zoomOut,
bind = OpenLayers.Function.bind,
eventsInstance = this.map.events;
if (zoomOut.parentNode !== div) {

View File

@@ -473,49 +473,43 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
moveTo: function(bounds, zoomChanged, dragging) {
OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
var ng = (OpenLayers.Renderer.NG && this.renderer instanceof OpenLayers.Renderer.NG);
if (ng) {
dragging || this.renderer.updateDimensions(zoomChanged);
} else {
var coordSysUnchanged = true;
var coordSysUnchanged = true;
if (!dragging) {
this.renderer.root.style.visibility = 'hidden';
if (!dragging) {
this.renderer.root.style.visibility = 'hidden';
var viewSize = this.map.getSize(),
viewWidth = viewSize.w,
viewHeight = viewSize.h,
offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2,
offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2;
offsetLeft += parseInt(this.map.layerContainerDiv.style.left, 10);
offsetLeft = -Math.round(offsetLeft);
offsetTop += parseInt(this.map.layerContainerDiv.style.top, 10);
offsetTop = -Math.round(offsetTop);
var viewSize = this.map.getSize(),
viewWidth = viewSize.w,
viewHeight = viewSize.h,
offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2,
offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2;
offsetLeft += parseInt(this.map.layerContainerDiv.style.left, 10);
offsetLeft = -Math.round(offsetLeft);
offsetTop += parseInt(this.map.layerContainerDiv.style.top, 10);
offsetTop = -Math.round(offsetTop);
this.div.style.left = offsetLeft + 'px';
this.div.style.top = offsetTop + 'px';
var extent = this.map.getExtent().scale(this.ratio);
coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
this.div.style.left = offsetLeft + 'px';
this.div.style.top = offsetTop + 'px';
this.renderer.root.style.visibility = 'visible';
var extent = this.map.getExtent().scale(this.ratio);
coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
// Force a reflow on gecko based browsers to prevent jump/flicker.
// This seems to happen on only certain configurations; it was originally
// noticed in FF 2.0 and Linux.
if (OpenLayers.IS_GECKO === true) {
this.div.scrollLeft = this.div.scrollLeft;
}
this.renderer.root.style.visibility = 'visible';
// Force a reflow on gecko based browsers to prevent jump/flicker.
// This seems to happen on only certain configurations; it was originally
// noticed in FF 2.0 and Linux.
if (OpenLayers.IS_GECKO === true) {
this.div.scrollLeft = this.div.scrollLeft;
}
if(!zoomChanged && coordSysUnchanged) {
for(var i in this.unrenderedFeatures) {
var feature = this.unrenderedFeatures[i];
this.drawFeature(feature);
}
if (!zoomChanged && coordSysUnchanged) {
for (var i in this.unrenderedFeatures) {
var feature = this.unrenderedFeatures[i];
this.drawFeature(feature);
}
}
}
if (!this.drawn || (!ng && (zoomChanged || !coordSysUnchanged))) {
if (!this.drawn || zoomChanged || !coordSysUnchanged) {
this.drawn = true;
var feature;
for(var i=0, len=this.features.length; i<len; i++) {
@@ -534,12 +528,9 @@ OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
* {Boolean} The layer was redrawn.
*/
redraw: function() {
if (OpenLayers.Renderer.NG && this.renderer instanceof OpenLayers.Renderer.NG) {
this.drawn = false;
}
this.resolution = null; // this is to force Layer.redraw set
// zoomChanged to true in the moveTo
// call
// this is to force Layer.redraw set zoomChanged
// to true in the moveTo call
this.resolution = null;
return OpenLayers.Layer.prototype.redraw.apply(this, arguments);
},

View File

@@ -1,135 +0,0 @@
/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Renderer/Elements.js
*/
/**
* Class: OpenLayers.Renderer.NG
*
* Inherits from:
* - <OpenLayers.Renderer.Elements>
*/
OpenLayers.Renderer.NG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
/**
* Constant: labelNodeType
* {String} The node type for text label containers. To be defined by
* subclasses.
*/
labelNodeType: null,
/**
* Constructor: OpenLayers.Renderer.NG
*
* Parameters:
* containerID - {String}
* options - {Object} options for this renderer. Supported options are:
* * yOrdering - {Boolean} Whether to use y-ordering
* * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
* if yOrdering is set to true.
*/
/**
* Method: updateDimensions
* To be extended by subclasses - here we set positioning related styles
* on HTML elements, subclasses have to do the same for renderer specific
* elements (e.g. viewBox, width and height of the rendererRoot)
*
* Parameters:
* zoomChanged - {Boolean} Has the zoom changed? If so, subclasses may have
* to update feature styles/dimensions.
*/
updateDimensions: function(zoomChanged) {
var mapExtent = this.map.getExtent();
var renderExtent = mapExtent.scale(3);
this.setExtent(renderExtent, true);
var res = this.getResolution();
var div = this.rendererRoot.parentNode;
var layerLeft = parseFloat(div.parentNode.style.left);
var layerTop = parseFloat(div.parentNode.style.top);
div.style.left = ((renderExtent.left - mapExtent.left) / res - layerLeft) + "px";
div.style.top = ((mapExtent.top - renderExtent.top) / res - layerTop) + "px";
},
/**
* Method: resize
*/
setSize: function() {
this.map.getExtent() && this.updateDimensions();
},
/**
* Method: drawFeature
* Draw the feature. The optional style argument can be used
* to override the feature's own style. This method should only
* be called from layer.drawFeature().
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {<Object>}
*
* Returns:
* {Boolean} true if the feature has been drawn completely, false if not,
* undefined if the feature had no geometry
*/
drawFeature: function(feature, style) {
if(style == null) {
style = feature.style;
}
if (feature.geometry) {
var rendered = this.drawGeometry(feature.geometry, style, feature.id);
if(rendered !== false && style.label) {
var location = feature.geometry.getCentroid();
this.drawText(feature.id, style, location);
} else {
this.removeText(feature.id);
}
return rendered;
}
},
/**
* Method: drawText
* Function for drawing text labels.
* This method is only called by the renderer itself.
*
* Parameters:
* featureId - {String|DOMElement}
* style - {Object}
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
*
* Returns:
* {DOMElement} container holding the text label (to be populated by
* subclasses)
*/
drawText: function(featureId, style, location) {
var label;
if (typeof featureId !== "string") {
label = featureId;
} else {
label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, this.labelNodeType);
label._featureId = featureId;
}
label._style = style;
label._x = location.x;
label._y = location.y;
if(style.labelXOffset || style.labelYOffset) {
var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
var res = this.getResolution();
location.move(xOffset*res, yOffset*res);
}
if(label.parentNode !== this.textRoot) {
this.textRoot.appendChild(label);
}
return label;
},
CLASS_NAME: "OpenLayers.Renderer.NG"
});

View File

@@ -1,797 +0,0 @@
/* Copyright (c) 2006-2012 by OpenLayers Contributors (see authors.txt for
* full list of contributors). Published under the Clear BSD license.
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/**
* @requires OpenLayers/Renderer/NG.js
*/
/**
* Class: OpenLayers.Renderer.SVG2
*
* Inherits from:
* - <OpenLayers.Renderer.NG>
*/
OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
/**
* Property: xmlns
* {String}
*/
xmlns: "http://www.w3.org/2000/svg",
/**
* Property: xlinkns
* {String}
*/
xlinkns: "http://www.w3.org/1999/xlink",
/**
* Property: symbolMetrics
* {Object} Cache for symbol metrics according to their svg coordinate
* space. This is an object keyed by the symbol's id, and values are
* an object with size, x and y properties.
*/
symbolMetrics: null,
/**
* Constant: labelNodeType
* {String} The node type for text label containers.
*/
labelNodeType: "g",
/**
* Constructor: OpenLayers.Renderer.SVG2
*
* Parameters:
* containerID - {String}
*/
initialize: function(containerID) {
if (!this.supported()) {
return;
}
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
arguments);
this.symbolMetrics = {};
},
/**
* APIMethod: supported
*
* Returns:
* {Boolean} Whether or not the browser supports the SVG renderer
*/
supported: function() {
var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
return (document.implementation &&
(document.implementation.hasFeature("org.w3c.svg", "1.0") ||
document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
},
/**
* Method: updateDimensions
*
* Parameters:
* zoomChanged - {Boolean}
*/
updateDimensions: function(zoomChanged) {
OpenLayers.Renderer.NG.prototype.updateDimensions.apply(this, arguments);
var res = this.getResolution();
var width = this.extent.getWidth();
var height = this.extent.getHeight();
var extentString = [
this.extent.left,
-this.extent.top,
width,
height
].join(" ");
this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
this.rendererRoot.setAttributeNS(null, "width", width / res);
this.rendererRoot.setAttributeNS(null, "height", height / res);
if (zoomChanged === true) {
// update styles for the new resolution
var i, len;
var nodes = this.vectorRoot.childNodes;
for (i=0, len=nodes.length; i<len; ++i) {
this.setStyle(nodes[i]);
}
var textNodes = this.textRoot.childNodes;
var label;
for (i=0, len=textNodes.length; i<len; ++i) {
label = textNodes[i];
this.drawText(label, label._style,
new OpenLayers.Geometry.Point(label._x, label._y)
);
}
}
},
/**
* Method: getNodeType
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
*
* Returns:
* {String} The corresponding node type for the specified geometry
*/
getNodeType: function(geometry, style) {
var nodeType = null;
switch (geometry.CLASS_NAME) {
case "OpenLayers.Geometry.Point":
if (style.externalGraphic) {
nodeType = "image";
} else if (this.isComplexSymbol(style.graphicName)) {
nodeType = "svg";
} else {
nodeType = "circle";
}
break;
case "OpenLayers.Geometry.Rectangle":
nodeType = "rect";
break;
case "OpenLayers.Geometry.LineString":
nodeType = "polyline";
break;
case "OpenLayers.Geometry.LinearRing":
nodeType = "polygon";
break;
case "OpenLayers.Geometry.Polygon":
case "OpenLayers.Geometry.Curve":
nodeType = "path";
break;
default:
break;
}
return nodeType;
},
/**
* Method: setStyle
* Use to set all the style attributes to a SVG node.
*
* Takes care to adjust stroke width and point radius to be
* resolution-relative
*
* Parameters:
* node - {SVGDomElement} An SVG element to decorate
* style - {Object}
* options - {Object} Currently supported options include
* 'isFilled' {Boolean} and
* 'isStroked' {Boolean}
*/
setStyle: function(node, style, options) {
style = style || node._style;
options = options || node._options;
var resolution = this.getResolution();
var r = node._radius;
var widthFactor = resolution;
if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
node.style.visibility = "";
if (style.graphic === false) {
node.style.visibility = "hidden";
} else if (style.externalGraphic) {
if (style.graphicTitle) {
node.setAttributeNS(null, "title", style.graphicTitle);
//Standards-conformant SVG
// Prevent duplicate nodes. See issue https://github.com/openlayers/openlayers/issues/92
var titleNode = node.getElementsByTagName("title");
if (titleNode.length > 0) {
titleNode[0].firstChild.textContent = style.graphicTitle;
} else {
var label = this.nodeFactory(null, "title");
label.textContent = style.graphicTitle;
node.appendChild(label);
}
}
if (style.graphicWidth && style.graphicHeight) {
node.setAttributeNS(null, "preserveAspectRatio", "none");
}
var width = style.graphicWidth || style.graphicHeight;
var height = style.graphicHeight || style.graphicWidth;
width = width ? width : style.pointRadius*2;
height = height ? height : style.pointRadius*2;
width *= resolution;
height *= resolution;
var xOffset = (style.graphicXOffset != undefined) ?
style.graphicXOffset * resolution : -(0.5 * width);
var yOffset = (style.graphicYOffset != undefined) ?
style.graphicYOffset * resolution : -(0.5 * height);
var opacity = style.graphicOpacity || style.fillOpacity;
node.setAttributeNS(null, "x", node._x + xOffset);
node.setAttributeNS(null, "y", node._y + yOffset);
node.setAttributeNS(null, "width", width);
node.setAttributeNS(null, "height", height);
node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
node.setAttributeNS(null, "style", "opacity: "+opacity);
node.onclick = OpenLayers.Renderer.SVG2.preventDefault;
} else if (this.isComplexSymbol(style.graphicName)) {
// the symbol viewBox is three times as large as the symbol
var offset = style.pointRadius * 3 * resolution;
var size = offset * 2;
var src = this.importSymbol(style.graphicName);
widthFactor = this.symbolMetrics[src.id].size * 3 / size * resolution;
// remove the node from the dom before we modify it. This
// prevents various rendering issues in Safari and FF
var parent = node.parentNode;
var nextSibling = node.nextSibling;
if(parent) {
parent.removeChild(node);
}
// The more appropriate way to implement this would be use/defs,
// but due to various issues in several browsers, it is safer to
// copy the symbols instead of referencing them.
// See e.g. ticket http://trac.osgeo.org/openlayers/ticket/2985
// and this email thread
// http://osgeo-org.1803224.n2.nabble.com/Select-Control-Ctrl-click-on-Feature-with-a-graphicName-opens-new-browser-window-tc5846039.html
node.firstChild && node.removeChild(node.firstChild);
node.appendChild(src.firstChild.cloneNode(true));
node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
node.setAttributeNS(null, "width", size);
node.setAttributeNS(null, "height", size);
node.setAttributeNS(null, "x", node._x - offset);
node.setAttributeNS(null, "y", node._y - offset);
// now that the node has all its new properties, insert it
// back into the dom where it was
if(nextSibling) {
parent.insertBefore(node, nextSibling);
} else if(parent) {
parent.appendChild(node);
}
} else {
node.setAttributeNS(null, "r", style.pointRadius * resolution);
}
var rotation = style.rotation;
if (rotation !== undefined || node._rotation !== undefined) {
node._rotation = rotation;
rotation |= 0;
if (node.nodeName !== "svg") {
node.setAttributeNS(null, "transform",
["rotate(", rotation, node._x, node._y, ")"].join(" ")
);
} else {
var metrics = this.symbolMetrics[src.id];
node.firstChild.setAttributeNS(null, "transform",
["rotate(", rotation, metrics.x, metrics.y, ")"].join(" ")
);
}
}
}
if (options.isFilled) {
node.setAttributeNS(null, "fill", style.fillColor);
node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
} else {
node.setAttributeNS(null, "fill", "none");
}
if (options.isStroked) {
node.setAttributeNS(null, "stroke", style.strokeColor);
node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
// Hard-coded linejoin for now, to make it look the same as in VML.
// There is no strokeLinejoin property yet for symbolizers.
node.setAttributeNS(null, "stroke-linejoin", "round");
style.strokeDashstyle && node.setAttributeNS(null,
"stroke-dasharray", this.dashStyle(style, widthFactor));
} else {
node.setAttributeNS(null, "stroke", "none");
}
if (style.pointerEvents) {
node.setAttributeNS(null, "pointer-events", style.pointerEvents);
}
if (style.cursor != null) {
node.setAttributeNS(null, "cursor", style.cursor);
}
return node;
},
/**
* Method: dashStyle
*
* Parameters:
* style - {Object}
* widthFactor - {Number}
*
* Returns:
* {String} A SVG compliant 'stroke-dasharray' value
*/
dashStyle: function(style, widthFactor) {
var w = style.strokeWidth * widthFactor;
var str = style.strokeDashstyle;
switch (str) {
case 'solid':
return 'none';
case 'dot':
return [widthFactor, 4 * w].join();
case 'dash':
return [4 * w, 4 * w].join();
case 'dashdot':
return [4 * w, 4 * w, widthFactor, 4 * w].join();
case 'longdash':
return [8 * w, 4 * w].join();
case 'longdashdot':
return [8 * w, 4 * w, widthFactor, 4 * w].join();
default:
var parts = OpenLayers.String.trim(str).split(/\s+/g);
for (var i=0, ii=parts.length; i<ii; i++) {
parts[i] = parts[i] * widthFactor;
}
return parts.join();
}
},
/**
* Method: createNode
*
* Parameters:
* type - {String} Kind of node to draw
* id - {String} Id for node
*
* Returns:
* {DOMElement} A new node of the given type and id
*/
createNode: function(type, id) {
var node = document.createElementNS(this.xmlns, type);
if (id) {
node.setAttributeNS(null, "id", id);
}
return node;
},
/**
* Method: nodeTypeCompare
*
* Parameters:
* node - {SVGDomElement} An SVG element
* type - {String} Kind of node
*
* Returns:
* {Boolean} Whether or not the specified node is of the specified type
*/
nodeTypeCompare: function(node, type) {
return (type == node.nodeName);
},
/**
* Method: createRenderRoot
*
* Returns:
* {DOMElement} The specific render engine's root element
*/
createRenderRoot: function() {
return this.nodeFactory(this.container.id + "_svgRoot", "svg");
},
/**
* Method: createRoot
*
* Parameters:
* suffix - {String} suffix to append to the id
*
* Returns:
* {DOMElement}
*/
createRoot: function(suffix) {
return this.nodeFactory(this.container.id + suffix, "g");
},
/**
* Method: createDefs
*
* Returns:
* {DOMElement} The element to which we'll add the symbol definitions
*/
createDefs: function() {
var defs = this.nodeFactory(this.container.id + "_defs", "defs");
this.rendererRoot.appendChild(defs);
return defs;
},
/**************************************
* *
* GEOMETRY DRAWING FUNCTIONS *
* *
**************************************/
/**
* Method: drawPoint
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the point
*/
drawPoint: function(node, geometry) {
return this.drawCircle(node, geometry, 1);
},
/**
* Method: drawCircle
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* radius - {Float}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the circle
*/
drawCircle: function(node, geometry, radius) {
var x = geometry.x;
var y = -geometry.y;
node.setAttributeNS(null, "cx", x);
node.setAttributeNS(null, "cy", y);
node._x = x;
node._y = y;
node._radius = radius;
return node;
},
/**
* Method: drawLineString
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components of
* the linestring, or false if nothing could be drawn
*/
drawLineString: function(node, geometry) {
var path = this.getComponentsString(geometry.components);
node.setAttributeNS(null, "points", path);
return node;
},
/**
* Method: drawLinearRing
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the linear ring, or false if nothing could be drawn
*/
drawLinearRing: function(node, geometry) {
var path = this.getComponentsString(geometry.components);
node.setAttributeNS(null, "points", path);
return node;
},
/**
* Method: drawPolygon
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the polygon, or false if nothing could be drawn
*/
drawPolygon: function(node, geometry) {
var d = [];
var draw = true;
var complete = true;
var linearRingResult, path;
for (var j=0, len=geometry.components.length; j<len; j++) {
d.push("M");
path = this.getComponentsString(
geometry.components[j].components, " ");
d.push(path);
}
d.push("z");
node.setAttributeNS(null, "d", d.join(" "));
node.setAttributeNS(null, "fill-rule", "evenodd");
return node;
},
/**
* Method: drawRectangle
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the rectangle
*/
drawRectangle: function(node, geometry) {
node.setAttributeNS(null, "x", geometry.x);
node.setAttributeNS(null, "y", -geometry.y);
node.setAttributeNS(null, "width", geometry.width);
node.setAttributeNS(null, "height", geometry.height);
return node;
},
/**
* Method: drawText
* Function for drawing text labels.
* This method is only called by the renderer itself.
*
* Parameters:
* featureId - {String|DOMElement}
* style - {Object}
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
*
* Returns:
* {DOMElement} container holding the text label
*/
drawText: function(featureId, style, location) {
var g = OpenLayers.Renderer.NG.prototype.drawText.apply(this, arguments);
var text = g.firstChild ||
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_text", "text");
var res = this.getResolution();
text.setAttributeNS(null, "x", location.x / res);
text.setAttributeNS(null, "y", - location.y / res);
g.setAttributeNS(null, "transform", "scale(" + res + ")");
if (style.fontColor) {
text.setAttributeNS(null, "fill", style.fontColor);
}
if (style.fontOpacity) {
text.setAttributeNS(null, "opacity", style.fontOpacity);
}
if (style.fontFamily) {
text.setAttributeNS(null, "font-family", style.fontFamily);
}
if (style.fontSize) {
text.setAttributeNS(null, "font-size", style.fontSize);
}
if (style.fontWeight) {
text.setAttributeNS(null, "font-weight", style.fontWeight);
}
if (style.fontStyle) {
text.setAttributeNS(null, "font-style", style.fontStyle);
}
if (style.labelSelect === true) {
text.setAttributeNS(null, "pointer-events", "visible");
text._featureId = featureId;
} else {
text.setAttributeNS(null, "pointer-events", "none");
}
var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign;
text.setAttributeNS(null, "text-anchor",
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[0]] || "middle");
if (OpenLayers.IS_GECKO === true) {
text.setAttributeNS(null, "dominant-baseline",
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[1]] || "central");
}
var labelRows = style.label.split('\n');
var numRows = labelRows.length;
while (text.childNodes.length > numRows) {
text.removeChild(text.lastChild);
}
for (var i = 0; i < numRows; i++) {
var tspan = text.childNodes[i] ||
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_" + i, "tspan");
if (style.labelSelect === true) {
tspan._featureId = featureId;
}
if (OpenLayers.IS_GECKO === false) {
tspan.setAttributeNS(null, "baseline-shift",
OpenLayers.Renderer.SVG2.LABEL_VSHIFT[align[1]] || "-35%");
}
tspan.setAttribute("x", location.x / res);
if (i == 0) {
var vfactor = OpenLayers.Renderer.SVG2.LABEL_VFACTOR[align[1]];
if (vfactor == null) {
vfactor = -.5;
}
tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em");
} else {
tspan.setAttribute("dy", "1em");
}
tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i];
if (!tspan.parentNode) {
text.appendChild(tspan);
}
}
if (!text.parentNode) {
g.appendChild(text);
}
return g;
},
/**
* Method: getComponentString
*
* Parameters:
* components - {Array(<OpenLayers.Geometry.Point>)} Array of points
* separator - {String} character between coordinate pairs. Defaults to ","
*
* Returns:
* {Object} hash with properties "path" (the string created from the
* components and "complete" (false if the renderer was unable to
* draw all components)
*/
getComponentsString: function(components, separator) {
var len = components.length;
var strings = new Array(len);
for (var i=0; i<len; i++) {
strings[i] = this.getShortString(components[i]);
}
return strings.join(separator || ",");
},
/**
* Method: getShortString
*
* Parameters:
* point - {<OpenLayers.Geometry.Point>}
*
* Returns:
* {String} or false if point is outside the valid range
*/
getShortString: function(point) {
return point.x + "," + (-point.y);
},
/**
* Method: importSymbol
* add a new symbol definition from the rendererer's symbol hash
*
* Parameters:
* graphicName - {String} name of the symbol to import
*
* Returns:
* {DOMElement} - the imported symbol
*/
importSymbol: function (graphicName) {
if (!this.defs) {
// create svg defs tag
this.defs = this.createDefs();
}
var id = this.container.id + "-" + graphicName;
// check if symbol already exists in the defs
var existing = document.getElementById(id);
if (existing != null) {
return existing;
}
var symbol = OpenLayers.Renderer.symbol[graphicName];
if (!symbol) {
throw new Error(graphicName + ' is not a valid symbol name');
}
var symbolNode = this.nodeFactory(id, "symbol");
var node = this.nodeFactory(null, "polygon");
symbolNode.appendChild(node);
var symbolExtent = new OpenLayers.Bounds(
Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
var points = [];
var x,y;
for (var i=0, len=symbol.length; i<len; i=i+2) {
x = symbol[i];
y = symbol[i+1];
symbolExtent.left = Math.min(symbolExtent.left, x);
symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
symbolExtent.right = Math.max(symbolExtent.right, x);
symbolExtent.top = Math.max(symbolExtent.top, y);
points.push(x, ",", y);
}
node.setAttributeNS(null, "points", points.join(" "));
var width = symbolExtent.getWidth();
var height = symbolExtent.getHeight();
// create a viewBox three times as large as the symbol itself,
// to allow for strokeWidth being displayed correctly at the corners.
var viewBox = [symbolExtent.left - width,
symbolExtent.bottom - height, width * 3, height * 3];
symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
this.symbolMetrics[id] = {
size: Math.max(width, height),
x: symbolExtent.getCenterLonLat().lon,
y: symbolExtent.getCenterLonLat().lat
};
this.defs.appendChild(symbolNode);
return symbolNode;
},
/**
* Method: getFeatureIdFromEvent
*
* Parameters:
* evt - {Object} An <OpenLayers.Event> object
*
* Returns:
* {String} A feature id or undefined.
*/
getFeatureIdFromEvent: function(evt) {
var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
if(!featureId) {
var target = evt.target;
featureId = target.parentNode && target != this.rendererRoot ?
target.parentNode._featureId : undefined;
}
return featureId;
},
CLASS_NAME: "OpenLayers.Renderer.SVG2"
});
/**
* Constant: OpenLayers.Renderer.SVG2.LABEL_ALIGN
* {Object}
*/
OpenLayers.Renderer.SVG2.LABEL_ALIGN = {
"l": "start",
"r": "end",
"b": "bottom",
"t": "hanging"
};
/**
* Constant: OpenLayers.Renderer.SVG2.LABEL_VSHIFT
* {Object}
*/
OpenLayers.Renderer.SVG2.LABEL_VSHIFT = {
// according to
// http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
// a baseline-shift of -70% shifts the text exactly from the
// bottom to the top of the baseline, so -35% moves the text to
// the center of the baseline.
"t": "-70%",
"b": "0"
};
/**
* Constant: OpenLayers.Renderer.SVG2.LABEL_VFACTOR
* {Object}
*/
OpenLayers.Renderer.SVG2.LABEL_VFACTOR = {
"t": 0,
"b": -1
};
/**
* Function: OpenLayers.Renderer.SVG2.preventDefault
* Used to prevent default events (especially opening images in a new tab on
* ctrl-click) from being executed for externalGraphic and graphicName symbols
*/
OpenLayers.Renderer.SVG2.preventDefault = function(e) {
e.preventDefault && e.preventDefault();
};

View File

@@ -21,6 +21,7 @@
* @requires OpenLayers/Format/WKT.js
* @requires OpenLayers/Format/XML.js
* @requires OpenLayers/Geometry.js
* @requires OpenLayers/Renderer/Elements.js
*/
/**
@@ -4976,3 +4977,948 @@ OpenLayers.Geometry.Rectangle = OpenLayers.Class(OpenLayers.Geometry, {
CLASS_NAME: "OpenLayers.Geometry.Rectangle"
});
/**
* Class: OpenLayers.Renderer.NG
*
* Inherits from:
* - <OpenLayers.Renderer.Elements>
*/
OpenLayers.Renderer.NG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
/**
* Constant: labelNodeType
* {String} The node type for text label containers. To be defined by
* subclasses.
*/
labelNodeType: null,
/**
* Constructor: OpenLayers.Renderer.NG
*
* Parameters:
* containerID - {String}
* options - {Object} options for this renderer. Supported options are:
* * yOrdering - {Boolean} Whether to use y-ordering
* * zIndexing - {Boolean} Whether to use z-indexing. Will be ignored
* if yOrdering is set to true.
*/
/**
* Method: updateDimensions
* To be extended by subclasses - here we set positioning related styles
* on HTML elements, subclasses have to do the same for renderer specific
* elements (e.g. viewBox, width and height of the rendererRoot)
*
* Parameters:
* zoomChanged - {Boolean} Has the zoom changed? If so, subclasses may have
* to update feature styles/dimensions.
*/
updateDimensions: function(zoomChanged) {
var mapExtent = this.map.getExtent();
var renderExtent = mapExtent.scale(3);
this.setExtent(renderExtent, true);
var res = this.getResolution();
var div = this.rendererRoot.parentNode;
var layerLeft = parseFloat(div.parentNode.style.left);
var layerTop = parseFloat(div.parentNode.style.top);
div.style.left = ((renderExtent.left - mapExtent.left) / res - layerLeft) + "px";
div.style.top = ((mapExtent.top - renderExtent.top) / res - layerTop) + "px";
},
/**
* Method: resize
*/
setSize: function() {
this.map.getExtent() && this.updateDimensions();
},
/**
* Method: drawFeature
* Draw the feature. The optional style argument can be used
* to override the feature's own style. This method should only
* be called from layer.drawFeature().
*
* Parameters:
* feature - {<OpenLayers.Feature.Vector>}
* style - {<Object>}
*
* Returns:
* {Boolean} true if the feature has been drawn completely, false if not,
* undefined if the feature had no geometry
*/
drawFeature: function(feature, style) {
if(style == null) {
style = feature.style;
}
if (feature.geometry) {
var rendered = this.drawGeometry(feature.geometry, style, feature.id);
if(rendered !== false && style.label) {
var location = feature.geometry.getCentroid();
this.drawText(feature.id, style, location);
} else {
this.removeText(feature.id);
}
return rendered;
}
},
/**
* Method: drawText
* Function for drawing text labels.
* This method is only called by the renderer itself.
*
* Parameters:
* featureId - {String|DOMElement}
* style - {Object}
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
*
* Returns:
* {DOMElement} container holding the text label (to be populated by
* subclasses)
*/
drawText: function(featureId, style, location) {
var label;
if (typeof featureId !== "string") {
label = featureId;
} else {
label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, this.labelNodeType);
label._featureId = featureId;
}
label._style = style;
label._x = location.x;
label._y = location.y;
if(style.labelXOffset || style.labelYOffset) {
var xOffset = isNaN(style.labelXOffset) ? 0 : style.labelXOffset;
var yOffset = isNaN(style.labelYOffset) ? 0 : style.labelYOffset;
var res = this.getResolution();
location.move(xOffset*res, yOffset*res);
}
if(label.parentNode !== this.textRoot) {
this.textRoot.appendChild(label);
}
return label;
},
CLASS_NAME: "OpenLayers.Renderer.NG"
});
// Monkey-patching Layer.Vector for Renderer.NG support
(function() {
var moveTo = OpenLayers.Layer.Vector.prototype.moveTo;
OpenLayers.Layer.Vector.prototype.moveTo = function(bounds, zoomChanged, dragging) {
if (OpenLayers.Renderer.NG && this.renderer instanceof OpenLayers.Renderer.NG) {
OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
dragging || this.renderer.updateDimensions(zoomChanged);
if (!this.drawn) {
this.drawn = true;
var feature;
for(var i=0, len=this.features.length; i<len; i++) {
this.renderer.locked = (i !== (len - 1));
feature = this.features[i];
this.drawFeature(feature);
}
}
} else {
moveTo.apply(this, arguments);
}
}
var redraw = OpenLayers.Layer.Vector.prototype.redraw;
OpenLayers.Layer.Vector.prototype.redraw = function() {
if (OpenLayers.Renderer.NG && this.renderer instanceof OpenLayers.Renderer.NG) {
this.drawn = false;
}
redraw.apply(this, arguments);
}
})();
/**
* Class: OpenLayers.Renderer.SVG2
*
* Inherits from:
* - <OpenLayers.Renderer.NG>
*/
OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
/**
* Property: xmlns
* {String}
*/
xmlns: "http://www.w3.org/2000/svg",
/**
* Property: xlinkns
* {String}
*/
xlinkns: "http://www.w3.org/1999/xlink",
/**
* Property: symbolMetrics
* {Object} Cache for symbol metrics according to their svg coordinate
* space. This is an object keyed by the symbol's id, and values are
* an object with size, x and y properties.
*/
symbolMetrics: null,
/**
* Constant: labelNodeType
* {String} The node type for text label containers.
*/
labelNodeType: "g",
/**
* Constructor: OpenLayers.Renderer.SVG2
*
* Parameters:
* containerID - {String}
*/
initialize: function(containerID) {
if (!this.supported()) {
return;
}
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
arguments);
this.symbolMetrics = {};
},
/**
* APIMethod: supported
*
* Returns:
* {Boolean} Whether or not the browser supports the SVG renderer
*/
supported: function() {
var svgFeature = "http://www.w3.org/TR/SVG11/feature#";
return (document.implementation &&
(document.implementation.hasFeature("org.w3c.svg", "1.0") ||
document.implementation.hasFeature(svgFeature + "SVG", "1.1") ||
document.implementation.hasFeature(svgFeature + "BasicStructure", "1.1") ));
},
/**
* Method: updateDimensions
*
* Parameters:
* zoomChanged - {Boolean}
*/
updateDimensions: function(zoomChanged) {
OpenLayers.Renderer.NG.prototype.updateDimensions.apply(this, arguments);
var res = this.getResolution();
var width = this.extent.getWidth();
var height = this.extent.getHeight();
var extentString = [
this.extent.left,
-this.extent.top,
width,
height
].join(" ");
this.rendererRoot.setAttributeNS(null, "viewBox", extentString);
this.rendererRoot.setAttributeNS(null, "width", width / res);
this.rendererRoot.setAttributeNS(null, "height", height / res);
if (zoomChanged === true) {
// update styles for the new resolution
var i, len;
var nodes = this.vectorRoot.childNodes;
for (i=0, len=nodes.length; i<len; ++i) {
this.setStyle(nodes[i]);
}
var textNodes = this.textRoot.childNodes;
var label;
for (i=0, len=textNodes.length; i<len; ++i) {
label = textNodes[i];
this.drawText(label, label._style,
new OpenLayers.Geometry.Point(label._x, label._y)
);
}
}
},
/**
* Method: getNodeType
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
* style - {Object}
*
* Returns:
* {String} The corresponding node type for the specified geometry
*/
getNodeType: function(geometry, style) {
var nodeType = null;
switch (geometry.CLASS_NAME) {
case "OpenLayers.Geometry.Point":
if (style.externalGraphic) {
nodeType = "image";
} else if (this.isComplexSymbol(style.graphicName)) {
nodeType = "svg";
} else {
nodeType = "circle";
}
break;
case "OpenLayers.Geometry.Rectangle":
nodeType = "rect";
break;
case "OpenLayers.Geometry.LineString":
nodeType = "polyline";
break;
case "OpenLayers.Geometry.LinearRing":
nodeType = "polygon";
break;
case "OpenLayers.Geometry.Polygon":
case "OpenLayers.Geometry.Curve":
nodeType = "path";
break;
default:
break;
}
return nodeType;
},
/**
* Method: setStyle
* Use to set all the style attributes to a SVG node.
*
* Takes care to adjust stroke width and point radius to be
* resolution-relative
*
* Parameters:
* node - {SVGDomElement} An SVG element to decorate
* style - {Object}
* options - {Object} Currently supported options include
* 'isFilled' {Boolean} and
* 'isStroked' {Boolean}
*/
setStyle: function(node, style, options) {
style = style || node._style;
options = options || node._options;
var resolution = this.getResolution();
var r = node._radius;
var widthFactor = resolution;
if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
node.style.visibility = "";
if (style.graphic === false) {
node.style.visibility = "hidden";
} else if (style.externalGraphic) {
if (style.graphicTitle) {
node.setAttributeNS(null, "title", style.graphicTitle);
//Standards-conformant SVG
// Prevent duplicate nodes. See issue https://github.com/openlayers/openlayers/issues/92
var titleNode = node.getElementsByTagName("title");
if (titleNode.length > 0) {
titleNode[0].firstChild.textContent = style.graphicTitle;
} else {
var label = this.nodeFactory(null, "title");
label.textContent = style.graphicTitle;
node.appendChild(label);
}
}
if (style.graphicWidth && style.graphicHeight) {
node.setAttributeNS(null, "preserveAspectRatio", "none");
}
var width = style.graphicWidth || style.graphicHeight;
var height = style.graphicHeight || style.graphicWidth;
width = width ? width : style.pointRadius*2;
height = height ? height : style.pointRadius*2;
width *= resolution;
height *= resolution;
var xOffset = (style.graphicXOffset != undefined) ?
style.graphicXOffset * resolution : -(0.5 * width);
var yOffset = (style.graphicYOffset != undefined) ?
style.graphicYOffset * resolution : -(0.5 * height);
var opacity = style.graphicOpacity || style.fillOpacity;
node.setAttributeNS(null, "x", node._x + xOffset);
node.setAttributeNS(null, "y", node._y + yOffset);
node.setAttributeNS(null, "width", width);
node.setAttributeNS(null, "height", height);
node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
node.setAttributeNS(null, "style", "opacity: "+opacity);
node.onclick = OpenLayers.Renderer.SVG2.preventDefault;
} else if (this.isComplexSymbol(style.graphicName)) {
// the symbol viewBox is three times as large as the symbol
var offset = style.pointRadius * 3 * resolution;
var size = offset * 2;
var src = this.importSymbol(style.graphicName);
widthFactor = this.symbolMetrics[src.id].size * 3 / size * resolution;
// remove the node from the dom before we modify it. This
// prevents various rendering issues in Safari and FF
var parent = node.parentNode;
var nextSibling = node.nextSibling;
if(parent) {
parent.removeChild(node);
}
// The more appropriate way to implement this would be use/defs,
// but due to various issues in several browsers, it is safer to
// copy the symbols instead of referencing them.
// See e.g. ticket http://trac.osgeo.org/openlayers/ticket/2985
// and this email thread
// http://osgeo-org.1803224.n2.nabble.com/Select-Control-Ctrl-click-on-Feature-with-a-graphicName-opens-new-browser-window-tc5846039.html
node.firstChild && node.removeChild(node.firstChild);
node.appendChild(src.firstChild.cloneNode(true));
node.setAttributeNS(null, "viewBox", src.getAttributeNS(null, "viewBox"));
node.setAttributeNS(null, "width", size);
node.setAttributeNS(null, "height", size);
node.setAttributeNS(null, "x", node._x - offset);
node.setAttributeNS(null, "y", node._y - offset);
// now that the node has all its new properties, insert it
// back into the dom where it was
if(nextSibling) {
parent.insertBefore(node, nextSibling);
} else if(parent) {
parent.appendChild(node);
}
} else {
node.setAttributeNS(null, "r", style.pointRadius * resolution);
}
var rotation = style.rotation;
if (rotation !== undefined || node._rotation !== undefined) {
node._rotation = rotation;
rotation |= 0;
if (node.nodeName !== "svg") {
node.setAttributeNS(null, "transform",
["rotate(", rotation, node._x, node._y, ")"].join(" ")
);
} else {
var metrics = this.symbolMetrics[src.id];
node.firstChild.setAttributeNS(null, "transform",
["rotate(", rotation, metrics.x, metrics.y, ")"].join(" ")
);
}
}
}
if (options.isFilled) {
node.setAttributeNS(null, "fill", style.fillColor);
node.setAttributeNS(null, "fill-opacity", style.fillOpacity);
} else {
node.setAttributeNS(null, "fill", "none");
}
if (options.isStroked) {
node.setAttributeNS(null, "stroke", style.strokeColor);
node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap || "round");
// Hard-coded linejoin for now, to make it look the same as in VML.
// There is no strokeLinejoin property yet for symbolizers.
node.setAttributeNS(null, "stroke-linejoin", "round");
style.strokeDashstyle && node.setAttributeNS(null,
"stroke-dasharray", this.dashStyle(style, widthFactor));
} else {
node.setAttributeNS(null, "stroke", "none");
}
if (style.pointerEvents) {
node.setAttributeNS(null, "pointer-events", style.pointerEvents);
}
if (style.cursor != null) {
node.setAttributeNS(null, "cursor", style.cursor);
}
return node;
},
/**
* Method: dashStyle
*
* Parameters:
* style - {Object}
* widthFactor - {Number}
*
* Returns:
* {String} A SVG compliant 'stroke-dasharray' value
*/
dashStyle: function(style, widthFactor) {
var w = style.strokeWidth * widthFactor;
var str = style.strokeDashstyle;
switch (str) {
case 'solid':
return 'none';
case 'dot':
return [widthFactor, 4 * w].join();
case 'dash':
return [4 * w, 4 * w].join();
case 'dashdot':
return [4 * w, 4 * w, widthFactor, 4 * w].join();
case 'longdash':
return [8 * w, 4 * w].join();
case 'longdashdot':
return [8 * w, 4 * w, widthFactor, 4 * w].join();
default:
var parts = OpenLayers.String.trim(str).split(/\s+/g);
for (var i=0, ii=parts.length; i<ii; i++) {
parts[i] = parts[i] * widthFactor;
}
return parts.join();
}
},
/**
* Method: createNode
*
* Parameters:
* type - {String} Kind of node to draw
* id - {String} Id for node
*
* Returns:
* {DOMElement} A new node of the given type and id
*/
createNode: function(type, id) {
var node = document.createElementNS(this.xmlns, type);
if (id) {
node.setAttributeNS(null, "id", id);
}
return node;
},
/**
* Method: nodeTypeCompare
*
* Parameters:
* node - {SVGDomElement} An SVG element
* type - {String} Kind of node
*
* Returns:
* {Boolean} Whether or not the specified node is of the specified type
*/
nodeTypeCompare: function(node, type) {
return (type == node.nodeName);
},
/**
* Method: createRenderRoot
*
* Returns:
* {DOMElement} The specific render engine's root element
*/
createRenderRoot: function() {
return this.nodeFactory(this.container.id + "_svgRoot", "svg");
},
/**
* Method: createRoot
*
* Parameters:
* suffix - {String} suffix to append to the id
*
* Returns:
* {DOMElement}
*/
createRoot: function(suffix) {
return this.nodeFactory(this.container.id + suffix, "g");
},
/**
* Method: createDefs
*
* Returns:
* {DOMElement} The element to which we'll add the symbol definitions
*/
createDefs: function() {
var defs = this.nodeFactory(this.container.id + "_defs", "defs");
this.rendererRoot.appendChild(defs);
return defs;
},
/**************************************
* *
* GEOMETRY DRAWING FUNCTIONS *
* *
**************************************/
/**
* Method: drawPoint
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the point
*/
drawPoint: function(node, geometry) {
return this.drawCircle(node, geometry, 1);
},
/**
* Method: drawCircle
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* radius - {Float}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the circle
*/
drawCircle: function(node, geometry, radius) {
var x = geometry.x;
var y = -geometry.y;
node.setAttributeNS(null, "cx", x);
node.setAttributeNS(null, "cy", y);
node._x = x;
node._y = y;
node._radius = radius;
return node;
},
/**
* Method: drawLineString
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components of
* the linestring, or false if nothing could be drawn
*/
drawLineString: function(node, geometry) {
var path = this.getComponentsString(geometry.components);
node.setAttributeNS(null, "points", path);
return node;
},
/**
* Method: drawLinearRing
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the linear ring, or false if nothing could be drawn
*/
drawLinearRing: function(node, geometry) {
var path = this.getComponentsString(geometry.components);
node.setAttributeNS(null, "points", path);
return node;
},
/**
* Method: drawPolygon
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or null if the renderer could not draw all components
* of the polygon, or false if nothing could be drawn
*/
drawPolygon: function(node, geometry) {
var d = [];
var draw = true;
var complete = true;
var linearRingResult, path;
for (var j=0, len=geometry.components.length; j<len; j++) {
d.push("M");
path = this.getComponentsString(
geometry.components[j].components, " ");
d.push(path);
}
d.push("z");
node.setAttributeNS(null, "d", d.join(" "));
node.setAttributeNS(null, "fill-rule", "evenodd");
return node;
},
/**
* Method: drawRectangle
* This method is only called by the renderer itself.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*
* Returns:
* {DOMElement} or false if the renderer could not draw the rectangle
*/
drawRectangle: function(node, geometry) {
node.setAttributeNS(null, "x", geometry.x);
node.setAttributeNS(null, "y", -geometry.y);
node.setAttributeNS(null, "width", geometry.width);
node.setAttributeNS(null, "height", geometry.height);
return node;
},
/**
* Method: drawText
* Function for drawing text labels.
* This method is only called by the renderer itself.
*
* Parameters:
* featureId - {String|DOMElement}
* style - {Object}
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
*
* Returns:
* {DOMElement} container holding the text label
*/
drawText: function(featureId, style, location) {
var g = OpenLayers.Renderer.NG.prototype.drawText.apply(this, arguments);
var text = g.firstChild ||
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_text", "text");
var res = this.getResolution();
text.setAttributeNS(null, "x", location.x / res);
text.setAttributeNS(null, "y", - location.y / res);
g.setAttributeNS(null, "transform", "scale(" + res + ")");
if (style.fontColor) {
text.setAttributeNS(null, "fill", style.fontColor);
}
if (style.fontOpacity) {
text.setAttributeNS(null, "opacity", style.fontOpacity);
}
if (style.fontFamily) {
text.setAttributeNS(null, "font-family", style.fontFamily);
}
if (style.fontSize) {
text.setAttributeNS(null, "font-size", style.fontSize);
}
if (style.fontWeight) {
text.setAttributeNS(null, "font-weight", style.fontWeight);
}
if (style.fontStyle) {
text.setAttributeNS(null, "font-style", style.fontStyle);
}
if (style.labelSelect === true) {
text.setAttributeNS(null, "pointer-events", "visible");
text._featureId = featureId;
} else {
text.setAttributeNS(null, "pointer-events", "none");
}
var align = style.labelAlign || OpenLayers.Renderer.defaultSymbolizer.labelAlign;
text.setAttributeNS(null, "text-anchor",
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[0]] || "middle");
if (OpenLayers.IS_GECKO === true) {
text.setAttributeNS(null, "dominant-baseline",
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[1]] || "central");
}
var labelRows = style.label.split('\n');
var numRows = labelRows.length;
while (text.childNodes.length > numRows) {
text.removeChild(text.lastChild);
}
for (var i = 0; i < numRows; i++) {
var tspan = text.childNodes[i] ||
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_" + i, "tspan");
if (style.labelSelect === true) {
tspan._featureId = featureId;
}
if (OpenLayers.IS_GECKO === false) {
tspan.setAttributeNS(null, "baseline-shift",
OpenLayers.Renderer.SVG2.LABEL_VSHIFT[align[1]] || "-35%");
}
tspan.setAttribute("x", location.x / res);
if (i == 0) {
var vfactor = OpenLayers.Renderer.SVG2.LABEL_VFACTOR[align[1]];
if (vfactor == null) {
vfactor = -.5;
}
tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em");
} else {
tspan.setAttribute("dy", "1em");
}
tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i];
if (!tspan.parentNode) {
text.appendChild(tspan);
}
}
if (!text.parentNode) {
g.appendChild(text);
}
return g;
},
/**
* Method: getComponentString
*
* Parameters:
* components - {Array(<OpenLayers.Geometry.Point>)} Array of points
* separator - {String} character between coordinate pairs. Defaults to ","
*
* Returns:
* {Object} hash with properties "path" (the string created from the
* components and "complete" (false if the renderer was unable to
* draw all components)
*/
getComponentsString: function(components, separator) {
var len = components.length;
var strings = new Array(len);
for (var i=0; i<len; i++) {
strings[i] = this.getShortString(components[i]);
}
return strings.join(separator || ",");
},
/**
* Method: getShortString
*
* Parameters:
* point - {<OpenLayers.Geometry.Point>}
*
* Returns:
* {String} or false if point is outside the valid range
*/
getShortString: function(point) {
return point.x + "," + (-point.y);
},
/**
* Method: importSymbol
* add a new symbol definition from the rendererer's symbol hash
*
* Parameters:
* graphicName - {String} name of the symbol to import
*
* Returns:
* {DOMElement} - the imported symbol
*/
importSymbol: function (graphicName) {
if (!this.defs) {
// create svg defs tag
this.defs = this.createDefs();
}
var id = this.container.id + "-" + graphicName;
// check if symbol already exists in the defs
var existing = document.getElementById(id);
if (existing != null) {
return existing;
}
var symbol = OpenLayers.Renderer.symbol[graphicName];
if (!symbol) {
throw new Error(graphicName + ' is not a valid symbol name');
}
var symbolNode = this.nodeFactory(id, "symbol");
var node = this.nodeFactory(null, "polygon");
symbolNode.appendChild(node);
var symbolExtent = new OpenLayers.Bounds(
Number.MAX_VALUE, Number.MAX_VALUE, 0, 0);
var points = [];
var x,y;
for (var i=0, len=symbol.length; i<len; i=i+2) {
x = symbol[i];
y = symbol[i+1];
symbolExtent.left = Math.min(symbolExtent.left, x);
symbolExtent.bottom = Math.min(symbolExtent.bottom, y);
symbolExtent.right = Math.max(symbolExtent.right, x);
symbolExtent.top = Math.max(symbolExtent.top, y);
points.push(x, ",", y);
}
node.setAttributeNS(null, "points", points.join(" "));
var width = symbolExtent.getWidth();
var height = symbolExtent.getHeight();
// create a viewBox three times as large as the symbol itself,
// to allow for strokeWidth being displayed correctly at the corners.
var viewBox = [symbolExtent.left - width,
symbolExtent.bottom - height, width * 3, height * 3];
symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" "));
this.symbolMetrics[id] = {
size: Math.max(width, height),
x: symbolExtent.getCenterLonLat().lon,
y: symbolExtent.getCenterLonLat().lat
};
this.defs.appendChild(symbolNode);
return symbolNode;
},
/**
* Method: getFeatureIdFromEvent
*
* Parameters:
* evt - {Object} An <OpenLayers.Event> object
*
* Returns:
* {String} A feature id or undefined.
*/
getFeatureIdFromEvent: function(evt) {
var featureId = OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this, arguments);
if(!featureId) {
var target = evt.target;
featureId = target.parentNode && target != this.rendererRoot ?
target.parentNode._featureId : undefined;
}
return featureId;
},
CLASS_NAME: "OpenLayers.Renderer.SVG2"
});
/**
* Constant: OpenLayers.Renderer.SVG2.LABEL_ALIGN
* {Object}
*/
OpenLayers.Renderer.SVG2.LABEL_ALIGN = {
"l": "start",
"r": "end",
"b": "bottom",
"t": "hanging"
};
/**
* Constant: OpenLayers.Renderer.SVG2.LABEL_VSHIFT
* {Object}
*/
OpenLayers.Renderer.SVG2.LABEL_VSHIFT = {
// according to
// http://www.w3.org/Graphics/SVG/Test/20061213/htmlObjectHarness/full-text-align-02-b.html
// a baseline-shift of -70% shifts the text exactly from the
// bottom to the top of the baseline, so -35% moves the text to
// the center of the baseline.
"t": "-70%",
"b": "0"
};
/**
* Constant: OpenLayers.Renderer.SVG2.LABEL_VFACTOR
* {Object}
*/
OpenLayers.Renderer.SVG2.LABEL_VFACTOR = {
"t": 0,
"b": -1
};
/**
* Function: OpenLayers.Renderer.SVG2.preventDefault
* Used to prevent default events (especially opening images in a new tab on
* ctrl-click) from being executed for externalGraphic and graphicName symbols
*/
OpenLayers.Renderer.SVG2.preventDefault = function(e) {
e.preventDefault && e.preventDefault();
};

View File

@@ -248,6 +248,8 @@ A number of properties, methods, and constructors have been marked as deprecated
* OpenLayers.Layer.Yahoo
* OpenLayers.Layer.GML
* OpenLayers.Geometry.Rectangle
* OpenLayers.Renderer.NG
* OpenLayers.Renderer.SVG2
In addition, OpenLayers no longer modifies any native prototypes or objects by default. If you rely on any of the following, you'll need to include deprecated.js explicitly to get the same behavior.

View File

@@ -723,54 +723,6 @@
(-y + customStyle6.graphicYOffset).toFixed().toString(),
"graphicYOffset correctly set");
}
if (layer.renderer.CLASS_NAME == 'OpenLayers.Renderer.SVG2') {
feature.style = customStyle1;
layer.drawFeature(feature);
var resolution = map.getResolution();
t.eq(root.firstChild.getAttributeNS(null, 'width'),
(2*customStyle1.pointRadius*resolution).toString(),
"given a pointRadius, width equals 2*pointRadius");
t.eq(root.firstChild.getAttributeNS(null, 'height'),
(2*customStyle1.pointRadius*resolution).toString(),
"given a pointRadius, height equals 2*pointRadius");
feature.style = customStyle2;
layer.drawFeature(feature);
t.eq(root.firstChild.getAttributeNS(null, 'width'),
root.firstChild.getAttributeNS(null, 'height'),
"given a graphicWidth, width equals height");
t.eq(root.firstChild.getAttributeNS(null, 'width'),
(customStyle2.graphicWidth*resolution).toString(),
"width is set correctly");
feature.style = customStyle3;
layer.drawFeature(feature);
t.eq(root.firstChild.getAttributeNS(null, 'height'),
root.firstChild.getAttributeNS(null, 'width'),
"given a graphicHeight, height equals width");
t.eq(root.firstChild.getAttributeNS(null, 'height'),
(customStyle3.graphicHeight*resolution).toString(),
"height is set correctly");
feature.style = customStyle4;
layer.drawFeature(feature);
t.eq(root.firstChild.getAttributeNS(null, 'height'),
(customStyle4.graphicHeight*resolution).toString(),
"given graphicHeight and graphicWidth, both are set: height");
t.eq(root.firstChild.getAttributeNS(null, 'width'),
(customStyle4.graphicWidth*resolution).toString(),
"given graphicHeight and graphicWidth, both are set: width");
feature.style = customStyle5;
layer.drawFeature(feature);
t.eq(root.firstChild.getAttributeNS(null, 'style'),
'opacity: '+customStyle5.graphicOpacity.toString()+((OpenLayers.Util.getBrowserName() == "opera" || OpenLayers.Util.getBrowserName() == "safari") ? "" : ';'),
"graphicOpacity correctly set");
feature.style = customStyle6;
layer.drawFeature(feature);
t.eq(root.firstChild.getAttributeNS(null, 'x'),
(geometryX + customStyle6.graphicXOffset*resolution).toString(),
"graphicXOffset correctly set");
t.eq(root.firstChild.getAttributeNS(null, 'y'),
(-geometryY + customStyle6.graphicYOffset*resolution).toString(),
"graphicYOffset correctly set");
}
if (layer.renderer.CLASS_NAME == 'OpenLayers.Renderer.VML') {
feature.style = customStyle1;
layer.drawFeature(feature);

View File

@@ -1,6 +1,7 @@
<html>
<head>
<script src="../OLLoader.js"></script>
<script src="../../OLLoader.js"></script>
<script src="../../../lib/deprecated.js"></script>
<script type="text/javascript">
var geometry = null, node = null;

View File

@@ -202,7 +202,6 @@
<li>Renderer/Canvas.html</li>
<li>Renderer/Elements.html</li>
<li>Renderer/SVG.html</li>
<li>Renderer/SVG2.html</li>
<li>Renderer/VML.html</li>
<li>Request.html</li>
<li>Request/XMLHttpRequest.html</li>
@@ -245,6 +244,7 @@
<li>deprecated/Layer/WMS/Post.html</li>
<li>deprecated/Protocol/SQL.html</li>
<li>deprecated/Protocol/SQL/Gears.html</li>
<li>deprecated/Renderer/SVG2.html</li>
<li>deprecated/Layer/Yahoo.html</li>
<li>deprecated/Tile/WFS.html</li>
</ul>

View File

@@ -1,50 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >
<link rel="stylesheet" href="../../theme/default/style.css" type="text/css" />
<style type="text/css">
#map {
width: 512px;
height: 512px;
border: 1px solid gray;
}
</style>
<title>SVG2 coordinate range check</title>
<script type="text/javascript" src="../../lib/OpenLayers.js"></script>
<script>
var WGS84 = new OpenLayers.Projection("EPSG:4326");
var Mercator = new OpenLayers.Projection("EPSG:900913");
var wkt = new OpenLayers.Format.WKT({ internalProjection: Mercator, externalProjection: WGS84 });
function init() {
var externalGraphic, baseURL, baseLayer, layerOptions, hidemessenger;
var map = new OpenLayers.Map('map', {
controls: [
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoom(),
new OpenLayers.Control.Attribution()
],
theme: null
});
baseLayer = new OpenLayers.Layer.OSM("OSM");
var viewLayer = new OpenLayers.Layer.Vector("View Layer", {renderers: ["SVG2"]});
map.addLayers([baseLayer, viewLayer]);
viewLayer.addFeatures([wkt.read("LINESTRING(2.4356174739332 48.816618174539, 2.4313688548536 48.826083884311)")]);
var lonLat = new OpenLayers.LonLat( 2.43686, 48.81742) .transform( WGS84, Mercator);
map.setCenter (lonLat, 16);
}
</script>
<body onload="init()">
<div id="map"></div>
<p>The map should show a line on top of the OSM layer. If it does not, then
either the CSS or the SVG coordinate range is exceeded.</p>
<p>This test only works on browsers that support SVG.</p>
</body>
</html>