diff --git a/lib/OpenLayers/Format/SLD.js b/lib/OpenLayers/Format/SLD.js index 24a20df762..ed11d5b495 100644 --- a/lib/OpenLayers/Format/SLD.js +++ b/lib/OpenLayers/Format/SLD.js @@ -1,599 +1,599 @@ -/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license. - * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt - * for the full text of the license. */ - -/** - * @requires OpenLayers/Format/XML.js - * @requires OpenLayers/Style.js - * @requires OpenLayers/Rule/FeatureId.js - * @requires OpenLayers/Rule/Logical.js - * @requires OpenLayers/Rule/Comparison.js - */ - -/** - * Class: OpenLayers.Format.SLD - * Read/Wite SLD. Create a new instance with the - * constructor. - * - * Inherits from: - * - - */ -OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML, { - - /** - * APIProperty: sldns - * Namespace used for sld. - */ - sldns: "http://www.opengis.net/sld", - - /** - * APIProperty: ogcns - * Namespace used for ogc. - */ - ogcns: "http://www.opengis.net/ogc", - - /** - * APIProperty: gmlns - * Namespace used for gml. - */ - gmlns: "http://www.opengis.net/gml", - - /** - * APIProperty: defaultStyle. - * {Object} - * A simple style, preset with the SLD defaults. - */ - defaultStyle: { - fillColor: "#808080", - fillOpacity: 1, - strokeColor: "#000000", - strokeOpacity: 1, - strokeWidth: 1, - pointRadius: 6 - }, - - /** - * Property: withNamedLayer - * {Boolean} Option set during . Default is false. If true, the - * return from will be a two item array ([styles, namedLayer]): - * - styles - {Array()} - * - namedLayer - {Object} hash of userStyles, keyed by - * sld:NamedLayer/Name, each again keyed by - * sld:UserStyle/Name. Each entry of namedLayer is a - * StyleMap for a layer, with the userStyle names as style - * keys. - */ - withNamedLayer: false, - - /** - * APIProperty: overrideDefaultStyleKey - * {Boolean} Store styles with key of "default" instead of user style name. - * If true, userStyles with sld:IsDefault==1 will be stored with - * key "default" instead of the sld:UserStyle/Name in the style map. - * Default is true. - */ - overrideDefaultStyleKey: true, - - - /** - * Constructor: OpenLayers.Format.SLD - * Create a new parser for SLD. - * - * Parameters: - * options - {Object} An optional object whose properties will be set on - * this instance. - */ - initialize: function(options) { - OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); - }, - - /** - * APIMethod: read - * Read data from a string, and return a list of features. - * - * Parameters: - * data - {String} or {XMLNode} data to read/parse. - * options - {Object} Object that sets optional read configuration values. - * These include , and . - * - * Returns: - * {Array()} List of styles. If is - * true, return will be a two item array where the first item is - * a list of styles and the second is the namedLayer object. - */ - read: function(data, options) { - if (typeof data == "string") { - data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); - } - - options = options || {}; - OpenLayers.Util.applyDefaults(options, { - withNamedLayer: false, - overrideDefaultStyleKey: true - }); - - var userStyles = this.getElementsByTagNameNS( - data, this.sldns, "UserStyle" - ); - var result = {}; - if (userStyles.length > 0) { - var namedLayer = {}; - var styles = new Array(userStyles.length); - var styleName, userStyle, style; - for (var i=0; i} - */ - parseUserStyle: function(xmlNode, name) { - var userStyle = new OpenLayers.Style(this.defaultStyle, {name: name}); - - userStyle.isDefault = ( - this.parseProperty(xmlNode, this.sldns, "IsDefault") == 1 - ); - - // get the name of the layer if we have a NamedLayer - var namedLayerNode = xmlNode.parentNode; - var nameNodes = this.getElementsByTagNameNS( - namedLayerNode, this.sldns, "Name" - ); - if (namedLayerNode.nodeName.indexOf("NamedLayer") != -1 && - nameNodes && - nameNodes.length > 0 && - nameNodes[0].parentNode == namedLayerNode) { - userStyle.layerName = this.getChildValue(nameNodes[0]); - } - - var ruleNodes = this.getElementsByTagNameNS( - xmlNode, this.sldns, "Rule" - ); - - if (ruleNodes.length > 0) { - var rules = userStyle.rules; - var ruleName; - for (var i=0; i} - * - * Returns: - * {Object} Hash of rule properties - */ - parseRule: function(xmlNode, name) { - - // FILTERS - - var filter = this.getElementsByTagNameNS(xmlNode, this.ogcns, "Filter"); - if (filter && filter.length > 0) { - var rule = this.parseFilter(filter[0]); - } else { - // start with an empty rule that always applies - var rule = new OpenLayers.Rule(); - // and check if the rule is an ElseFilter - var elseFilter = this.getElementsByTagNameNS(xmlNode, this.ogcns, - "ElseFilter"); - if (elseFilter && elseFilter.length > 0) { - rule.elseFilter = true; - } - } - - rule.name = name; - - // SCALE DENOMINATORS - - // MinScaleDenominator - var minScale = this.getElementsByTagNameNS( - xmlNode, this.sldns, "MinScaleDenominator" - ); - if (minScale && minScale.length > 0) { - rule.minScaleDenominator = - parseFloat(this.getChildValue(minScale[0])); - } - - // MaxScaleDenominator - var maxScale = this.getElementsByTagNameNS( - xmlNode, this.sldns, "MaxScaleDenominator" - ); - if (maxScale && maxScale.length > 0) { - rule.maxScaleDenominator = - parseFloat(this.getChildValue(maxScale[0])); - } - - // STYLES - - // walk through all symbolizers - var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; - for (var s=0; s 0) { - - var style = {}; - - // externalGraphic - var graphic = this.getElementsByTagNameNS( - symbolizer[0], this.sldns, "Graphic" - ); - if (graphic && graphic.length > 0) { - style.externalGraphic = this.parseProperty( - graphic[0], this.sldns, "OnlineResource", "xlink:href" - ); - style.pointRadius = this.parseProperty( - graphic[0], this.sldns, "Size" - ); - style.graphicOpacity = this.parseProperty( - graphic[0], this.sldns, "Opacity" - ); - } - - // fill - var fill = this.getElementsByTagNameNS( - symbolizer[0], this.sldns, "Fill" - ); - if (fill && fill.length > 0) { - style.fillColor = this.parseProperty( - fill[0], this.sldns, "CssParameter", "name", "fill" - ); - style.fillOpacity = this.parseProperty( - fill[0], this.sldns, "CssParameter", - "name", "fill-opacity" - ) || 1; - } - - // stroke - var stroke = this.getElementsByTagNameNS( - symbolizer[0], this.sldns, "Stroke" - ); - if (stroke && stroke.length > 0) { - style.strokeColor = this.parseProperty( - stroke[0], this.sldns, "CssParameter", "name", "stroke" - ); - style.strokeOpacity = this.parseProperty( - stroke[0], this.sldns, "CssParameter", - "name", "stroke-opacity" - ) || 1; - style.strokeWidth = this.parseProperty( - stroke[0], this.sldns, "CssParameter", - "name", "stroke-width" - ); - style.strokeLinecap = this.parseProperty( - stroke[0], this.sldns, "CssParameter", - "name", "stroke-linecap" - ); - } - - // set the [point|line|polygon]Symbolizer property of the rule - rule.symbolizer[prefixes[s]] = style; - } - } - - return rule; - }, - - /** - * Method: parseFilter - * Parses ogc fiters. - * - * Parameters: - * xmlNode - {} - * - * Returns: - * {} rule representing the filter - */ - parseFilter: function(xmlNode) { - // ogc:FeatureId filter - var filter = this.getNodeOrChildrenByTagName(xmlNode, "FeatureId"); - if (filter) { - var rule = new OpenLayers.Rule.FeatureId(); - for (var i=0; i)} or null if no matching content is found - */ - getNodeOrChildrenByTagName: function(xmlNode, tagName) { - var nodeName = (xmlNode.prefix) ? - xmlNode.nodeName.split(":")[1] : - xmlNode.nodeName; - - if (nodeName == tagName) { - return [xmlNode]; - } else { - var nodelist = this.getElementsByTagNameNS( - xmlNode, this.ogcns, tagName); - } - - // make a new list which only contains matching child nodes - if (nodelist.length > 0) { - var node; - var list = []; - for (var i=0; i 0 ? list : null; - } - - return null; - }, - - /** - * Method: parseProperty - * Convenience method to parse the different kinds of properties - * found in the sld and ogc namespace. - * - * Parses an ogc node that can either contain a value directly, - * or inside a property. The parsing can also be limited - * to nodes with certain attribute names and/or values. - * - * Parameters: - * xmlNode - {} - * namespace - {String} namespace of the node to find - * propertyName - {String} name of the property to parse - * attributeName - {String} optional name of the property to match - * attributeValue - {String} optional value of the specified attribute - * - * Returns: - * {String} The value for the requested property. - */ - parseProperty: function(xmlNode, namespace, propertyName, attributeName, - attributeValue) { - var result = null; - var propertyNodeList = this.getElementsByTagNameNS( - xmlNode, namespace, propertyName); - - if (propertyNodeList && propertyNodeList.length > 0) { - var propertyNode = attributeName ? - this.getNodeWithAttribute(propertyNodeList, - attributeName) : - propertyNodeList[0]; - - // strip namespace from attribute name for Opera browsers - if (window.opera && attributeName) { - var nsDelimiterPos = attributeName.indexOf(":"); - if (nsDelimiterPos != -1) { - attributeName = attributeName.substring(++nsDelimiterPos); - } - } - - // get the property value from the node matching attributeName - // and attributeValue, eg.: - // - // red - // - // or: - // red - if (attributeName && attributeValue) { - propertyNode = this.getNodeWithAttribute(propertyNodeList, - attributeName, attributeValue); - result = this.parseParameter(propertyNode); - } - - // get the attribute value and use it as result, eg.: - // - if (attributeName && !attributeValue) { - var propertyNode = this.getNodeWithAttribute(propertyNodeList, - attributeName); - result = propertyNode.getAttribute(attributeName); - } - - // get the property value directly or from an ogc:propertyName, - // ogc:Literal or any other property at the level of the property - // node, eg.: - // 0.5 - if (!attributeName) { - var result = this.parseParameter(propertyNode); - } - } - - // adjust the result to be a trimmed string or a number - if (result) { - result = OpenLayers.String.trim(result); - if (!isNaN(result)) { - result = parseFloat(result); - } - } - - return result; - }, - - /** - * Method: parseParameter - * parses a property for propertyNames, Literals and textContent and - * creates the according value string. - * - * Parameters: - * xmlNode - {} - * - * Returns: - * {String} a string holding a value suitable for OpenLayers.Style.value - */ - parseParameter: function(xmlNode) { - if (!xmlNode) { - return null; - } - var childNodes = xmlNode.childNodes; - if (!childNodes) { - return null; - } - - var value = new Array(childNodes.length); - for (var i=0; i)} list to search - * attributeName - {String} name of the attribute to match - * attributeValue - {String} optional value of the attribute - */ - getNodeWithAttribute: function(xmlNodeList, attributeName, attributeValue) { - for (var i=0; i + * constructor. + * + * Inherits from: + * - + */ +OpenLayers.Format.SLD = OpenLayers.Class(OpenLayers.Format.XML, { + + /** + * APIProperty: sldns + * Namespace used for sld. + */ + sldns: "http://www.opengis.net/sld", + + /** + * APIProperty: ogcns + * Namespace used for ogc. + */ + ogcns: "http://www.opengis.net/ogc", + + /** + * APIProperty: gmlns + * Namespace used for gml. + */ + gmlns: "http://www.opengis.net/gml", + + /** + * APIProperty: defaultStyle. + * {Object} + * A simple style, preset with the SLD defaults. + */ + defaultStyle: { + fillColor: "#808080", + fillOpacity: 1, + strokeColor: "#000000", + strokeOpacity: 1, + strokeWidth: 1, + pointRadius: 6 + }, + + /** + * Property: withNamedLayer + * {Boolean} Option set during . Default is false. If true, the + * return from will be a two item array ([styles, namedLayer]): + * - styles - {Array()} + * - namedLayer - {Object} hash of userStyles, keyed by + * sld:NamedLayer/Name, each again keyed by + * sld:UserStyle/Name. Each entry of namedLayer is a + * StyleMap for a layer, with the userStyle names as style + * keys. + */ + withNamedLayer: false, + + /** + * APIProperty: overrideDefaultStyleKey + * {Boolean} Store styles with key of "default" instead of user style name. + * If true, userStyles with sld:IsDefault==1 will be stored with + * key "default" instead of the sld:UserStyle/Name in the style map. + * Default is true. + */ + overrideDefaultStyleKey: true, + + + /** + * Constructor: OpenLayers.Format.SLD + * Create a new parser for SLD. + * + * Parameters: + * options - {Object} An optional object whose properties will be set on + * this instance. + */ + initialize: function(options) { + OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: read + * Read data from a string, and return a list of features. + * + * Parameters: + * data - {String} or {XMLNode} data to read/parse. + * options - {Object} Object that sets optional read configuration values. + * These include , and . + * + * Returns: + * {Array()} List of styles. If is + * true, return will be a two item array where the first item is + * a list of styles and the second is the namedLayer object. + */ + read: function(data, options) { + if (typeof data == "string") { + data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); + } + + options = options || {}; + OpenLayers.Util.applyDefaults(options, { + withNamedLayer: false, + overrideDefaultStyleKey: true + }); + + var userStyles = this.getElementsByTagNameNS( + data, this.sldns, "UserStyle" + ); + var result = {}; + if (userStyles.length > 0) { + var namedLayer = {}; + var styles = new Array(userStyles.length); + var styleName, userStyle, style; + for (var i=0; i} + */ + parseUserStyle: function(xmlNode, name) { + var userStyle = new OpenLayers.Style(this.defaultStyle, {name: name}); + + userStyle.isDefault = ( + this.parseProperty(xmlNode, this.sldns, "IsDefault") == 1 + ); + + // get the name of the layer if we have a NamedLayer + var namedLayerNode = xmlNode.parentNode; + var nameNodes = this.getElementsByTagNameNS( + namedLayerNode, this.sldns, "Name" + ); + if (namedLayerNode.nodeName.indexOf("NamedLayer") != -1 && + nameNodes && + nameNodes.length > 0 && + nameNodes[0].parentNode == namedLayerNode) { + userStyle.layerName = this.getChildValue(nameNodes[0]); + } + + var ruleNodes = this.getElementsByTagNameNS( + xmlNode, this.sldns, "Rule" + ); + + if (ruleNodes.length > 0) { + var rules = userStyle.rules; + var ruleName; + for (var i=0; i} + * + * Returns: + * {Object} Hash of rule properties + */ + parseRule: function(xmlNode, name) { + + // FILTERS + + var filter = this.getElementsByTagNameNS(xmlNode, this.ogcns, "Filter"); + if (filter && filter.length > 0) { + var rule = this.parseFilter(filter[0]); + } else { + // start with an empty rule that always applies + var rule = new OpenLayers.Rule(); + // and check if the rule is an ElseFilter + var elseFilter = this.getElementsByTagNameNS(xmlNode, this.ogcns, + "ElseFilter"); + if (elseFilter && elseFilter.length > 0) { + rule.elseFilter = true; + } + } + + rule.name = name; + + // SCALE DENOMINATORS + + // MinScaleDenominator + var minScale = this.getElementsByTagNameNS( + xmlNode, this.sldns, "MinScaleDenominator" + ); + if (minScale && minScale.length > 0) { + rule.minScaleDenominator = + parseFloat(this.getChildValue(minScale[0])); + } + + // MaxScaleDenominator + var maxScale = this.getElementsByTagNameNS( + xmlNode, this.sldns, "MaxScaleDenominator" + ); + if (maxScale && maxScale.length > 0) { + rule.maxScaleDenominator = + parseFloat(this.getChildValue(maxScale[0])); + } + + // STYLES + + // walk through all symbolizers + var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; + for (var s=0; s 0) { + + var style = {}; + + // externalGraphic + var graphic = this.getElementsByTagNameNS( + symbolizer[0], this.sldns, "Graphic" + ); + if (graphic && graphic.length > 0) { + style.externalGraphic = this.parseProperty( + graphic[0], this.sldns, "OnlineResource", "xlink:href" + ); + style.pointRadius = this.parseProperty( + graphic[0], this.sldns, "Size" + ); + style.graphicOpacity = this.parseProperty( + graphic[0], this.sldns, "Opacity" + ); + } + + // fill + var fill = this.getElementsByTagNameNS( + symbolizer[0], this.sldns, "Fill" + ); + if (fill && fill.length > 0) { + style.fillColor = this.parseProperty( + fill[0], this.sldns, "CssParameter", "name", "fill" + ); + style.fillOpacity = this.parseProperty( + fill[0], this.sldns, "CssParameter", + "name", "fill-opacity" + ) || 1; + } + + // stroke + var stroke = this.getElementsByTagNameNS( + symbolizer[0], this.sldns, "Stroke" + ); + if (stroke && stroke.length > 0) { + style.strokeColor = this.parseProperty( + stroke[0], this.sldns, "CssParameter", "name", "stroke" + ); + style.strokeOpacity = this.parseProperty( + stroke[0], this.sldns, "CssParameter", + "name", "stroke-opacity" + ) || 1; + style.strokeWidth = this.parseProperty( + stroke[0], this.sldns, "CssParameter", + "name", "stroke-width" + ); + style.strokeLinecap = this.parseProperty( + stroke[0], this.sldns, "CssParameter", + "name", "stroke-linecap" + ); + } + + // set the [point|line|polygon]Symbolizer property of the rule + rule.symbolizer[prefixes[s]] = style; + } + } + + return rule; + }, + + /** + * Method: parseFilter + * Parses ogc fiters. + * + * Parameters: + * xmlNode - {} + * + * Returns: + * {} rule representing the filter + */ + parseFilter: function(xmlNode) { + // ogc:FeatureId filter + var filter = this.getNodeOrChildrenByTagName(xmlNode, "FeatureId"); + if (filter) { + var rule = new OpenLayers.Rule.FeatureId(); + for (var i=0; i)} or null if no matching content is found + */ + getNodeOrChildrenByTagName: function(xmlNode, tagName) { + var nodeName = (xmlNode.prefix) ? + xmlNode.nodeName.split(":")[1] : + xmlNode.nodeName; + + if (nodeName == tagName) { + return [xmlNode]; + } else { + var nodelist = this.getElementsByTagNameNS( + xmlNode, this.ogcns, tagName); + } + + // make a new list which only contains matching child nodes + if (nodelist.length > 0) { + var node; + var list = []; + for (var i=0; i 0 ? list : null; + } + + return null; + }, + + /** + * Method: parseProperty + * Convenience method to parse the different kinds of properties + * found in the sld and ogc namespace. + * + * Parses an ogc node that can either contain a value directly, + * or inside a property. The parsing can also be limited + * to nodes with certain attribute names and/or values. + * + * Parameters: + * xmlNode - {} + * namespace - {String} namespace of the node to find + * propertyName - {String} name of the property to parse + * attributeName - {String} optional name of the property to match + * attributeValue - {String} optional value of the specified attribute + * + * Returns: + * {String} The value for the requested property. + */ + parseProperty: function(xmlNode, namespace, propertyName, attributeName, + attributeValue) { + var result = null; + var propertyNodeList = this.getElementsByTagNameNS( + xmlNode, namespace, propertyName); + + if (propertyNodeList && propertyNodeList.length > 0) { + var propertyNode = attributeName ? + this.getNodeWithAttribute(propertyNodeList, + attributeName) : + propertyNodeList[0]; + + // strip namespace from attribute name for Opera browsers + if (window.opera && attributeName) { + var nsDelimiterPos = attributeName.indexOf(":"); + if (nsDelimiterPos != -1) { + attributeName = attributeName.substring(++nsDelimiterPos); + } + } + + // get the property value from the node matching attributeName + // and attributeValue, eg.: + // + // red + // + // or: + // red + if (attributeName && attributeValue) { + propertyNode = this.getNodeWithAttribute(propertyNodeList, + attributeName, attributeValue); + result = this.parseParameter(propertyNode); + } + + // get the attribute value and use it as result, eg.: + // + if (attributeName && !attributeValue) { + var propertyNode = this.getNodeWithAttribute(propertyNodeList, + attributeName); + result = propertyNode.getAttribute(attributeName); + } + + // get the property value directly or from an ogc:propertyName, + // ogc:Literal or any other property at the level of the property + // node, eg.: + // 0.5 + if (!attributeName) { + var result = this.parseParameter(propertyNode); + } + } + + // adjust the result to be a trimmed string or a number + if (result) { + result = OpenLayers.String.trim(result); + if (!isNaN(result)) { + result = parseFloat(result); + } + } + + return result; + }, + + /** + * Method: parseParameter + * parses a property for propertyNames, Literals and textContent and + * creates the according value string. + * + * Parameters: + * xmlNode - {} + * + * Returns: + * {String} a string holding a value suitable for OpenLayers.Style.value + */ + parseParameter: function(xmlNode) { + if (!xmlNode) { + return null; + } + var childNodes = xmlNode.childNodes; + if (!childNodes) { + return null; + } + + var value = new Array(childNodes.length); + for (var i=0; i)} list to search + * attributeName - {String} name of the attribute to match + * attributeValue - {String} optional value of the attribute + */ + getNodeWithAttribute: function(xmlNodeList, attributeName, attributeValue) { + for (var i=0; i} - */ - initialize: function(options) { - this.symbolizer = {}; - - OpenLayers.Util.extend(this, options); - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - for (var i in this.symbolizer) { - this.symbolizer[i] = null; - } - this.symbolizer = null; - }, - - /** - * APIMethod: evaluate - * evaluates this rule for a specific feature - * - * Parameters: - * feature - {} feature to apply the rule to. - * - * Returns: - * {boolean} true if the rule applies, false if it does not. - * This rule is the default rule and always returns true. - */ - evaluate: function(feature) { - // Default rule always applies. Subclasses will want to override this. - return true; - }, - - CLASS_NAME: "OpenLayers.Rule" +/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license. + * See http://svn.openlayers.org/trunk/openlayers/repository-license.txt + * for the full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Style.js + */ + +/** + * Class: OpenLayers.Rule + * This class represents a OGC Rule, as being used for rule-based SLD styling. + */ +OpenLayers.Rule = OpenLayers.Class({ + + /** + * APIProperty: name + * {String} name of this rule + */ + name: 'default', + + /** + * Property: context + * {Object} An optional object with properties that the rule and its + * symbolizers' property values should be evaluatad against. If no + * context is specified, feature.attributes will be used + */ + context: null, + + /** + * Property: elseFilter + * {Boolean} Determines whether this rule is only to be applied only if + * no other rules match (ElseFilter according to the SLD specification). + * Default is false. For instances of OpenLayers.Rule, if elseFilter is + * false, the rule will always apply. For subclasses, the else property is + * ignored. + */ + elseFilter: false, + + /** + * Property: symbolizer + * {Object} Hash of styles for this rule. Contains hashes of feature + * styles. Keys are one or more of ["Point", "Line", "Polygon"] + */ + symbolizer: null, + + /** + * APIProperty: minScaleDenominator + * {Number} or {String} minimum scale at which to draw the feature. + * In the case of a String, this can be a combination of text and + * propertyNames in the form "literal ${propertyName}" + */ + minScaleDenominator: null, + + /** + * APIProperty: maxScaleDenominator + * {Number} or {String} maximum scale at which to draw the feature. + * In the case of a String, this can be a combination of text and + * propertyNames in the form "literal ${propertyName}" + */ + maxScaleDenominator: null, + + /** + * Constructor: OpenLayers.Rule + * Creates a Rule. + * + * Parameters: + * options - {Object} An optional object with properties to set on the + * rule + * + * Returns: + * {} + */ + initialize: function(options) { + this.symbolizer = {}; + + OpenLayers.Util.extend(this, options); + }, + + /** + * APIMethod: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + for (var i in this.symbolizer) { + this.symbolizer[i] = null; + } + this.symbolizer = null; + }, + + /** + * APIMethod: evaluate + * evaluates this rule for a specific feature + * + * Parameters: + * feature - {} feature to apply the rule to. + * + * Returns: + * {boolean} true if the rule applies, false if it does not. + * This rule is the default rule and always returns true. + */ + evaluate: function(feature) { + var context = this.getContext(feature); + var applies = true; + + if (this.minScaleDenominator || this.maxScaleDenominator) { + var scale = feature.layer.map.getScale(); + } + + // check if within minScale/maxScale bounds + if (this.minScaleDenominator) { + applies = scale >= OpenLayers.Style.createLiteral( + this.minScaleDenominator, context); + } + if (applies && this.maxScaleDenominator) { + applies = scale < OpenLayers.Style.createLiteral( + this.maxScaleDenominator, context); + } + + return applies; + }, + + /** + * Method: getContext + * Gets the context for evaluating this rule + * + * Paramters: + * feature - {} feature to take the context from if + * none is specified. + */ + getContext: function(feature) { + var context = this.context; + if (!context) { + context = feature.attributes || feature.data; + } + return context; + }, + + CLASS_NAME: "OpenLayers.Rule" }); \ No newline at end of file diff --git a/lib/OpenLayers/Rule/Comparison.js b/lib/OpenLayers/Rule/Comparison.js index 7b600d3225..6be7a7fb58 100644 --- a/lib/OpenLayers/Rule/Comparison.js +++ b/lib/OpenLayers/Rule/Comparison.js @@ -1,204 +1,206 @@ -/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD - * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the - * full text of the license. */ - -/** - * @requires OpenLayers/Rule.js - */ - -/** - * Class: OpenLayers.Rule.Comparison - * This class represents the comparison rules, as being used for rule-based - * SLD styling - * - * Inherits from - * - - */ -OpenLayers.Rule.Comparison = OpenLayers.Class(OpenLayers.Rule, { - - /** - * APIProperty: type - * {String} type: type of the comparison. This is one of - * - OpenLayers.Rule.Comparison.EQUAL_TO = "=="; - * - OpenLayers.Rule.Comparison.NOT_EQUAL_TO = "!="; - * - OpenLayers.Rule.Comparison.LESS_THAN = "<"; - * - OpenLayers.Rule.Comparison.GREATER_THAN = ">"; - * - OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO = "<="; - * - OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO = ">="; - * - OpenLayers.Rule.Comparison.BETWEEN = ".."; - * - OpenLayers.Rule.Comparison.LIKE = "~"; - */ - type: null, - - /** - * APIProperty: property - * {String} - * name of the feature attribute to compare - */ - property: null, - - /** - * APIProperty: value - * {Number} or {String} - * comparison value for binary comparisons. In the case of a String, this - * can be a combination of text and propertyNames in the form - * "literal ${propertyName}" - */ - value: null, - - /** - * APIProperty: lowerBoundary - * {Number} or {String} - * lower boundary for between comparisons. In the case of a String, this - * can be a combination of text and propertyNames in the form - * "literal ${propertyName}" - */ - lowerBoundary: null, - - /** - * APIProperty: upperBoundary - * {Number} or {String} - * upper boundary for between comparisons. In the case of a String, this - * can be a combination of text and propertyNames in the form - * "literal ${propertyName}" - */ - upperBoundary: null, - - /** - * Constructor: OpenLayers.Rule.Comparison - * Creates a comparison rule. - * - * Parameters: - * params - {Object} Hash of parameters for this rule: - * - - * - value: - * options - {Object} An optional object with properties to set on the - * rule - * - * Returns: - * {} - */ - initialize: function(options) { - OpenLayers.Rule.prototype.initialize.apply(this, [options]); - }, - - /** - * APIMethod: evaluate - * evaluates this rule for a specific feature - * - * Parameters: - * feature - {} feature to apply the rule to. - * - * Returns: - * {boolean} true if the rule applies, false if it does not - */ - evaluate: function(feature) { - var attributes = feature.attributes || feature.data; - switch(this.type) { - case OpenLayers.Rule.Comparison.EQUAL_TO: - case OpenLayers.Rule.Comparison.LESS_THAN: - case OpenLayers.Rule.Comparison.GREATER_THAN: - case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO: - case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO: - return this.binaryCompare(feature, this.property, this.value); - - case OpenLayers.Rule.Comparison.BETWEEN: - var result = - attributes[this.property] > this.lowerBoundary; - result = result && - attributes[this.property] < this.upperBoundary; - return result; - case OpenLayers.Rule.Comparison.LIKE: - var regexp = new RegExp(this.value, - "gi"); - return regexp.test(attributes[this.property]); - } - }, - - /** - * APIMethod: value2regex - * Converts the value of this rule into a regular expression string, - * according to the wildcard characters specified. This method has to - * be called after instantiation of this class, if the value is not a - * regular expression already. - * - * Parameters: - * wildCard - {} wildcard character in the above value, default - * is "*" - * singleChar - {) single-character wildcard in the above value - * default is "." - * escape - {) escape character in the above value, default is - * "!" - * - * Returns: - * {String} regular expression string - */ - value2regex: function(wildCard, singleChar, escapeChar) { - if (wildCard == ".") { - var msg = "'.' is an unsupported wildCard character for "+ - "OpenLayers.Rule.Comparison"; - OpenLayers.Console.error(msg); - return null; - } - - // set UMN MapServer defaults for unspecified parameters - wildCard = wildCard ? wildCard : "*"; - singleChar = singleChar ? singleChar : "."; - escapeChar = escapeChar ? escapeChar : "!"; - - this.value = this.value.replace( - new RegExp("\\"+escapeChar, "g"), "\\"); - this.value = this.value.replace( - new RegExp("\\"+singleChar, "g"), "."); - this.value = this.value.replace( - new RegExp("\\"+wildCard, "g"), ".*"); - this.value = this.value.replace( - new RegExp("\\\\.\\*", "g"), "\\"+wildCard); - this.value = this.value.replace( - new RegExp("\\\\\\.", "g"), "\\"+singleChar); - - return this.value; - }, - - /** - * Function: binaryCompare - * Compares a feature property to a rule value - * - * Parameters: - * feature - {} - * property - {String} or {Number} - * value - {String} or {Number}, same as property - * - * Returns: - * {boolean} - */ - binaryCompare: function(feature, property, value) { - var attributes = feature.attributes || feature.data; - switch (this.type) { - case OpenLayers.Rule.Comparison.EQUAL_TO: - return attributes[property] == value; - case OpenLayers.Rule.Comparison.NOT_EQUAL_TO: - return attributes[property] != value; - case OpenLayers.Rule.Comparison.LESS_THAN: - return attributes[property] < value; - case OpenLayers.Rule.Comparison.GREATER_THAN: - return attributes[property] > value; - case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO: - return attributes[property] <= value; - case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO: - return attributes[property] >= value; - } - }, - - CLASS_NAME: "OpenLayers.Rule.Comparison" -}); - - -OpenLayers.Rule.Comparison.EQUAL_TO = "=="; -OpenLayers.Rule.Comparison.NOT_EQUAL_TO = "!="; -OpenLayers.Rule.Comparison.LESS_THAN = "<"; -OpenLayers.Rule.Comparison.GREATER_THAN = ">"; -OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO = "<="; -OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO = ">="; -OpenLayers.Rule.Comparison.BETWEEN = ".."; -OpenLayers.Rule.Comparison.LIKE = "~"; +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + +/** + * @requires OpenLayers/Rule.js + */ + +/** + * Class: OpenLayers.Rule.Comparison + * This class represents the comparison rules, as being used for rule-based + * SLD styling + * + * Inherits from + * - + */ +OpenLayers.Rule.Comparison = OpenLayers.Class(OpenLayers.Rule, { + + /** + * APIProperty: type + * {String} type: type of the comparison. This is one of + * - OpenLayers.Rule.Comparison.EQUAL_TO = "=="; + * - OpenLayers.Rule.Comparison.NOT_EQUAL_TO = "!="; + * - OpenLayers.Rule.Comparison.LESS_THAN = "<"; + * - OpenLayers.Rule.Comparison.GREATER_THAN = ">"; + * - OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO = "<="; + * - OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO = ">="; + * - OpenLayers.Rule.Comparison.BETWEEN = ".."; + * - OpenLayers.Rule.Comparison.LIKE = "~"; + */ + type: null, + + /** + * APIProperty: property + * {String} + * name of the context property to compare + */ + property: null, + + /** + * APIProperty: value + * {Number} or {String} + * comparison value for binary comparisons. In the case of a String, this + * can be a combination of text and propertyNames in the form + * "literal ${propertyName}" + */ + value: null, + + /** + * APIProperty: lowerBoundary + * {Number} or {String} + * lower boundary for between comparisons. In the case of a String, this + * can be a combination of text and propertyNames in the form + * "literal ${propertyName}" + */ + lowerBoundary: null, + + /** + * APIProperty: upperBoundary + * {Number} or {String} + * upper boundary for between comparisons. In the case of a String, this + * can be a combination of text and propertyNames in the form + * "literal ${propertyName}" + */ + upperBoundary: null, + + /** + * Constructor: OpenLayers.Rule.Comparison + * Creates a comparison rule. + * + * Parameters: + * params - {Object} Hash of parameters for this rule: + * - + * - value: + * options - {Object} An optional object with properties to set on the + * rule + * + * Returns: + * {} + */ + initialize: function(options) { + OpenLayers.Rule.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: evaluate + * evaluates this rule for a specific context + * + * Parameters: + * context - {Object} context to apply the rule to. + * + * Returns: + * {boolean} true if the rule applies, false if it does not + */ + evaluate: function(feature) { + if (!OpenLayers.Rule.prototype.evaluate.apply(this, arguments)) { + return false; + } + var context = this.getContext(feature); + switch(this.type) { + case OpenLayers.Rule.Comparison.EQUAL_TO: + case OpenLayers.Rule.Comparison.LESS_THAN: + case OpenLayers.Rule.Comparison.GREATER_THAN: + case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO: + case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO: + return this.binaryCompare(context, this.property, this.value); + + case OpenLayers.Rule.Comparison.BETWEEN: + var result = + context[this.property] > this.lowerBoundary; + result = result && + context[this.property] < this.upperBoundary; + return result; + case OpenLayers.Rule.Comparison.LIKE: + var regexp = new RegExp(this.value, + "gi"); + return regexp.test(context[this.property]); + } + }, + + /** + * APIMethod: value2regex + * Converts the value of this rule into a regular expression string, + * according to the wildcard characters specified. This method has to + * be called after instantiation of this class, if the value is not a + * regular expression already. + * + * Parameters: + * wildCard - {} wildcard character in the above value, default + * is "*" + * singleChar - {) single-character wildcard in the above value + * default is "." + * escape - {) escape character in the above value, default is + * "!" + * + * Returns: + * {String} regular expression string + */ + value2regex: function(wildCard, singleChar, escapeChar) { + if (wildCard == ".") { + var msg = "'.' is an unsupported wildCard character for "+ + "OpenLayers.Rule.Comparison"; + OpenLayers.Console.error(msg); + return null; + } + + // set UMN MapServer defaults for unspecified parameters + wildCard = wildCard ? wildCard : "*"; + singleChar = singleChar ? singleChar : "."; + escapeChar = escapeChar ? escapeChar : "!"; + + this.value = this.value.replace( + new RegExp("\\"+escapeChar, "g"), "\\"); + this.value = this.value.replace( + new RegExp("\\"+singleChar, "g"), "."); + this.value = this.value.replace( + new RegExp("\\"+wildCard, "g"), ".*"); + this.value = this.value.replace( + new RegExp("\\\\.\\*", "g"), "\\"+wildCard); + this.value = this.value.replace( + new RegExp("\\\\\\.", "g"), "\\"+singleChar); + + return this.value; + }, + + /** + * Function: binaryCompare + * Compares a feature property to a rule value + * + * Parameters: + * context - {Object} + * property - {String} or {Number} + * value - {String} or {Number}, same as property + * + * Returns: + * {boolean} + */ + binaryCompare: function(context, property, value) { + switch (this.type) { + case OpenLayers.Rule.Comparison.EQUAL_TO: + return context[property] == value; + case OpenLayers.Rule.Comparison.NOT_EQUAL_TO: + return context[property] != value; + case OpenLayers.Rule.Comparison.LESS_THAN: + return context[property] < value; + case OpenLayers.Rule.Comparison.GREATER_THAN: + return context[property] > value; + case OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO: + return context[property] <= value; + case OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO: + return context[property] >= value; + } + }, + + CLASS_NAME: "OpenLayers.Rule.Comparison" +}); + + +OpenLayers.Rule.Comparison.EQUAL_TO = "=="; +OpenLayers.Rule.Comparison.NOT_EQUAL_TO = "!="; +OpenLayers.Rule.Comparison.LESS_THAN = "<"; +OpenLayers.Rule.Comparison.GREATER_THAN = ">"; +OpenLayers.Rule.Comparison.LESS_THAN_OR_EQUAL_TO = "<="; +OpenLayers.Rule.Comparison.GREATER_THAN_OR_EQUAL_TO = ">="; +OpenLayers.Rule.Comparison.BETWEEN = ".."; +OpenLayers.Rule.Comparison.LIKE = "~"; diff --git a/lib/OpenLayers/Rule/FeatureId.js b/lib/OpenLayers/Rule/FeatureId.js index 082abdcb12..806933d9ec 100644 --- a/lib/OpenLayers/Rule/FeatureId.js +++ b/lib/OpenLayers/Rule/FeatureId.js @@ -1,66 +1,69 @@ -/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD - * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Rule.js - */ - -/** - * Class: OpenLayers.Rule.FeatureId - * This class represents a ogc:FeatureId Rule, as being used for rule-based SLD - * styling - * - * Inherits from - * - - */ -OpenLayers.Rule.FeatureId = OpenLayers.Class(OpenLayers.Rule, { - - /** - * APIProperty: fids - * {Array()} Feature Ids to evaluate this rule against. To be passed - * To be passed inside the params object. - */ - fids: null, - - /** - * Constructor: OpenLayers.Rule.FeatureId - * Creates an ogc:FeatureId rule. - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * rule - * - * Returns: - * {} - */ - initialize: function(options) { - this.fids = []; - OpenLayers.Rule.prototype.initialize.apply(this, [options]); - }, - - /** - * APIMethod: evaluate - * evaluates this rule for a specific feature - * - * Parameters: - * feature - {} feature to apply the rule to. - * For vector features, the check is run against the fid, - * for plain features against the id. - * - * Returns: - * {boolean} true if the rule applies, false if it does not - */ - evaluate: function(feature) { - for (var i=0; i + */ +OpenLayers.Rule.FeatureId = OpenLayers.Class(OpenLayers.Rule, { + + /** + * APIProperty: fids + * {Array()} Feature Ids to evaluate this rule against. To be passed + * To be passed inside the params object. + */ + fids: null, + + /** + * Constructor: OpenLayers.Rule.FeatureId + * Creates an ogc:FeatureId rule. + * + * Parameters: + * options - {Object} An optional object with properties to set on the + * rule + * + * Returns: + * {} + */ + initialize: function(options) { + this.fids = []; + OpenLayers.Rule.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: evaluate + * evaluates this rule for a specific feature + * + * Parameters: + * feature - {} feature to apply the rule to. + * For vector features, the check is run against the fid, + * for plain features against the id. + * + * Returns: + * {boolean} true if the rule applies, false if it does not + */ + evaluate: function(feature) { + if (!OpenLayers.Rule.prototype.evaluate.apply(this, arguments)) { + return false; + } + for (var i=0; i - */ -OpenLayers.Rule.Logical = OpenLayers.Class(OpenLayers.Rule, { - - /** - * APIProperty: children - * {Array()} child rules for this rule - */ - children: null, - - /** - * APIProperty: type - * {String} type of logical operator. Available types are: - * - OpenLayers.Rule.Locical.AND = "&&"; - * - OpenLayers.Rule.Logical.OR = "||"; - * - OpenLayers.Rule.Logical.NOT = "!"; - */ - type: null, - - /** - * Constructor: OpenLayers.Rule.Logical - * Creates a logical rule (And, Or, Not). - * - * Parameters: - * options - {Object} An optional object with properties to set on the - * rule - * - * Returns: - * {} - */ - initialize: function(options) { - this.children = []; - OpenLayers.Rule.prototype.initialize.apply(this, [options]); - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - for (var i=0; i} feature to apply the rule to. - * - * Returns: - * {boolean} true if the rule applies, false if it does not - */ - evaluate: function(feature) { - switch(this.type) { - case OpenLayers.Rule.Logical.AND: - for (var i=0; i + */ +OpenLayers.Rule.Logical = OpenLayers.Class(OpenLayers.Rule, { + + /** + * APIProperty: children + * {Array()} child rules for this rule + */ + rules: null, + + /** + * APIProperty: type + * {String} type of logical operator. Available types are: + * - OpenLayers.Rule.Locical.AND = "&&"; + * - OpenLayers.Rule.Logical.OR = "||"; + * - OpenLayers.Rule.Logical.NOT = "!"; + */ + type: null, + + /** + * Constructor: OpenLayers.Rule.Logical + * Creates a logical rule (And, Or, Not). + * + * Parameters: + * options - {Object} An optional object with properties to set on the + * rule + * + * Returns: + * {} + */ + initialize: function(options) { + this.rules = []; + OpenLayers.Rule.prototype.initialize.apply(this, [options]); + }, + + /** + * APIMethod: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + for (var i=0; i} feature to apply the rule to. + * + * Returns: + * {boolean} true if the rule applies, false if it does not + */ + evaluate: function(feature) { + if (!OpenLayers.Rule.prototype.evaluate.apply(this, arguments)) { + return false; + } + switch(this.type) { + case OpenLayers.Rule.Logical.AND: + for (var i=0; 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, - - /** - * Property: rules - * Array({}) - */ - rules: null, - - /** - * Property: defaultStyle - * {Object} hash of style properties to use as default for merging - * rule-based style symbolizers onto. If no rules are defined, createStyle - * will return this style. - */ - defaultStyle: null, - - /** - * Property: propertyStyles - * {Hash of Boolean} cache of style properties that need to be parsed for - * propertyNames. Property names are keys, values won't be used. - */ - propertyStyles: null, - - - /** - * Constructor: OpenLayers.Style - * Creates a UserStyle. - * - * Parameters: - * style - {Object} Optional hash of style properties that will be - * used as default style for this style object. This style - * applies if no rules are specified. Symbolizers defined in - * rules will extend this default style. - * options - {Object} An optional object with properties to set on the - * userStyle - * - * Return: - * {} - */ - initialize: function(style, options) { - this.rules = []; - - // use the default style from OpenLayers.Feature.Vector if no style - // was given in the constructor - this.setDefaultStyle(style || - OpenLayers.Feature.Vector.style["default"]); - - OpenLayers.Util.extend(this, options); - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - for (var i=0; i} feature to evaluate rules for - * baseStyle - {Object} hash of styles feature styles to extend - * - * Returns: - * {} hash of feature styles - */ - createStyle: function(feature) { - var style = OpenLayers.Util.extend({}, this.defaultStyle); - - var rules = this.rules; - - var rule; - var elseRules = []; - var appliedRules = false; - for(var i=0; i= OpenLayers.Style.createLiteral( - rule.minScaleDenominator, feature); - } - if (applies && rule.maxScaleDenominator) { - applies = scale < OpenLayers.Style.createLiteral( - rule.maxScaleDenominator, feature); - } - - if(applies) { - if(rule instanceof OpenLayers.Rule && rule.elseFilter) { - elseRules.push(rule); - } else { - appliedRules = true; - this.applySymbolizer(rule, style, feature); - } - } - } - - // if no other rules apply, apply the rules with else filters - if(appliedRules == false && elseRules.length > 0) { - appliedRules = true; - for(var i=0; i 0 && appliedRules == false) { - style.display = "none"; - } else { - style.display = ""; - } - - return style; - }, - - /** - * Method: applySymbolizer - * - * Parameters: - * rule - {OpenLayers.Rule} - * style - {Object} - * feature - {} - * - * Returns: - * {Object} A style with new symbolizer applied. - */ - applySymbolizer: function(rule, style, feature) { - var symbolizerPrefix = feature.geometry ? - this.getSymbolizerPrefix(feature.geometry) : - OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; - - // merge the style with the current style - var symbolizer = rule.symbolizer[symbolizerPrefix]; - return OpenLayers.Util.extend(style, symbolizer); - }, - - /** - * Method: createLiterals - * creates literals for all style properties that have an entry in - * . - * - * Parameters: - * style - {Object} style to create literals for. Will be modified - * inline. - * feature - {} feature to take properties from - * - * Returns; - * {Object} the modified style - */ - createLiterals: function(style, feature) { - for (var i in this.propertyStyles) { - style[i] = OpenLayers.Style.createLiteral(style[i], feature); - } - return style; - }, - - /** - * Method: findPropertyStyles - * Looks into all rules for this style and the defaultStyle to collect - * all the style hash property names containing ${...} strings that have - * to be replaced using the createLiteral method before returning them. - * - * Returns: - * {Object} hash of property names that need createLiteral parsing. The - * name of the property is the key, and the value is true; - */ - findPropertyStyles: function() { - var propertyStyles = {}; - - // check the default style - var style = this.defaultStyle; - for (var i in style) { - if (typeof style[i] == "string" && style[i].match(/\$\{\w+\}/)) { - propertyStyles[i] = true; - } - } - - // walk through all rules to check for properties in their symbolizer - var rules = this.rules; - var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; - for (var i in rules) { - for (var s=0; s)} - */ - addRules: function(rules) { - this.rules = this.rules.concat(rules); - this.propertyStyles = this.findPropertyStyles(); - }, - - /** - * APIMethod: setDefaultStyle - * Sets the default style for this style object. - * - * Parameters: - * style - {Object} Hash of style properties - */ - setDefaultStyle: function(style) { - this.defaultStyle = style; - this.propertyStyles = this.findPropertyStyles(); - }, - - /** - * Method: getSymbolizerPrefix - * Returns the correct symbolizer prefix according to the - * geometry type of the passed geometry - * - * Parameters: - * geometry {} - * - * Returns: - * {String} key of the according symbolizer - */ - getSymbolizerPrefix: function(geometry) { - var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; - for (var i=0; i} feature to take attribute values from - * - * Returns: - * {String} the parsed value. In the example of the value parameter above, the - * result would be "foo valueOfBar", assuming that the passed feature has an - * attribute named "bar" with the value "valueOfBar". - */ -OpenLayers.Style.createLiteral = function(value, feature) { - if (typeof value == "string" && value.indexOf("${") != -1) { - var attributes = feature.attributes || feature.data; - value = OpenLayers.String.format(value, attributes) - value = isNaN(value) ? value : parseFloat(value); - } - return value; -} - -/** - * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES - * {Array} prefixes of the sld symbolizers. These are the - * same as the main geometry types - */ -OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon']; +/* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD + * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the + * full text of the license. */ + + +/** + * @requires OpenLayers/Util.js + * @requires OpenLayers/Feature/Vector.js + */ + +/** + * Class: OpenLayers.Style + * This class represents a UserStyle obtained + * from a SLD, containing styling rules. + */ +OpenLayers.Style = OpenLayers.Class({ + + /** + * APIProperty: name + * {String} + */ + name: null, + + /** + * APIProperty: layerName + * {} 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, + + /** + * Property: rules + * Array({}) + */ + rules: null, + + /** + * Property: defaultStyle + * {Object} hash of style properties to use as default for merging + * rule-based style symbolizers onto. If no rules are defined, createStyle + * will return this style. + */ + defaultStyle: null, + + /** + * Property: propertyStyles + * {Hash of Boolean} cache of style properties that need to be parsed for + * propertyNames. Property names are keys, values won't be used. + */ + propertyStyles: null, + + + /** + * Constructor: OpenLayers.Style + * Creates a UserStyle. + * + * Parameters: + * style - {Object} Optional hash of style properties that will be + * used as default style for this style object. This style + * applies if no rules are specified. Symbolizers defined in + * rules will extend this default style. + * options - {Object} An optional object with properties to set on the + * userStyle + * + * Return: + * {} + */ + initialize: function(style, options) { + this.rules = []; + + // use the default style from OpenLayers.Feature.Vector if no style + // was given in the constructor + this.setDefaultStyle(style || + OpenLayers.Feature.Vector.style["default"]); + + OpenLayers.Util.extend(this, options); + }, + + /** + * APIMethod: destroy + * nullify references to prevent circular references and memory leaks + */ + destroy: function() { + for (var i=0; i} feature to evaluate rules for + * baseStyle - {Object} hash of styles feature styles to extend + * + * Returns: + * {} hash of feature styles + */ + createStyle: function(feature) { + var style = OpenLayers.Util.extend({}, this.defaultStyle); + + var rules = this.rules; + + var rule, context; + var elseRules = []; + var appliedRules = false; + for(var i=0; i 0) { + appliedRules = true; + for(var i=0; i 0 && appliedRules == false) { + style.display = "none"; + } else { + style.display = ""; + } + + return style; + }, + + /** + * Method: applySymbolizer + * + * Parameters: + * rule - {OpenLayers.Rule} + * style - {Object} + * feature - {} + * context - {Object} + * + * Returns: + * {Object} A style with new symbolizer applied. + */ + applySymbolizer: function(rule, style, feature, context) { + var symbolizerPrefix = feature.geometry ? + this.getSymbolizerPrefix(feature.geometry) : + OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; + + var symbolizer = rule.symbolizer[symbolizerPrefix]; + + // merge the style with the current style + return this.createLiterals( + OpenLayers.Util.extend(style, symbolizer), context); + }, + + /** + * Method: createLiterals + * creates literals for all style properties that have an entry in + * . + * + * Parameters: + * style - {Object} style to create literals for. Will be modified + * inline. + * context - {Object} context to take property values from. Defaults to + * feature.attributes (or feature.data, if attributes are not + * available) + * + * Returns; + * {Object} the modified style + */ + createLiterals: function(style, context) { + for (var i in this.propertyStyles) { + style[i] = OpenLayers.Style.createLiteral(style[i], context); + } + return style; + }, + + /** + * Method: findPropertyStyles + * Looks into all rules for this style and the defaultStyle to collect + * all the style hash property names containing ${...} strings that have + * to be replaced using the createLiteral method before returning them. + * + * Returns: + * {Object} hash of property names that need createLiteral parsing. The + * name of the property is the key, and the value is true; + */ + findPropertyStyles: function() { + var propertyStyles = {}; + + // check the default style + var style = this.defaultStyle; + for (var i in style) { + if (typeof style[i] == "string" && style[i].match(/\$\{\w+\}/)) { + propertyStyles[i] = true; + } + } + + // walk through all rules to check for properties in their symbolizer + var rules = this.rules; + var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; + for (var i in rules) { + for (var s=0; s)} + */ + addRules: function(rules) { + this.rules = this.rules.concat(rules); + this.propertyStyles = this.findPropertyStyles(); + }, + + /** + * APIMethod: setDefaultStyle + * Sets the default style for this style object. + * + * Parameters: + * style - {Object} Hash of style properties + */ + setDefaultStyle: function(style) { + this.defaultStyle = style; + this.propertyStyles = this.findPropertyStyles(); + }, + + /** + * Method: getSymbolizerPrefix + * Returns the correct symbolizer prefix according to the + * geometry type of the passed geometry + * + * Parameters: + * geometry {} + * + * Returns: + * {String} key of the according symbolizer + */ + getSymbolizerPrefix: function(geometry) { + var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES; + for (var i=0; i - - - - - - - + + + + + + + + diff --git a/tests/test_Style.html b/tests/test_Style.html index 3c9af04ea2..c831a5601f 100644 --- a/tests/test_Style.html +++ b/tests/test_Style.html @@ -1,131 +1,146 @@ - - - - - - -
- - + + + + + + +
+ +