summaryrefslogtreecommitdiff
path: root/misc/openlayers/lib/OpenLayers/Style.js
diff options
context:
space:
mode:
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Style.js')
-rw-r--r--misc/openlayers/lib/OpenLayers/Style.js448
1 files changed, 448 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Style.js b/misc/openlayers/lib/OpenLayers/Style.js
new file mode 100644
index 0000000..39c4a48
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Style.js
@@ -0,0 +1,448 @@
+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+
+/**
+ * @requires OpenLayers/BaseTypes/Class.js
+ * @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({
+
+ /**
+ * Property: id
+ * {String} A unique id for this session.
+ */
+ id: null,
+
+ /**
+ * APIProperty: name
+ * {String}
+ */
+ name: null,
+
+ /**
+ * Property: title
+ * {String} Title of this style (set if included in SLD)
+ */
+ title: null,
+
+ /**
+ * Property: description
+ * {String} Description of this style (set if abstract is included in SLD)
+ */
+ description: null,
+
+ /**
+ * APIProperty: layerName
+ * {<String>} 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(<OpenLayers.Rule>)}
+ */
+ rules: null,
+
+ /**
+ * APIProperty: context
+ * {Object} An optional object with properties that symbolizers' property
+ * values should be evaluated against. If no context is specified,
+ * feature.attributes will be used
+ */
+ context: null,
+
+ /**
+ * Property: defaultStyle
+ * {Object} hash of style properties to use as default for merging
+ * rule-based style symbolizers onto. If no rules are defined,
+ * createSymbolizer will return this style. If <defaultsPerSymbolizer> is set to
+ * true, the defaultStyle will only be taken into account if there are
+ * rules defined.
+ */
+ defaultStyle: null,
+
+ /**
+ * Property: defaultsPerSymbolizer
+ * {Boolean} If set to true, the <defaultStyle> will extend the symbolizer
+ * of every rule. Properties of the <defaultStyle> will also be used to set
+ * missing symbolizer properties if the symbolizer has stroke, fill or
+ * graphic set to true. Default is false.
+ */
+ defaultsPerSymbolizer: false,
+
+ /**
+ * 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
+ * style.
+ *
+ * Valid options:
+ * rules - {Array(<OpenLayers.Rule>)} List of rules to be added to the
+ * style.
+ *
+ * Returns:
+ * {<OpenLayers.Style>}
+ */
+ initialize: function(style, options) {
+
+ OpenLayers.Util.extend(this, options);
+ this.rules = [];
+ if(options && options.rules) {
+ this.addRules(options.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"]);
+
+ 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<len; i++) {
+ this.rules[i].destroy();
+ this.rules[i] = null;
+ }
+ this.rules = null;
+ this.defaultStyle = null;
+ },
+
+ /**
+ * Method: createSymbolizer
+ * creates a style by applying all feature-dependent rules to the base
+ * style.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature>} feature to evaluate rules for
+ *
+ * Returns:
+ * {Object} symbolizer hash
+ */
+ createSymbolizer: function(feature) {
+ var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(
+ OpenLayers.Util.extend({}, this.defaultStyle), feature);
+
+ var rules = this.rules;
+
+ var rule, context;
+ var elseRules = [];
+ var appliedRules = false;
+ for(var i=0, len=rules.length; i<len; i++) {
+ rule = rules[i];
+ // does the rule apply?
+ var applies = rule.evaluate(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, len=elseRules.length; i<len; i++) {
+ this.applySymbolizer(elseRules[i], style, feature);
+ }
+ }
+
+ // don't display if there were rules but none applied
+ if(rules.length > 0 && appliedRules == false) {
+ style.display = "none";
+ }
+
+ if (style.label != null && typeof style.label !== "string") {
+ style.label = String(style.label);
+ }
+
+ return style;
+ },
+
+ /**
+ * Method: applySymbolizer
+ *
+ * Parameters:
+ * rule - {<OpenLayers.Rule>}
+ * style - {Object}
+ * feature - {<OpenLayer.Feature.Vector>}
+ *
+ * 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];
+
+ var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;
+
+ if(this.defaultsPerSymbolizer === true) {
+ var defaults = this.defaultStyle;
+ OpenLayers.Util.applyDefaults(symbolizer, {
+ pointRadius: defaults.pointRadius
+ });
+ if(symbolizer.stroke === true || symbolizer.graphic === true) {
+ OpenLayers.Util.applyDefaults(symbolizer, {
+ strokeWidth: defaults.strokeWidth,
+ strokeColor: defaults.strokeColor,
+ strokeOpacity: defaults.strokeOpacity,
+ strokeDashstyle: defaults.strokeDashstyle,
+ strokeLinecap: defaults.strokeLinecap
+ });
+ }
+ if(symbolizer.fill === true || symbolizer.graphic === true) {
+ OpenLayers.Util.applyDefaults(symbolizer, {
+ fillColor: defaults.fillColor,
+ fillOpacity: defaults.fillOpacity
+ });
+ }
+ if(symbolizer.graphic === true) {
+ OpenLayers.Util.applyDefaults(symbolizer, {
+ pointRadius: this.defaultStyle.pointRadius,
+ externalGraphic: this.defaultStyle.externalGraphic,
+ graphicName: this.defaultStyle.graphicName,
+ graphicOpacity: this.defaultStyle.graphicOpacity,
+ graphicWidth: this.defaultStyle.graphicWidth,
+ graphicHeight: this.defaultStyle.graphicHeight,
+ graphicXOffset: this.defaultStyle.graphicXOffset,
+ graphicYOffset: this.defaultStyle.graphicYOffset
+ });
+ }
+ }
+
+ // merge the style with the current style
+ return this.createLiterals(
+ OpenLayers.Util.extend(style, symbolizer), feature);
+ },
+
+ /**
+ * Method: createLiterals
+ * creates literals for all style properties that have an entry in
+ * <this.propertyStyles>.
+ *
+ * Parameters:
+ * style - {Object} style to create literals for. Will be modified
+ * inline.
+ * feature - {Object}
+ *
+ * Returns:
+ * {Object} the modified style
+ */
+ createLiterals: function(style, feature) {
+ var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);
+ OpenLayers.Util.extend(context, this.context);
+
+ for (var i in this.propertyStyles) {
+ style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);
+ }
+ 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;
+ this.addPropertyStyles(propertyStyles, style);
+
+ // walk through all rules to check for properties in their symbolizer
+ var rules = this.rules;
+ var symbolizer, value;
+ for (var i=0, len=rules.length; i<len; i++) {
+ symbolizer = rules[i].symbolizer;
+ for (var key in symbolizer) {
+ value = symbolizer[key];
+ if (typeof value == "object") {
+ // symbolizer key is "Point", "Line" or "Polygon"
+ this.addPropertyStyles(propertyStyles, value);
+ } else {
+ // symbolizer is a hash of style properties
+ this.addPropertyStyles(propertyStyles, symbolizer);
+ break;
+ }
+ }
+ }
+ return propertyStyles;
+ },
+
+ /**
+ * Method: addPropertyStyles
+ *
+ * Parameters:
+ * propertyStyles - {Object} hash to add new property styles to. Will be
+ * modified inline
+ * symbolizer - {Object} search this symbolizer for property styles
+ *
+ * Returns:
+ * {Object} propertyStyles hash
+ */
+ addPropertyStyles: function(propertyStyles, symbolizer) {
+ var property;
+ for (var key in symbolizer) {
+ property = symbolizer[key];
+ if (typeof property == "string" &&
+ property.match(/\$\{\w+\}/)) {
+ propertyStyles[key] = true;
+ }
+ }
+ return propertyStyles;
+ },
+
+ /**
+ * APIMethod: addRules
+ * Adds rules to this style.
+ *
+ * Parameters:
+ * rules - {Array(<OpenLayers.Rule>)}
+ */
+ addRules: function(rules) {
+ Array.prototype.push.apply(this.rules, 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 - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {String} key of the according symbolizer
+ */
+ getSymbolizerPrefix: function(geometry) {
+ var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
+ for (var i=0, len=prefixes.length; i<len; i++) {
+ if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {
+ return prefixes[i];
+ }
+ }
+ },
+
+ /**
+ * APIMethod: clone
+ * Clones this style.
+ *
+ * Returns:
+ * {<OpenLayers.Style>} Clone of this style.
+ */
+ clone: function() {
+ var options = OpenLayers.Util.extend({}, this);
+ // clone rules
+ if(this.rules) {
+ options.rules = [];
+ for(var i=0, len=this.rules.length; i<len; ++i) {
+ options.rules.push(this.rules[i].clone());
+ }
+ }
+ // clone context
+ options.context = this.context && OpenLayers.Util.extend({}, this.context);
+ //clone default style
+ var defaultStyle = OpenLayers.Util.extend({}, this.defaultStyle);
+ return new OpenLayers.Style(defaultStyle, options);
+ },
+
+ CLASS_NAME: "OpenLayers.Style"
+});
+
+
+/**
+ * Function: createLiteral
+ * converts a style value holding a combination of PropertyName and Literal
+ * into a Literal, taking the property values from the passed features.
+ *
+ * Parameters:
+ * value - {String} value to parse. If this string contains a construct like
+ * "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
+ * will be replaced by the value of the "bar" attribute of the passed
+ * feature.
+ * context - {Object} context to take attribute values from
+ * feature - {<OpenLayers.Feature.Vector>} optional feature to pass to
+ * <OpenLayers.String.format> for evaluating functions in the
+ * context.
+ * property - {String} optional, name of the property for which the literal is
+ * being created for evaluating functions in the context.
+ *
+ * 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, context, feature, property) {
+ if (typeof value == "string" && value.indexOf("${") != -1) {
+ value = OpenLayers.String.format(value, context, [feature, property]);
+ value = (isNaN(value) || !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', 'Text',
+ 'Raster'];