Parsing Styled Layer Descriptor (SLD) documents with the SLD format.
+
+
+
+
+
+
+
+ This example uses the SLD format to parse SLD documents pasted into the textarea above.
+ A rough representation of the parsed style is shown in the textarea below.
+
+
+
+
+
+
+
+
diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js
index 6e0c962dbc..94ba1d2206 100644
--- a/lib/OpenLayers.js
+++ b/lib/OpenLayers.js
@@ -227,6 +227,7 @@
"OpenLayers/Layer/PointTrack.js",
"OpenLayers/Layer/GML.js",
"OpenLayers/Style.js",
+ "OpenLayers/Style2.js",
"OpenLayers/StyleMap.js",
"OpenLayers/Rule.js",
"OpenLayers/Format.js",
@@ -303,6 +304,12 @@
"OpenLayers/Control/ZoomOut.js",
"OpenLayers/Control/ZoomPanel.js",
"OpenLayers/Control/EditingToolbar.js",
+ "OpenLayers/Symbolizer.js",
+ "OpenLayers/Symbolizer/Point.js",
+ "OpenLayers/Symbolizer/Line.js",
+ "OpenLayers/Symbolizer/Polygon.js",
+ "OpenLayers/Symbolizer/Text.js",
+ "OpenLayers/Symbolizer/Raster.js",
"OpenLayers/Lang.js",
"OpenLayers/Lang/en.js"
); // etc.
diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js
index 78b8a066e7..08c231a101 100644
--- a/lib/OpenLayers/Format/SLD/v1.js
+++ b/lib/OpenLayers/Format/SLD/v1.js
@@ -39,6 +39,27 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
* {String} Schema location for a particular minor version.
*/
schemaLocation: null,
+
+ /**
+ * APIProperty: multipleSymbolizers
+ * {Boolean} Support multiple symbolizers per rule. Default is false. if
+ * true, an OpenLayers.Style2 instance will be created to represent
+ * user styles instead of an OpenLayers.Style instace. The
+ * OpenLayers.Style2 class allows collections of rules with multiple
+ * symbolizers, but is not currently useful for client side rendering.
+ * If multiple symbolizers is true, multiple FeatureTypeStyle elements
+ * are preserved in reading/writing by setting symbolizer zIndex values.
+ * In addition, the property is ignored if
+ * multiple symbolizers are supported (defaults should be applied
+ * when rendering).
+ */
+ multipleSymbolizers: false,
+
+ /**
+ * Property: featureTypeCounter
+ * {Number} Private counter for multiple feature type styles.
+ */
+ featureTypeCounter: null,
/**
* APIProperty: defaultSymbolizer.
@@ -138,8 +159,15 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
},
"UserStyle": function(node, layer) {
var obj = {defaultsPerSymbolizer: true, rules: []};
+ this.featureTypeCounter = -1;
this.readChildNodes(node, obj);
- var style = new OpenLayers.Style(this.defaultSymbolizer, obj);
+ var style;
+ if (this.multipleSymbolizers) {
+ delete obj.defaultsPerSymbolizer;
+ style = new OpenLayers.Style2(obj);
+ } else {
+ style = new OpenLayers.Style(this.defaultSymbolizer, obj);
+ }
layer.userStyles.push(style);
},
"IsDefault": function(node, style) {
@@ -148,18 +176,21 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
},
"FeatureTypeStyle": function(node, style) {
- // OpenLayers doesn't have a place for FeatureTypeStyle
- // Name, Title, Abstract, FeatureTypeName, or
- // SemanticTypeIdentifier so, we make a temporary object
- // and later just use the Rule(s).
+ ++this.featureTypeCounter;
var obj = {
- rules: []
+ rules: this.multipleSymbolizers ? style.rules : []
};
this.readChildNodes(node, obj);
- style.rules = obj.rules;
+ if (!this.multipleSymbolizers) {
+ style.rules = obj.rules;
+ }
},
"Rule": function(node, obj) {
- var rule = new OpenLayers.Rule();
+ var config;
+ if (this.multipleSymbolizers) {
+ config = {symbolizers: []};
+ }
+ var rule = new OpenLayers.Rule(config);
this.readChildNodes(node, rule);
obj.rules.push(rule);
},
@@ -173,11 +204,18 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
rule.maxScaleDenominator = parseFloat(this.getChildValue(node));
},
"TextSymbolizer": function(node, rule) {
- // OpenLayers doens't do painter's order, instead we extend
- var symbolizer = rule.symbolizer["Text"] || {};
- this.readChildNodes(node, symbolizer);
- // in case it didn't exist before
- rule.symbolizer["Text"] = symbolizer;
+ var config = {};
+ this.readChildNodes(node, config);
+ if (this.multipleSymbolizers) {
+ config.zIndex = this.featureTypeCounter;
+ rule.symbolizers.push(
+ new OpenLayers.Symbolizer.Text(config)
+ );
+ } else {
+ rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults(
+ config, rule.symbolizer["Text"]
+ );
+ }
},
"Label": function(node, symbolizer) {
// only supporting literal or property name
@@ -211,11 +249,18 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
},
"RasterSymbolizer": function(node, rule) {
- // OpenLayers doesn't do painter's order, instead we extend
- var symbolizer = rule.symbolizer["Raster"] || {};
- this.readChildNodes(node, symbolizer);
- // in case it didn't exist before
- rule.symbolizer["Raster"] = symbolizer;
+ var config = {};
+ this.readChildNodes(node, config);
+ if (this.multipleSymbolizers) {
+ config.zIndex = this.featureTypeCounter;
+ rule.symbolizers.push(
+ new OpenLayers.Symbolizer.Raster(config)
+ );
+ } else {
+ rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults(
+ config, rule.symbolizer["Raster"]
+ );
+ }
},
"Geometry": function(node, obj) {
obj.geometry = {};
@@ -236,32 +281,55 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
});
},
"LineSymbolizer": function(node, rule) {
- // OpenLayers doesn't do painter's order, instead we extend
- var symbolizer = rule.symbolizer["Line"] || {};
- this.readChildNodes(node, symbolizer);
- // in case it didn't exist before
- rule.symbolizer["Line"] = symbolizer;
+ var config = {};
+ this.readChildNodes(node, config);
+ if (this.multipleSymbolizers) {
+ config.zIndex = this.featureTypeCounter;
+ rule.symbolizers.push(
+ new OpenLayers.Symbolizer.Line(config)
+ );
+ } else {
+ rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults(
+ config, rule.symbolizer["Line"]
+ );
+ }
},
"PolygonSymbolizer": function(node, rule) {
- // OpenLayers doens't do painter's order, instead we extend
- var symbolizer = rule.symbolizer["Polygon"] || {
+ var config = {
fill: false,
stroke: false
};
- this.readChildNodes(node, symbolizer);
- // in case it didn't exist before
- rule.symbolizer["Polygon"] = symbolizer;
+ if (!this.multipleSymbolizers) {
+ config = rule.symbolizer["Polygon"] || config;
+ }
+ this.readChildNodes(node, config);
+ if (this.multipleSymbolizers) {
+ config.zIndex = this.featureTypeCounter;
+ rule.symbolizers.push(
+ new OpenLayers.Symbolizer.Polygon(config)
+ );
+ } else {
+ rule.symbolizer["Polygon"] = config;
+ }
},
"PointSymbolizer": function(node, rule) {
- // OpenLayers doens't do painter's order, instead we extend
- var symbolizer = rule.symbolizer["Point"] || {
+ var config = {
fill: false,
stroke: false,
graphic: false
};
- this.readChildNodes(node, symbolizer);
- // in case it didn't exist before
- rule.symbolizer["Point"] = symbolizer;
+ if (!this.multipleSymbolizers) {
+ config = rule.symbolizer["Point"] || config;
+ }
+ this.readChildNodes(node, config);
+ if (this.multipleSymbolizers) {
+ config.zIndex = this.featureTypeCounter;
+ rule.symbolizers.push(
+ new OpenLayers.Symbolizer.Point(config)
+ );
+ } else {
+ rule.symbolizer["Point"] = config;
+ }
},
"Stroke": function(node, symbolizer) {
symbolizer.stroke = true;
@@ -566,7 +634,53 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
// add FeatureTypeStyles
- this.writeNode("FeatureTypeStyle", style, node);
+ if (this.multipleSymbolizers && style.rules) {
+ // group style objects by symbolizer zIndex
+ var rulesByZ = {
+ 0: []
+ };
+ var zValues = [0];
+ var rule, ruleMap, symbolizer, zIndex, clone;
+ for (var i=0, ii=style.rules.length; i 0) {
+ clone = style.clone();
+ clone.rules = rulesByZ[zValues[i]];
+ this.writeNode("FeatureTypeStyle", clone, node);
+ }
+ }
+ } else {
+ this.writeNode("FeatureTypeStyle", style, node);
+ }
return node;
},
@@ -626,17 +740,28 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
);
}
- // add in symbolizers (relies on geometry type keys)
- var types = OpenLayers.Style.SYMBOLIZER_PREFIXES;
var type, symbolizer;
- for(var i=0, len=types.length; i} Name of the layer that this style belongs to, usually
+ * according to the NamedLayer attribute of an SLD document.
+ */
+ layerName: null,
+
+ /**
+ * APIProperty: isDefault
+ * {Boolean}
+ */
+ isDefault: false,
+
+ /**
+ * APIProperty: rules
+ * {Array()} Collection of rendering rules.
+ */
+ rules: null,
+
+ /**
+ * Constructor: OpenLayers.Style2
+ * Creates a style representing a collection of rendering rules.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * style. Any documented properties may be set at construction.
+ *
+ * Return:
+ * {} A new style object.
+ */
+ initialize: function(config) {
+ OpenLayers.Util.extend(this, config);
+ this.id = OpenLayers.Util.createUniqueID(this.CLASS_NAME + "_");
+ },
+
+ /**
+ * APIMethod: destroy
+ * nullify references to prevent circular references and memory leaks
+ */
+ destroy: function() {
+ for (var i=0, len=this.rules.length; i} Clone of this style.
+ */
+ clone: function() {
+ var config = OpenLayers.Util.extend({}, this);
+ // clone rules
+ if (this.rules) {
+ config.rules = [];
+ for (var i=0, len=this.rules.length; i and ).
+ */
+ rotation: null,
+
+ /**
+ * APIProperty: graphicName
+ * {String} Named graphic to use when rendering points. Supported values
+ * include "circle", "square", "star", "x", "cross", and "triangle".
+ */
+ graphicName: null,
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Point
+ * Create a symbolizer for rendering points.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new point symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Point"
+
+});
+
diff --git a/lib/OpenLayers/Symbolizer/Polygon.js b/lib/OpenLayers/Symbolizer/Polygon.js
new file mode 100644
index 0000000000..b72a892779
--- /dev/null
+++ b/lib/OpenLayers/Symbolizer/Polygon.js
@@ -0,0 +1,76 @@
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Polygon
+ * A symbolizer used to render line features.
+ */
+OpenLayers.Symbolizer.Polygon = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * APIProperty: strokeColor
+ * {String} Color for line stroke. This is a RGB hex value (e.g. "#ff0000"
+ * for red).
+ */
+ strokeColor: null,
+
+ /**
+ * APIProperty: strokeOpacity
+ * {Number} Stroke opacity (0-1).
+ */
+ strokeOpacity: null,
+
+ /**
+ * APIProperty: strokeWidth
+ * {Number} Pixel stroke width.
+ */
+ strokeWidth: null,
+
+ /**
+ * APIProperty: strokeLinecap
+ * {String} Stroke cap type ("butt", "round", or "square").
+ */
+ strokeLinecap: null,
+
+ /**
+ * Property: strokeDashstyle
+ * {String} Stroke dash style according to the SLD spec. Note that the
+ * OpenLayers values for strokeDashstyle ("dot", "dash", "dashdot",
+ * "longdash", "longdashdot", or "solid") will not work in SLD, but
+ * most SLD patterns will render correctly in OpenLayers.
+ */
+ strokeDashstyle: "solid",
+
+ /**
+ * APIProperty: fillColor
+ * {String} RGB hex fill color (e.g. "#ff0000" for red).
+ */
+ fillColor: null,
+
+ /**
+ * APIProperty: fillOpacity
+ * {Number} Fill opacity (0-1).
+ */
+ fillOpacity: null,
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Polygon
+ * Create a symbolizer for rendering polygons.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new polygon symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Polygon"
+
+});
+
diff --git a/lib/OpenLayers/Symbolizer/Raster.js b/lib/OpenLayers/Symbolizer/Raster.js
new file mode 100644
index 0000000000..cdd72a882a
--- /dev/null
+++ b/lib/OpenLayers/Symbolizer/Raster.js
@@ -0,0 +1,29 @@
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Raster
+ * A symbolizer used to render raster images.
+ */
+OpenLayers.Symbolizer.Raster = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Raster
+ * Create a symbolizer for rendering rasters.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new raster symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Raster"
+
+});
diff --git a/lib/OpenLayers/Symbolizer/Text.js b/lib/OpenLayers/Symbolizer/Text.js
new file mode 100644
index 0000000000..3e97fa5b83
--- /dev/null
+++ b/lib/OpenLayers/Symbolizer/Text.js
@@ -0,0 +1,60 @@
+/**
+ * @requires OpenLayers/Symbolizer.js
+ */
+
+/**
+ * Class: OpenLayers.Symbolizer.Text
+ * A symbolizer used to render text labels for features.
+ */
+OpenLayers.Symbolizer.Text = OpenLayers.Class(OpenLayers.Symbolizer, {
+
+ /**
+ * APIProperty: label
+ * {String} The text for the label.
+ */
+ label: null,
+
+ /**
+ * APIProperty: fontFamily
+ * {String} The font family for the label.
+ */
+ fontFamily: null,
+
+ /**
+ * APIProperty: fontSize
+ * {String} The font size for the label.
+ */
+ fontSize: null,
+
+ /**
+ * APIProperty: fontWeight
+ * {String} The font weight for the label.
+ */
+ fontWeight: null,
+
+ /**
+ * Property: fontStyle
+ * {String} The font style for the label.
+ */
+ fontStyle: null,
+
+ /**
+ * Constructor: OpenLayers.Symbolizer.Text
+ * Create a symbolizer for rendering text labels.
+ *
+ * Parameters:
+ * config - {Object} An object containing properties to be set on the
+ * symbolizer. Any documented symbolizer property can be set at
+ * construction.
+ *
+ * Returns:
+ * A new text symbolizer.
+ */
+ initialize: function(config) {
+ OpenLayers.Symbolizer.prototype.initialize.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Symbolizer.Text"
+
+});
+
diff --git a/tests/Format/SLD/v1_0_0.html b/tests/Format/SLD/v1_0_0.html
index cfee1720f9..6cb604b82f 100644
--- a/tests/Format/SLD/v1_0_0.html
+++ b/tests/Format/SLD/v1_0_0.html
@@ -2,6 +2,11 @@
+
+
+
+
+
+