From 73fe6380c7b131aa1f6285646a8ac25762066af2 Mon Sep 17 00:00:00 2001 From: crschmidt Date: Sat, 1 Dec 2007 22:57:58 +0000 Subject: [PATCH] Fixes and performance improvements to VML renderer problems with externalGraphic, diligently filed, investigated, and fixed by The great and powerful Oz, er, Andreas, who is becoming my new vector rendering hero. (Closes #1172) git-svn-id: http://svn.openlayers.org/trunk/openlayers@5323 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- lib/OpenLayers/Renderer/Elements.js | 26 ++++++--- lib/OpenLayers/Renderer/SVG.js | 18 ++---- lib/OpenLayers/Renderer/VML.js | 86 +++++++++++++++++------------ 3 files changed, 73 insertions(+), 57 deletions(-) diff --git a/lib/OpenLayers/Renderer/Elements.js b/lib/OpenLayers/Renderer/Elements.js index 3572ddbf31..63912fe88f 100644 --- a/lib/OpenLayers/Renderer/Elements.js +++ b/lib/OpenLayers/Renderer/Elements.js @@ -84,19 +84,20 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { /** * Method: getNodeType * This function is in charge of asking the specific renderer which type - * of node to create for the given geometry. All geometries in an - * Elements-based renderer consist of one node and some attributes. We - * have the nodeFactory() function which creates a node for us, but it - * takes a 'type' as input, and that is precisely what this function - * tells us. + * of node to create for the given geometry and style. All geometries + * in an Elements-based renderer consist of one node and some + * attributes. We have the nodeFactory() function which creates a node + * for us, but it takes a 'type' as input, and that is precisely what + * this function tells us. * * Parameters: * geometry - {} + * style - {Object} * * Returns: * {String} The corresponding node type for the specified geometry */ - getNodeType: function(geometry) { }, + getNodeType: function(geometry, style) { }, /** * Method: drawGeometry @@ -122,7 +123,7 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { }; //first we create the basic node and add it to the root - var nodeType = this.getNodeType(geometry); + var nodeType = this.getNodeType(geometry, style); var node = this.nodeFactory(geometry.id, nodeType); node._featureId = featureId; node._geometryClass = geometry.CLASS_NAME; @@ -131,6 +132,7 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { //now actually draw the node, and style it node = this.drawGeometryNode(node, geometry); this.root.appendChild(node); + this.postDraw(node); }, /** @@ -183,6 +185,16 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { return this.setStyle(node, style, options, geometry); }, + /** + * Method: postDraw + * Things that have do be done after the geometry node is appended + * to its parent node. To be overridden by subclasses. + * + * Parameters: + * node - {DOMElement} + */ + postDraw: function(node) {}, + /** * Method: drawPoint * Virtual function for drawing Point Geometry. diff --git a/lib/OpenLayers/Renderer/SVG.js b/lib/OpenLayers/Renderer/SVG.js index 790fde4943..555ccdf77e 100644 --- a/lib/OpenLayers/Renderer/SVG.js +++ b/lib/OpenLayers/Renderer/SVG.js @@ -147,15 +147,16 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { * * Parameters: * geometry - {} + * style - {Object} * * Returns: * {String} The corresponding node type for the specified geometry */ - getNodeType: function(geometry) { + getNodeType: function(geometry, style) { var nodeType = null; switch (geometry.CLASS_NAME) { case "OpenLayers.Geometry.Point": - nodeType = "circle"; + nodeType = style.externalGraphic ? "image" : "circle"; break; case "OpenLayers.Geometry.Rectangle": nodeType = "rect"; @@ -196,21 +197,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { options = options || node._options; if (node._geometryClass == "OpenLayers.Geometry.Point") { if (style.externalGraphic) { - // remove old node - var id = node.getAttributeNS(null, "id"); var x = parseFloat(node.getAttributeNS(null, "cx")); var y = parseFloat(node.getAttributeNS(null, "cy")); - var _featureId = node._featureId; - var _geometryClass = node._geometryClass; - var _style = node._style; - // create new image node - node = this.createNode("image", id); - node._featureId = _featureId; - node._geometryClass = _geometryClass; - node._style = _style; - - // now style the new node if (style.graphicWidth && style.graphicHeight) { node.setAttributeNS(null, "preserveAspectRatio", "none"); } @@ -222,6 +211,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { style.graphicXOffset : -(0.5 * width); var yOffset = (style.graphicYOffset != undefined) ? style.graphicYOffset : -(0.5 * height); + var opacity = style.graphicOpacity || style.fillOpacity; node.setAttributeNS(null, "x", (x + xOffset).toFixed()); diff --git a/lib/OpenLayers/Renderer/VML.js b/lib/OpenLayers/Renderer/VML.js index 7d705c0e4d..9e09609c02 100644 --- a/lib/OpenLayers/Renderer/VML.js +++ b/lib/OpenLayers/Renderer/VML.js @@ -105,19 +105,20 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { /** * Method: getNodeType - * Get the noode type for a geometry + * Get the noode type for a geometry and style * * Parameters: * geometry - {} + * style - {Object} * * Returns: * {String} The corresponding node type for the specified geometry */ - getNodeType: function(geometry) { + getNodeType: function(geometry, style) { var nodeType = null; switch (geometry.CLASS_NAME) { case "OpenLayers.Geometry.Point": - nodeType = "v:oval"; + nodeType = style.externalGraphic ? "v:rect" : "v:oval"; break; case "OpenLayers.Geometry.Rectangle": nodeType = "v:rect"; @@ -153,29 +154,6 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { if (node._geometryClass == "OpenLayers.Geometry.Point") { if (style.externalGraphic) { - // remove old node - var id = node.id; - var _featureId = node._featureId; - var _geometryClass = node._geometryClass; - var _style = node._style; - - // create new image node - node = this.createNode("v:rect", id); - var fill = this.createNode("v:fill", id+"_image"); - node.appendChild(fill); - node._featureId = _featureId; - node._geometryClass = _geometryClass; - node._style = _style; - - fill.src = style.externalGraphic; - fill.type = "frame"; - node.style.flip = "y"; - - if (!(style.graphicWidth && style.graphicHeight)) { - fill.aspect = "atmost"; - } - - // now style the new node var width = style.graphicWidth || style.graphicHeight; var height = style.graphicHeight || style.graphicWidth; width = width ? width : style.pointRadius*2; @@ -192,9 +170,9 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { node.style.width = width; node.style.height = height; - // modify fill style for rect styling below + // modify style/options for fill and stroke styling below style.fillColor = "none"; - style.strokeColor = "none"; + options.isStroked = false; } else { this.drawCircle(node, geometry, style.pointRadius); @@ -216,16 +194,29 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { } else { if (!fill) { fill = this.createNode('v:fill', node.id + "_fill"); + + if (style.fillOpacity) { + fill.setAttribute("opacity", style.fillOpacity); + } + + if (node._geometryClass == "OpenLayers.Geometry.Point" && + style.externalGraphic) { + + // override fillOpacity + if (style.graphicOpacity) { + fill.setAttribute("opacity", style.graphicOpacity); + } + + fill.setAttribute("src", style.externalGraphic); + fill.setAttribute("type", "frame"); + node.style.flip = "y"; + + if (!(style.graphicWidth && style.graphicHeight)) { + fill.aspect = "atmost"; + } + } node.appendChild(fill); } - // if graphicOpacity is set use it in priority for external graphic - if (node._geometryClass == "OpenLayers.Geometry.Point" && - style.externalGraphic && - style.graphicOpacity) { - fill.setAttribute("opacity", style.graphicOpacity); - } else if (style.fillOpacity) { - fill.setAttribute("opacity", style.fillOpacity); - } } @@ -257,6 +248,29 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { return node; }, + /** + * Method: postDraw + * Some versions of Internet Explorer seem to be unable to set fillcolor + * and strokecolor to "none" correctly before the fill node is appended to + * a visible vml node. This method takes care of that and sets fillcolor + * and strokecolor again if needed. + * + * Parameters: + * node - {DOMElement} + */ + postDraw: function(node) { + var fillColor = node._style.fillColor; + var strokeColor = node._style.strokeColor; + if (fillColor == "none" && + node.getAttribute("fillcolor") != fillColor) { + node.setAttribute("fillcolor", fillColor); + } + if (strokeColor == "none" && + node.getAttribute("strokecolor") != strokeColor) { + node.setAttribute("strokecolor", strokeColor) + } + }, + /** * Method: setNodeDimension