I posted on this last month but i didnt get any response so i went ahead anyways. Now what i put together is only a first pass of sorts and is a little crude in places but i was hoping that someone here could have a look at it and tell me if it could be used within openlayers as i dont want to have to continually be updating it myself. Of course you may not like the way i went about it or have no plans to implement text rendering.
Using openlayers 2.5 stable, I created a patch for this version if anyone wants to have a look. The patch is called patch.txt and is attached to this mail. So run "patch -p0 < ../patch.txt" to update. Just a few quick points and issues i had. One reason to get text rendering working for example was, i needed to be able to output the names of certain hospitals on a map centered on there point on the map. Firstly i have "extractAttributes: true" and added an layer option called "textAttrToDisplay" which is the name of the attribute to be displayed within each feature that was coming from my database. Now biggest issue i had was in svg the text was rendering upside down due to the "transform scale(1,-1)" and so i just created a 2nd root node called textroot which i appended to the renderedRoot and added all text nodes to it instead. Of course this wasn't an issue in vml. Is there a better way ? I tried finding a quick example that you could quickly test this out on yourselves, but all the wfs examples i looked at in openlayers did not return any other data except there co-ordinates, but i assume a number of ye would be able to get it running quickly with your own local datasets. So as an example of its use, say this is some of the data returned from my database, <gml:featureMember> <fs:hospital fid="1"> <fs:geometry> <gml:Point> <gml:coordinates>99771.29,47991.03</gml:coordinates> </gml:Point> </fs:geometry> <fs:hospname>Bantry</fs:hospname> <fs:county>Co Cork</fs:county> <fs:he_admin_area>South</fs:he_admin_area> <fs:address>Bantry</fs:address> <fs:recordno>21</fs:recordno> <fs:regionname>Region 2</fs:regionname> </fs:hospital> </gml:featureMember> And i wanted to display the hospital name, i would add textAttrToDisplay as an option to the layer with the value hospname. var lOptions = { extractAttributes: true, textAttrToDisplay : 'hospname' } layer2 = new OpenLayers.Layer.WFS( "Hospital", "http://localhost/~dave/featureserver/featureserver.cgi/hospital?format=WFS", { maxfeatures:10}, lOptions); map.addLayer(layer2); Just looking for a bit of advice on this. Am i going about it the right way, and could i eventually submit this, so i wouldn't have to maintain it with with each update to openlayers itself. Thanks
Index: lib/OpenLayers/Renderer.js =================================================================== --- lib/OpenLayers/Renderer.js (.../tags/2.5) (revision 8852) +++ lib/OpenLayers/Renderer.js (.../branches/textnode) (working copy) @@ -135,17 +135,39 @@ * * Parameters: * feature - {<OpenLayers.Feature.Vector>} - * style - {<Object>} + * style - {<Object>} + * attr - {String} */ - drawFeature: function(feature, style) { + drawFeature: function(feature, style, attr) { if(style == null) { style = feature.style; } this.drawGeometry(feature.geometry, style, feature.id); + + //check if an text attribute name has been passed in the wfs layer options + var attrName = feature.layer.options.textAttrToDisplay + //if so and extractAttributes is true then render the text attributer associated with that geometry + if(feature.layer.options.extractAttributes==true && feature.attributes[attrName]) + { + style = OpenLayers.Feature.Vector.style['text']; + featuretext = feature.attributes[attrName]; + this.drawGeometryText(feature.geometry, style, feature.id, featuretext); + } }, /** + * Method: drawGeometryText + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * style - {Object} + * featureId - {<String>} + * featuretext - {<String>} + */ + drawGeometryText: function(geometry, style, featureId,featuretext) {}, + + /** * Method: drawGeometry * * Draw a geometry. This should only be called from the renderer itself. Index: lib/OpenLayers/Feature/Vector.js =================================================================== --- lib/OpenLayers/Feature/Vector.js (.../tags/2.5) (revision 8852) +++ lib/OpenLayers/Feature/Vector.js (.../branches/textnode) (working copy) @@ -318,5 +318,8 @@ hoverPointRadius: 1, hoverPointUnit: "%", pointerEvents: "visiblePainted" + }, + 'text': { + fillColor: "red" } }; Index: lib/OpenLayers/Renderer/Elements.js =================================================================== --- lib/OpenLayers/Renderer/Elements.js (.../tags/2.5) (revision 8852) +++ lib/OpenLayers/Renderer/Elements.js (.../branches/textnode) (working copy) @@ -34,6 +34,12 @@ root: null, /** + * Property: textroot + * {DOMElement} + */ + textroot: null, + + /** * Property: xmlns * {String} */ @@ -50,7 +56,8 @@ this.rendererRoot = this.createRenderRoot(); this.root = this.createRoot(); - + //calls either a svg or vml function to add the textroot node to the renderRoot node + this.appendTextToRoot(); this.rendererRoot.appendChild(this.root); this.container.appendChild(this.rendererRoot); }, @@ -64,6 +71,7 @@ this.rendererRoot = null; this.root = null; + this.textroot = null; this.xmlns = null; OpenLayers.Renderer.prototype.destroy.apply(this, arguments); @@ -78,6 +86,11 @@ while (this.root.childNodes.length > 0) { this.root.removeChild(this.root.firstChild); } + } + if (this.textroot) { + while (this.textroot.childNodes.length > 0) { + this.textroot.removeChild(this.textroot.firstChild); + } } }, @@ -98,8 +111,47 @@ */ getNodeType: function(geometry) { }, + /** + * Method: appendTextToNode + * + * Parameters: + * node - {DOMElement} + * geometry - {<OpenLayers.Geometry>} + */ + appendTextToNode: function(geometry,node) { }, + + /** + * Method: appendTextToRoot + * + */ + appendTextToRoot: function() { }, + /** * Method: drawGeometry + * Draw the text, creating new nodes, setting paths, setting style, + * setting featureId on the node. This method should only be called + * by the renderer itself. + * + * Parameters: + * geometry - {<OpenLayers.Geometry>} + * style - {Object} + * featureId - {String} + * featuretext - {String} + */ + drawGeometryText: function(geometry, style, featureId, featuretext) { + geometry.CLASS_NAME = "OpenLayers.Geometry.Text"; + var nodeType = this.getNodeType(geometry); + var node = this.nodeFactory(geometry.id+"Text", nodeType, geometry); + node._featureId = featureId; + node._geometryClass = geometry.CLASS_NAME; + node._style = style; + node.textContent = featuretext; + this.appendTextToNode(geometry,node); + this.drawGeometryNode(node, geometry); + }, + + /** + * Method: drawGeometry * Draw the geometry, creating new nodes, setting paths, setting style, * setting featureId on the node. This method should only be called * by the renderer itself. @@ -152,6 +204,9 @@ 'isStroked': true }; switch (geometry.CLASS_NAME) { + case "OpenLayers.Geometry.Text": + this.drawText(node, geometry); + break; case "OpenLayers.Geometry.Point": this.drawPoint(node, geometry); break; @@ -196,6 +251,15 @@ drawPoint: function(node, geometry) {}, /** + * Method: drawText + * + * Parameters: + * node - {DOMElement} + * geometry - {<OpenLayers.Geometry>} + */ + drawText: function(node, geometry) {}, + + /** * Method: drawLineString * Virtual function for drawing LineString Geometry. * Should be implemented by subclasses. Index: lib/OpenLayers/Renderer/VML.js =================================================================== --- lib/OpenLayers/Renderer/VML.js (.../tags/2.5) (revision 8852) +++ lib/OpenLayers/Renderer/VML.js (.../branches/textnode) (working copy) @@ -103,6 +103,24 @@ }, /** + * Method: appendTextToNode + * this function adds the text node to the the point data node, + * whereas the vml function adds the text node to the textroot node + */ + appendTextToNode: function(geometry,node) { + var element = OpenLayers.Util.getElement(geometry.id); + element.appendChild(node); + }, + + /** + * Method: appendTextToRoot + * the vml dosnot need a textroot node whereas, + * the svg adds the textroot node to the rendererRoot node, + */ + appendTextToRoot: function() { + }, + + /** * Method: getNodeType * Get the noode type for a geometry * @@ -115,6 +133,9 @@ getNodeType: function(geometry) { var nodeType = null; switch (geometry.CLASS_NAME) { + case "OpenLayers.Geometry.Text": + nodeType = "v:textbox"; + break; case "OpenLayers.Geometry.Point": nodeType = "v:oval"; break; @@ -150,6 +171,10 @@ style = style || node._style; options = options || node._options; + if (node._geometryClass == "OpenLayers.Geometry.Text") { + //dosnt work, tried centering text in IE + node.style.textAlign = "center"; + } if (node._geometryClass == "OpenLayers.Geometry.Point") { if (style.externalGraphic) { // remove old node @@ -378,6 +403,18 @@ }, /** + * Method: drawText + * This method is only called by the renderer itself. + * + * Parameters: + * node - {DOMElement} + * geometry - {<OpenLayers.Geometry>} + */ + drawText: function(node, geometry) { + this.drawTextLine(node, geometry); + }, + + /** * Method: drawCircle * Render a circle. * Size and Center a circle given geometry (x,y center) and radius @@ -390,10 +427,9 @@ drawCircle: function(node, geometry, radius) { if(!isNaN(geometry.x)&& !isNaN(geometry.y)) { var resolution = this.getResolution(); - + node.style.left = (geometry.x /resolution).toFixed() - radius; node.style.top = (geometry.y /resolution).toFixed() - radius; - var diameter = radius * 2; node.style.width = diameter; @@ -401,6 +437,19 @@ } }, + /** + * Method: drawTextLine + * This method is only called by the renderer itself. + * + * Parameters: + * node - {DOMElement} + * geometry - {<OpenLayers.Geometry>} + */ + drawTextLine: function(node, geometry) { + if(!isNaN(geometry.x)&& !isNaN(geometry.y)) { + node.innerHTML = node.textContent; + } + }, /** * Method: drawLineString Index: lib/OpenLayers/Renderer/SVG.js =================================================================== --- lib/OpenLayers/Renderer/SVG.js (.../tags/2.5) (revision 8852) +++ lib/OpenLayers/Renderer/SVG.js (.../branches/textnode) (working copy) @@ -139,6 +139,9 @@ getNodeType: function(geometry) { var nodeType = null; switch (geometry.CLASS_NAME) { + case "OpenLayers.Geometry.Text": + nodeType = "text"; + break; case "OpenLayers.Geometry.Point": nodeType = "circle"; break; @@ -180,6 +183,10 @@ style = style || node._style; options = options || node._options; + if (node._geometryClass == "OpenLayers.Geometry.Text") { + //centering text on the point + node.setAttributeNS(null, "style", "text-anchor: middle"); + } if (node._geometryClass == "OpenLayers.Geometry.Point") { if (style.externalGraphic) { // remove old node @@ -311,6 +318,43 @@ return root; }, + /** + * Method: createTextRoot + * + * Returns: + * {DOMElement} The textroot element to which we'll add text data + * This i just added for svg because i was unable to output the + * text data in the main root element without the text displaying + * upside down, due to the transform scale(1,-1), which is added + * to the main root element + */ + createTextRoot: function() { + var id = this.container.id + "_textroot"; + + var textroot = this.nodeFactory(id, "g"); + + return textroot; + }, + + /** + * Method: appendTextToNode + * this function adds the text node to the textroot node, + * whereas the vml function adds the text node to the the point data node + */ + appendTextToNode: function(geometry,node) { + this.textroot.appendChild(node); + }, + + /** + * Method: appendTextToRoot + * this function adds the textroot node to the rendererRoot node, + * whereas the vml dosnot need a textroot node + */ + appendTextToRoot: function() { + this.textroot = this.createTextRoot(); + this.rendererRoot.appendChild(this.textroot); + }, + /************************************** * * * GEOMETRY DRAWING FUNCTIONS * @@ -330,6 +374,18 @@ }, /** + * Method: drawText + * This method is only called by the renderer itself. + * + * Parameters: + * node - {DOMElement} + * geometry - {<OpenLayers.Geometry>} + */ + drawText: function(node, geometry) { + this.drawTextLine(node, geometry); + }, + + /** * Method: drawCircle * This method is only called by the renderer itself. * @@ -355,8 +411,34 @@ } }, - + /** + * Method: drawTextLine + * This method is only called by the renderer itself. + * + * Parameters: + * node - {DOMElement} + * geometry - {<OpenLayers.Geometry>} + */ + drawTextLine: function(node, geometry) { + var resolution = this.getResolution(); + var x = (geometry.x / resolution + this.left); + var y = (geometry.y / resolution - this.top); + var draw = true; + if (x < -this.maxPixel || x > this.maxPixel) { draw = false; } + if (y < -this.maxPixel || y > this.maxPixel) { draw = false; } + + if (draw) { + node.setAttributeNS(null, "x", x); + node.setAttributeNS(null, "y", -y); + } else { + this.root.removeChild(node); + } + + }, + + + /** * Method: drawLineString * This method is only called by the renderer itself. * Index: lib/OpenLayers/Layer/WFS.js =================================================================== --- lib/OpenLayers/Layer/WFS.js (.../tags/2.5) (revision 8852) +++ lib/OpenLayers/Layer/WFS.js (.../branches/textnode) (working copy) @@ -74,6 +74,11 @@ */ extractAttributes: false, + /**Should contain the name of the attribute you wish to display in text + *from the point data you are displaying + */ + textAttrToDisplay: null, + /** * Constructor: OpenLayers.Layer.WFS *
_______________________________________________ Dev mailing list Dev@openlayers.org http://openlayers.org/mailman/listinfo/dev