diff --git a/examples/graphic-name.html b/examples/graphic-name.html
new file mode 100644
index 0000000000..54649fc257
--- /dev/null
+++ b/examples/graphic-name.html
@@ -0,0 +1,83 @@
+
+
+ OpenLayers Graphic Names
+
+
+
+
+
+
+
Named Graphics Example
+
+
+
+
+ Shows how to use well-known graphic names.
+
+
+
+
+
+ OpenLayers supports well-known names for a few graphics. You can use
+ the names "star", "cross", "x", "square", "triangle", and "circle" as
+ the value for the graphicName property of a symbolizer.
+
+
+
\ No newline at end of file
diff --git a/examples/tasmania/TasmaniaCities.xml b/examples/tasmania/TasmaniaCities.xml
index 780d23ce35..11f5bd7c03 100644
--- a/examples/tasmania/TasmaniaCities.xml
+++ b/examples/tasmania/TasmaniaCities.xml
@@ -23,4 +23,18 @@
100,000 to 250,000
+
+
+
+
+
+
+ 147,-41.1
+
+
+
+
+ Australia
+
+
diff --git a/examples/tasmania/sld-tasmania.xml b/examples/tasmania/sld-tasmania.xml
index ce3e3e5538..1ffba6ec03 100644
--- a/examples/tasmania/sld-tasmania.xml
+++ b/examples/tasmania/sld-tasmania.xml
@@ -528,13 +528,27 @@
1
+
+
+ image/png
- 0.5
+ 0.7
+ 14
+
+
+
+
+
+
+
+
+ cross
+ 10
diff --git a/examples/vector-features.html b/examples/vector-features.html
index 78ea7364bf..bcde5e5b45 100644
--- a/examples/vector-features.html
+++ b/examples/vector-features.html
@@ -26,6 +26,11 @@
var style_blue = OpenLayers.Util.extend({}, layer_style);
style_blue.strokeColor = "blue";
style_blue.fillColor = "blue";
+ style_blue.graphicName = "star";
+ style_blue.pointRadius = 10;
+ style_blue.strokeWidth = 3;
+ style_blue.rotation = 45;
+ style_blue.strokeLinecap = "butt";
/*
* Green style
diff --git a/lib/OpenLayers/Feature/Vector.js b/lib/OpenLayers/Feature/Vector.js
index 127ef48258..338fce6ec8 100644
--- a/lib/OpenLayers/Feature/Vector.js
+++ b/lib/OpenLayers/Feature/Vector.js
@@ -323,9 +323,10 @@ OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
* - externalGraphic,
* - graphicWidth,
* - graphicHeight,
- * - graphicOpacity
- * - graphicXOffset
- * - graphicYOffset
+ * - graphicOpacity,
+ * - graphicXOffset,
+ * - graphicYOffset,
+ * - graphicName,
* - display
*/
OpenLayers.Feature.Vector.style = {
diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js
index cdffc6e36b..db2a88063d 100644
--- a/lib/OpenLayers/Format/SLD/v1.js
+++ b/lib/OpenLayers/Format/SLD/v1.js
@@ -52,7 +52,8 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
strokeColor: "#000000",
strokeOpacity: 1,
strokeWidth: 1,
- pointRadius: 6
+ pointRadius: 3,
+ graphicName: "square"
},
/**
diff --git a/lib/OpenLayers/Renderer/Elements.js b/lib/OpenLayers/Renderer/Elements.js
index fc025ffda7..e7cf0658cb 100644
--- a/lib/OpenLayers/Renderer/Elements.js
+++ b/lib/OpenLayers/Renderer/Elements.js
@@ -371,6 +371,35 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
}
return node;
},
-
+
+ /**
+ * Method: isComplexSymbol
+ * Determines if a symbol cannot be rendered using drawCircle
+ *
+ * Parameters:
+ * graphicName - {String}
+ *
+ * Returns
+ * {Boolean} true if the symbol is complex, false if not
+ */
+ isComplexSymbol: function(graphicName) {
+ return (graphicName != "circle") && !!graphicName;
+ },
+
CLASS_NAME: "OpenLayers.Renderer.Elements"
});
+
+
+/**
+ * Constant: OpenLayers.Renderer.symbol
+ * Coordinate arrays for well known (named) symbols.
+ */
+OpenLayers.Renderer.symbol = {
+ "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301,
+ 303,215, 231,161, 321,161, 350,75],
+ "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4,
+ 4,0],
+ "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0],
+ "square": [0,0, 0,1, 1,1, 1,0, 0,0],
+ "triangle": [0,10, 10,10, 5,0, 0,10]
+}
diff --git a/lib/OpenLayers/Renderer/SVG.js b/lib/OpenLayers/Renderer/SVG.js
index a158338272..ce18991fa7 100644
--- a/lib/OpenLayers/Renderer/SVG.js
+++ b/lib/OpenLayers/Renderer/SVG.js
@@ -19,6 +19,12 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* {String}
*/
xmlns: "http://www.w3.org/2000/svg",
+
+ /**
+ * Property: xlinkns
+ * {String}
+ */
+ xlinkns: "http://www.w3.org/1999/xlink",
/**
* Constant: MAX_PIXEL
@@ -33,6 +39,12 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
* {Float}
*/
localResolution: null,
+
+ /**
+ * Property: symbolSize
+ * {Object} Cache for symbol sizes according to their svg coordinate space
+ */
+ symbolSize: {},
/**
* Constructor: OpenLayers.Renderer.SVG
@@ -154,7 +166,13 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var nodeType = null;
switch (geometry.CLASS_NAME) {
case "OpenLayers.Geometry.Point":
- nodeType = style.externalGraphic ? "image" : "circle";
+ if (style.externalGraphic) {
+ nodeType = "image";
+ } else if (this.isComplexSymbol(style.graphicName)) {
+ nodeType = "use";
+ } else {
+ nodeType = "circle";
+ }
break;
case "OpenLayers.Geometry.Rectangle":
nodeType = "rect";
@@ -194,10 +212,11 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
style = style || node._style;
options = options || node._options;
var r = parseFloat(node.getAttributeNS(null, "r"));
+ var widthFactor = 1;
+ var pos;
if (node._geometryClass == "OpenLayers.Geometry.Point" && r) {
if (style.externalGraphic) {
- var x = parseFloat(node.getAttributeNS(null, "cx"));
- var y = parseFloat(node.getAttributeNS(null, "cy"));
+ pos = this.getPosition(node);
if (style.graphicWidth && style.graphicHeight) {
node.setAttributeNS(null, "preserveAspectRatio", "none");
@@ -213,19 +232,31 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
var opacity = style.graphicOpacity || style.fillOpacity;
- node.setAttributeNS(null, "x", (x + xOffset).toFixed());
- node.setAttributeNS(null, "y", (y + yOffset).toFixed());
+ node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed());
+ node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed());
node.setAttributeNS(null, "width", width);
node.setAttributeNS(null, "height", height);
- node.setAttributeNS("http://www.w3.org/1999/xlink", "href", style.externalGraphic);
+ node.setAttributeNS(this.xlinkns, "href", style.externalGraphic);
node.setAttributeNS(null, "style", "opacity: "+opacity);
+ } else if (this.isComplexSymbol(style.graphicName)) {
+ // the symbol viewBox is three times as large as the symbol
+ var offset = style.pointRadius * 3;
+ var size = offset * 2;
+ var id = this.importSymbol(style.graphicName);
+ pos = this.getPosition(node);
+ widthFactor = this.symbolSize[id] / size;
+ node.setAttributeNS(this.xlinkns, "href", "#" + id);
+ node.setAttributeNS(null, "width", size);
+ node.setAttributeNS(null, "height", size);
+ node.setAttributeNS(null, "x", pos.x - offset);
+ node.setAttributeNS(null, "y", pos.y - offset);
} else {
node.setAttributeNS(null, "r", style.pointRadius);
}
- if (style.rotation) {
+ if (style.rotation && pos) {
var rotation = OpenLayers.String.format(
- "rotate(${0} ${1} ${2})", [style.rotation, x, y]);
+ "rotate(${0} ${1} ${2})", [style.rotation, pos.x, pos.y]);
node.setAttributeNS(null, "transform", rotation);
}
}
@@ -240,7 +271,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
if (options.isStroked) {
node.setAttributeNS(null, "stroke", style.strokeColor);
node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity);
- node.setAttributeNS(null, "stroke-width", style.strokeWidth);
+ node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor);
node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap);
} else {
node.setAttributeNS(null, "stroke", "none");
@@ -308,6 +339,18 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
return this.nodeFactory(this.container.id + "_root", "g");
},
+ /**
+ * Method: createDefs
+ *
+ * Returns:
+ * {DOMElement} The element to which we'll add the symbol definitions
+ */
+ createDefs: function() {
+ var defs = this.nodeFactory("ol-renderer-defs", "defs");
+ this.rendererRoot.appendChild(defs);
+ return defs;
+ },
+
/**************************************
* *
* GEOMETRY DRAWING FUNCTIONS *
@@ -510,6 +553,88 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
return false;
}
},
+
+ /**
+ * Method: getPosition
+ * Finds the position of an svg node.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ *
+ * Returns:
+ * {Object} hash with x and y properties, representing the coordinates
+ * within the svg coordinate system
+ */
+ getPosition: function(node) {
+ return({
+ x: parseFloat(node.getAttributeNS(null, "cx")),
+ y: parseFloat(node.getAttributeNS(null, "cy"))
+ });
+ },
+
+ /**
+ * Method: importSymbol
+ * add a new symbol definition from the rendererer's symbol hash
+ *
+ * Parameters:
+ * graphicName - {String} name of the symbol to import
+ *
+ * Returns:
+ * {String} - id of 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
+ if (document.getElementById(id) != null) {
+ return id;
+ }
+
+ var symbol = OpenLayers.Renderer.symbol[graphicName];
+ if (!symbol) {
+ throw new Error(graphicName + ' is not a valid symbol name');
+ return;
+ }
+
+ 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; i
diff --git a/tests/Renderer/VML.html b/tests/Renderer/VML.html
index 5f2e513cf5..173bb43b57 100644
--- a/tests/Renderer/VML.html
+++ b/tests/Renderer/VML.html
@@ -338,7 +338,39 @@
t.eq(node.style.height, "8px", "node.style.height is correct");
}
+ function test_vml_getnodetype(t) {
+ if (!OpenLayers.Renderer.VML.prototype.supported()) {
+ t.plan(0);
+ return;
+ }
+ t.plan(1);
+
+ var r = new OpenLayers.Renderer.VML(document.body);
+
+ var g = {CLASS_NAME: "OpenLayers.Geometry.Point"}
+ var s = {graphicName: "square"};
+
+ t.eq(r.getNodeType(g, s), "olv:shape", "Correct node type for well known symbols");
+ }
+
+ function test_vml_importsymbol(t) {
+ if (!OpenLayers.Renderer.VML.prototype.supported()) {
+ t.plan(0);
+ return;
+ }
+
+ t.plan(2);
+
+ var r = new OpenLayers.Renderer.VML(document.body);
+
+ var cache = r.importSymbol("square");
+
+ t.eq(cache.path, "m 0 0 l 0 1 1 1 1 0 0 0 x e", "Square symbol rendered correctly");
+ t.ok(r.symbolCache["-square"], "Symbol has been cached correctly.");
+
+ }
+