From 420a6f4dd28c6158af82a4002f8eaa6285fe2ec5 Mon Sep 17 00:00:00 2001 From: fredj Date: Tue, 14 Feb 2012 15:09:39 +0100 Subject: [PATCH] Move SVG2 renderer to deprecated.js --- apidoc_config/Menu.txt | 1 - doc_config/Menu.txt | 1 - lib/OpenLayers.js | 1 - lib/OpenLayers/Renderer/SVG2.js | 797 ---------------------- lib/deprecated.js | 790 +++++++++++++++++++++ tests/Layer/Vector.html | 48 -- tests/{ => deprecated}/Renderer/SVG2.html | 3 +- tests/list-tests.html | 2 +- tests/manual/svg2-coordinaterange.html | 50 -- 9 files changed, 793 insertions(+), 900 deletions(-) delete mode 100644 lib/OpenLayers/Renderer/SVG2.js rename tests/{ => deprecated}/Renderer/SVG2.html (99%) delete mode 100644 tests/manual/svg2-coordinaterange.html diff --git a/apidoc_config/Menu.txt b/apidoc_config/Menu.txt index e372a59b09..4f5bde35ce 100644 --- a/apidoc_config/Menu.txt +++ b/apidoc_config/Menu.txt @@ -411,7 +411,6 @@ Group: OpenLayers { 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 diff --git a/doc_config/Menu.txt b/doc_config/Menu.txt index edbae8e2e8..411a903e8f 100644 --- a/doc_config/Menu.txt +++ b/doc_config/Menu.txt @@ -411,7 +411,6 @@ Group: OpenLayers { 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 diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index 749a14f027..a33dd25e9b 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -259,7 +259,6 @@ "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", diff --git a/lib/OpenLayers/Renderer/SVG2.js b/lib/OpenLayers/Renderer/SVG2.js deleted file mode 100644 index 3f64c50ca8..0000000000 --- a/lib/OpenLayers/Renderer/SVG2.js +++ /dev/null @@ -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.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} - * 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} - * - * 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 - {} - * 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 - {} - * - * 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 - {} - * - * 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 - {} - * - * 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} - * - * 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 - {}, 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()} 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} - * - * 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 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(); -}; diff --git a/lib/deprecated.js b/lib/deprecated.js index c22b849216..40333c185c 100644 --- a/lib/deprecated.js +++ b/lib/deprecated.js @@ -21,6 +21,7 @@ * @requires OpenLayers/Format/WKT.js * @requires OpenLayers/Format/XML.js * @requires OpenLayers/Geometry.js + * @requires OpenLayers/Renderer/NG.js */ /** @@ -4976,3 +4977,792 @@ OpenLayers.Geometry.Rectangle = OpenLayers.Class(OpenLayers.Geometry, { CLASS_NAME: "OpenLayers.Geometry.Rectangle" }); + +/** + * Class: OpenLayers.Renderer.SVG2 + * + * Inherits from: + * - + */ +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} + * 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} + * + * 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 - {} + * 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 - {} + * + * 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 - {} + * + * 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 - {} + * + * 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} + * + * 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 - {}, 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()} 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} + * + * 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 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(); +}; diff --git a/tests/Layer/Vector.html b/tests/Layer/Vector.html index fa2aff1471..160f2314d7 100644 --- a/tests/Layer/Vector.html +++ b/tests/Layer/Vector.html @@ -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); diff --git a/tests/Renderer/SVG2.html b/tests/deprecated/Renderer/SVG2.html similarity index 99% rename from tests/Renderer/SVG2.html rename to tests/deprecated/Renderer/SVG2.html index 6ee12ee9b6..c23b95c210 100644 --- a/tests/Renderer/SVG2.html +++ b/tests/deprecated/Renderer/SVG2.html @@ -1,6 +1,7 @@ - + + - - - -
-

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.

-

This test only works on browsers that support SVG.

- -