diff --git a/examples/vector-features.html b/examples/vector-features.html index a7193227c9..a8ba5040c3 100644 --- a/examples/vector-features.html +++ b/examples/vector-features.html @@ -7,7 +7,7 @@ border: 1px solid black; } - + @@ -75,5 +97,12 @@ in different styles, created 'manually', by constructing the entire style object, via 'copy', extending the default style object, and by inheriting the default style from the layer.

+

It also shows how to use external graphic files for point features + and how to set their size: If either graphicWidth or graphicHeight is set, + the aspect ratio of the image will be respected. If both graphicWidth and + graphicHeight are set, it will be ignored. Alternatively, if graphicWidth + and graphicHeight are omitted, pointRadius will be used to set the size + of the image, which will then be twice the value of pointRadius with the + original aspect ratio.

diff --git a/lib/OpenLayers/Renderer/SVG.js b/lib/OpenLayers/Renderer/SVG.js index f4812c3937..ed22f87ecc 100644 --- a/lib/OpenLayers/Renderer/SVG.js +++ b/lib/OpenLayers/Renderer/SVG.js @@ -183,7 +183,42 @@ OpenLayers.Renderer.SVG.prototype = options = options || node._options; if (node._geometryClass == "OpenLayers.Geometry.Point") { - node.setAttributeNS(null, "r", style.pointRadius); + if (style.externalGraphic) { + // remove old node + var id = node.getAttributeNS(null, "id"); + var x = node.getAttributeNS(null, "cx"); + var y = node.getAttributeNS(null, "cy"); + var _featureId = node._featureId; + var _geometryClass = node._geometryClass; + var _style = node._style; + this.root.removeChild(node); + + // create new image node + var node = this.createNode("image", id); + node._featureId = _featureId; + node._geometryClass = _geometryClass; + node._style = _style; + this.root.appendChild(node); + + // now style the new node + 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; + + node.setAttributeNS(null, "x", x-(.5*width).toFixed()); + node.setAttributeNS(null, "y", -y-(.5*height).toFixed()); + node.setAttributeNS(null, "width", width); + node.setAttributeNS(null, "height", height); + node.setAttributeNS("http://www.w3.org/1999/xlink", "href", style.externalGraphic); + node.setAttributeNS(null, "transform", "scale(1,-1)"); + node.setAttributeNS(null, "style", "opacity: "+style.fillOpacity); + } else { + node.setAttributeNS(null, "r", style.pointRadius); + } } if (options.isFilled) { diff --git a/lib/OpenLayers/Renderer/VML.js b/lib/OpenLayers/Renderer/VML.js index 0710a871c3..7796da376b 100644 --- a/lib/OpenLayers/Renderer/VML.js +++ b/lib/OpenLayers/Renderer/VML.js @@ -153,7 +153,49 @@ OpenLayers.Renderer.VML.prototype = options = options || node._options; if (node._geometryClass == "OpenLayers.Geometry.Point") { - this.drawCircle(node, geometry, style.pointRadius); + if (style.externalGraphic) { + // remove old node + var id = node.id; + var _featureId = node._featureId; + var _geometryClass = node._geometryClass; + var _style = node._style; + this.root.removeChild(node); + + // create new image node + var 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; + this.root.appendChild(node); + + 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; + height = height ? height : style.pointRadius*2; + var resolution = this.getResolution(); + node.style.left = (geometry.x/resolution-.5*width).toFixed(); + node.style.top = (geometry.y/resolution-.5*height).toFixed(); + node.style.width = width; + node.style.height = height; + + // modify fill style for rect styling below + style.fillColor = "none"; + style.strokeColor = "none"; + + } else { + this.drawCircle(node, geometry, style.pointRadius); + } } //fill @@ -170,7 +212,9 @@ OpenLayers.Renderer.VML.prototype = fill = this.createNode('v:fill', node.id + "_fill"); node.appendChild(fill); } - fill.setAttribute("opacity", style.fillOpacity); + if (style.fillOpacity) { + fill.setAttribute("opacity", style.fillOpacity); + } } diff --git a/tests/Layer/test_Vector.html b/tests/Layer/test_Vector.html index c368c14f9c..75dfc88d69 100644 --- a/tests/Layer/test_Vector.html +++ b/tests/Layer/test_Vector.html @@ -106,7 +106,7 @@ "given a custom style, renders with that"); } - + function test_Layer_Vector_eraseFeatures(t) { t.plan(2); var layer = new OpenLayers.Layer.Vector("Test Layer"); @@ -156,6 +156,113 @@ t.eq(layer.map, null, "layer.map is null after destroy"); } + function test_Layer_Vector_externalGraphic(t) { + t.plan(8); + // base layer is needed for getResolution() to return a value, + // otherwise VML test will fail because style.left and style.top + // cannot be set + var baseLayer = new OpenLayers.Layer.WMS("Base Layer", + "http://octo.metacarta.com/cgi-bin/mapserv", + { map: '/mapdata/vmap_wms.map', + layers: 'basic', + format: 'image/png'}); + + var layer = new OpenLayers.Layer.Vector("Test Layer"); + var map = new OpenLayers.Map('map'); + map.addLayers([baseLayer, layer]); + + var geometry = new OpenLayers.Geometry.Point(10, 10); + var feature = new OpenLayers.Feature.Vector(geometry); + + var customStyle1 = new Object({ + externalGraphic: 'test.png', + pointRadius: 10 + }); + var customStyle2 = new Object({ + externalGraphic: 'test.png', + graphicWidth: 12 + }); + var customStyle3 = new Object({ + externalGraphic: 'test.png', + graphicHeight: 14 + }); + var customStyle4 = new Object({ + externalGraphic: 'test.png', + graphicWidth: 24, + graphicHeight: 16 + }); + + var root = layer.renderer.root; + if (layer.renderer.CLASS_NAME == 'OpenLayers.Renderer.SVG') { + feature.style = customStyle1; + layer.drawFeature(feature); + t.eq(root.firstChild.getAttributeNS(null, 'width'), + (2*customStyle1.pointRadius).toString(), + "given a pointRadius, width equals 2*pointRadius"); + t.eq(root.firstChild.getAttributeNS(null, 'height'), + (2*customStyle1.pointRadius).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.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.toString(), + "height is set correctly"); + feature.style = customStyle4; + layer.drawFeature(feature); + t.eq(root.firstChild.getAttributeNS(null, 'height'), + customStyle4.graphicHeight.toString(), + "given graphicHeight and graphicWidth, both are set: height") + t.eq(root.firstChild.getAttributeNS(null, 'width'), + customStyle4.graphicWidth.toString(), + "given graphicHeight and graphicWidth, both are set: width") + } + if (layer.renderer.CLASS_NAME == 'OpenLayers.Renderer.VML') { + feature.style = customStyle1; + layer.drawFeature(feature); + t.eq(root.firstChild.style.width, + (2*customStyle1.pointRadius).toString()+'px', + "given a pointRadius, width equals 2*pointRadius"); + t.eq(root.firstChild.style.height, + (2*customStyle1.pointRadius).toString()+'px', + "given a pointRadius, height equals 2*pointRadius"); + feature.style = customStyle2; + layer.drawFeature(feature); + t.eq(root.firstChild.style.width, + root.firstChild.style.height, + "given a graphicWidth, width equals height"); + t.eq(root.firstChild.style.width, + customStyle2.graphicWidth.toString()+'px', + "width is set correctly"); + feature.style = customStyle3; + layer.drawFeature(feature); + t.eq(root.firstChild.style.height, + root.firstChild.style.width, + "given a graphicHeight, height equals width"); + t.eq(root.firstChild.style.height, + customStyle3.graphicHeight.toString()+'px', + "height is set correctly"); + feature.style = customStyle4; + layer.drawFeature(feature); + t.eq(root.firstChild.style.height, + customStyle4.graphicHeight.toString()+'px', + "given graphicHeight and graphicWidth, both are set: height") + t.eq(root.firstChild.style.width, + customStyle4.graphicWidth.toString()+'px', + "given graphicHeight and graphicWidth, both are set: width") + } + } + // -->