PageRenderTime 49ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/mapdev/public/mfbase/openlayers/lib/OpenLayers/Style.js

https://github.com/joshuaoa/MapDev
JavaScript | 411 lines | 164 code | 43 blank | 204 comment | 40 complexity | cf0e0772cfbf6b2d7d4d21c8b9e02316 MD5 | raw file
  1. /* Copyright (c) 2006-2008 MetaCarta, Inc., published under the Clear BSD
  2. * license. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  3. * full text of the license. */
  4. /**
  5. * @requires OpenLayers/Util.js
  6. * @requires OpenLayers/Feature/Vector.js
  7. */
  8. /**
  9. * Class: OpenLayers.Style
  10. * This class represents a UserStyle obtained
  11. * from a SLD, containing styling rules.
  12. */
  13. OpenLayers.Style = OpenLayers.Class({
  14. /**
  15. * APIProperty: name
  16. * {String}
  17. */
  18. name: null,
  19. /**
  20. * Property: title
  21. * {String} Title of this style (set if included in SLD)
  22. */
  23. title: null,
  24. /**
  25. * Property: description
  26. * {String} Description of this style (set if abstract is included in SLD)
  27. */
  28. description: null,
  29. /**
  30. * APIProperty: layerName
  31. * {<String>} name of the layer that this style belongs to, usually
  32. * according to the NamedLayer attribute of an SLD document.
  33. */
  34. layerName: null,
  35. /**
  36. * APIProperty: isDefault
  37. * {Boolean}
  38. */
  39. isDefault: false,
  40. /**
  41. * Property: rules
  42. * {Array(<OpenLayers.Rule>)}
  43. */
  44. rules: null,
  45. /**
  46. * Property: context
  47. * {Object} An optional object with properties that symbolizers' property
  48. * values should be evaluated against. If no context is specified,
  49. * feature.attributes will be used
  50. */
  51. context: null,
  52. /**
  53. * Property: defaultStyle
  54. * {Object} hash of style properties to use as default for merging
  55. * rule-based style symbolizers onto. If no rules are defined,
  56. * createSymbolizer will return this style. If <defaultsPerSymbolizer> is set to
  57. * true, the defaultStyle will only be taken into account if there are
  58. * rules defined.
  59. */
  60. defaultStyle: null,
  61. /**
  62. * Property: defaultsPerSymbolizer
  63. * {Boolean} If set to true, the <defaultStyle> will extend the symbolizer
  64. * of every rule. Properties of the <defaultStyle> will also be used to set
  65. * missing symbolizer properties if the symbolizer has stroke, fill or
  66. * graphic set to true. Default is false.
  67. */
  68. defaultsPerSymbolizer: false,
  69. /**
  70. * Property: propertyStyles
  71. * {Hash of Boolean} cache of style properties that need to be parsed for
  72. * propertyNames. Property names are keys, values won't be used.
  73. */
  74. propertyStyles: null,
  75. /**
  76. * Constructor: OpenLayers.Style
  77. * Creates a UserStyle.
  78. *
  79. * Parameters:
  80. * style - {Object} Optional hash of style properties that will be
  81. * used as default style for this style object. This style
  82. * applies if no rules are specified. Symbolizers defined in
  83. * rules will extend this default style.
  84. * options - {Object} An optional object with properties to set on the
  85. * style.
  86. *
  87. * Valid options:
  88. * rules - {Array(<OpenLayers.Rule>)} List of rules to be added to the
  89. * style.
  90. *
  91. * Return:
  92. * {<OpenLayers.Style>}
  93. */
  94. initialize: function(style, options) {
  95. OpenLayers.Util.extend(this, options);
  96. this.rules = [];
  97. if(options && options.rules) {
  98. this.addRules(options.rules);
  99. }
  100. // use the default style from OpenLayers.Feature.Vector if no style
  101. // was given in the constructor
  102. this.setDefaultStyle(style ||
  103. OpenLayers.Feature.Vector.style["default"]);
  104. },
  105. /**
  106. * APIMethod: destroy
  107. * nullify references to prevent circular references and memory leaks
  108. */
  109. destroy: function() {
  110. for (var i=0, len=this.rules.length; i<len; i++) {
  111. this.rules[i].destroy();
  112. this.rules[i] = null;
  113. }
  114. this.rules = null;
  115. this.defaultStyle = null;
  116. },
  117. /**
  118. * Method: createSymbolizer
  119. * creates a style by applying all feature-dependent rules to the base
  120. * style.
  121. *
  122. * Parameters:
  123. * feature - {<OpenLayers.Feature>} feature to evaluate rules for
  124. *
  125. * Returns:
  126. * {Object} symbolizer hash
  127. */
  128. createSymbolizer: function(feature) {
  129. var style = this.defaultsPerSymbolizer ? {} : this.createLiterals(
  130. OpenLayers.Util.extend({}, this.defaultStyle), feature);
  131. var rules = this.rules;
  132. var rule, context;
  133. var elseRules = [];
  134. var appliedRules = false;
  135. for(var i=0, len=rules.length; i<len; i++) {
  136. rule = rules[i];
  137. // does the rule apply?
  138. var applies = rule.evaluate(feature);
  139. if(applies) {
  140. if(rule instanceof OpenLayers.Rule && rule.elseFilter) {
  141. elseRules.push(rule);
  142. } else {
  143. appliedRules = true;
  144. this.applySymbolizer(rule, style, feature);
  145. }
  146. }
  147. }
  148. // if no other rules apply, apply the rules with else filters
  149. if(appliedRules == false && elseRules.length > 0) {
  150. appliedRules = true;
  151. for(var i=0, len=elseRules.length; i<len; i++) {
  152. this.applySymbolizer(elseRules[i], style, feature);
  153. }
  154. }
  155. // don't display if there were rules but none applied
  156. if(rules.length > 0 && appliedRules == false) {
  157. style.display = "none";
  158. }
  159. return style;
  160. },
  161. /**
  162. * Method: applySymbolizer
  163. *
  164. * Parameters:
  165. * rule - {OpenLayers.Rule}
  166. * style - {Object}
  167. * feature - {<OpenLayer.Feature.Vector>}
  168. *
  169. * Returns:
  170. * {Object} A style with new symbolizer applied.
  171. */
  172. applySymbolizer: function(rule, style, feature) {
  173. var symbolizerPrefix = feature.geometry ?
  174. this.getSymbolizerPrefix(feature.geometry) :
  175. OpenLayers.Style.SYMBOLIZER_PREFIXES[0];
  176. var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer;
  177. if(this.defaultsPerSymbolizer === true) {
  178. var defaults = this.defaultStyle;
  179. OpenLayers.Util.applyDefaults(symbolizer, {
  180. pointRadius: defaults.pointRadius
  181. });
  182. if(symbolizer.stroke === true || symbolizer.graphic === true) {
  183. OpenLayers.Util.applyDefaults(symbolizer, {
  184. strokeWidth: defaults.strokeWidth,
  185. strokeColor: defaults.strokeColor,
  186. strokeOpacity: defaults.strokeOpacity,
  187. strokeDashstyle: defaults.strokeDashstyle,
  188. strokeLinecap: defaults.strokeLinecap
  189. });
  190. }
  191. if(symbolizer.fill === true || symbolizer.graphic === true) {
  192. OpenLayers.Util.applyDefaults(symbolizer, {
  193. fillColor: defaults.fillColor,
  194. fillOpacity: defaults.fillOpacity
  195. });
  196. }
  197. if(symbolizer.graphic === true) {
  198. OpenLayers.Util.applyDefaults(symbolizer, {
  199. pointRadius: this.defaultStyle.pointRadius,
  200. externalGraphic: this.defaultStyle.externalGraphic,
  201. graphicName: this.defaultStyle.graphicName,
  202. graphicOpacity: this.defaultStyle.graphicOpacity,
  203. graphicWidth: this.defaultStyle.graphicWidth,
  204. graphicHeight: this.defaultStyle.graphicHeight,
  205. graphicXOffset: this.defaultStyle.graphicXOffset,
  206. graphicYOffset: this.defaultStyle.graphicYOffset
  207. });
  208. }
  209. }
  210. // merge the style with the current style
  211. return this.createLiterals(
  212. OpenLayers.Util.extend(style, symbolizer), feature);
  213. },
  214. /**
  215. * Method: createLiterals
  216. * creates literals for all style properties that have an entry in
  217. * <this.propertyStyles>.
  218. *
  219. * Parameters:
  220. * style - {Object} style to create literals for. Will be modified
  221. * inline.
  222. * feature - {Object}
  223. *
  224. * Returns:
  225. * {Object} the modified style
  226. */
  227. createLiterals: function(style, feature) {
  228. var context = OpenLayers.Util.extend({}, feature.attributes || feature.data);
  229. OpenLayers.Util.extend(context, this.context);
  230. for (var i in this.propertyStyles) {
  231. style[i] = OpenLayers.Style.createLiteral(style[i], context, feature, i);
  232. }
  233. return style;
  234. },
  235. /**
  236. * Method: findPropertyStyles
  237. * Looks into all rules for this style and the defaultStyle to collect
  238. * all the style hash property names containing ${...} strings that have
  239. * to be replaced using the createLiteral method before returning them.
  240. *
  241. * Returns:
  242. * {Object} hash of property names that need createLiteral parsing. The
  243. * name of the property is the key, and the value is true;
  244. */
  245. findPropertyStyles: function() {
  246. var propertyStyles = {};
  247. // check the default style
  248. var style = this.defaultStyle;
  249. this.addPropertyStyles(propertyStyles, style);
  250. // walk through all rules to check for properties in their symbolizer
  251. var rules = this.rules;
  252. var symbolizer, value;
  253. for (var i=0, len=rules.length; i<len; i++) {
  254. symbolizer = rules[i].symbolizer;
  255. for (var key in symbolizer) {
  256. value = symbolizer[key];
  257. if (typeof value == "object") {
  258. // symbolizer key is "Point", "Line" or "Polygon"
  259. this.addPropertyStyles(propertyStyles, value);
  260. } else {
  261. // symbolizer is a hash of style properties
  262. this.addPropertyStyles(propertyStyles, symbolizer);
  263. break;
  264. }
  265. }
  266. }
  267. return propertyStyles;
  268. },
  269. /**
  270. * Method: addPropertyStyles
  271. *
  272. * Parameters:
  273. * propertyStyles - {Object} hash to add new property styles to. Will be
  274. * modified inline
  275. * symbolizer - {Object} search this symbolizer for property styles
  276. *
  277. * Returns:
  278. * {Object} propertyStyles hash
  279. */
  280. addPropertyStyles: function(propertyStyles, symbolizer) {
  281. var property;
  282. for (var key in symbolizer) {
  283. property = symbolizer[key];
  284. if (typeof property == "string" &&
  285. property.match(/\$\{\w+\}/)) {
  286. propertyStyles[key] = true;
  287. }
  288. }
  289. return propertyStyles;
  290. },
  291. /**
  292. * APIMethod: addRules
  293. * Adds rules to this style.
  294. *
  295. * Parameters:
  296. * rules - {Array(<OpenLayers.Rule>)}
  297. */
  298. addRules: function(rules) {
  299. this.rules = this.rules.concat(rules);
  300. this.propertyStyles = this.findPropertyStyles();
  301. },
  302. /**
  303. * APIMethod: setDefaultStyle
  304. * Sets the default style for this style object.
  305. *
  306. * Parameters:
  307. * style - {Object} Hash of style properties
  308. */
  309. setDefaultStyle: function(style) {
  310. this.defaultStyle = style;
  311. this.propertyStyles = this.findPropertyStyles();
  312. },
  313. /**
  314. * Method: getSymbolizerPrefix
  315. * Returns the correct symbolizer prefix according to the
  316. * geometry type of the passed geometry
  317. *
  318. * Parameters:
  319. * geometry {<OpenLayers.Geometry>}
  320. *
  321. * Returns:
  322. * {String} key of the according symbolizer
  323. */
  324. getSymbolizerPrefix: function(geometry) {
  325. var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES;
  326. for (var i=0, len=prefixes.length; i<len; i++) {
  327. if (geometry.CLASS_NAME.indexOf(prefixes[i]) != -1) {
  328. return prefixes[i];
  329. }
  330. }
  331. },
  332. CLASS_NAME: "OpenLayers.Style"
  333. });
  334. /**
  335. * Function: createLiteral
  336. * converts a style value holding a combination of PropertyName and Literal
  337. * into a Literal, taking the property values from the passed features.
  338. *
  339. * Parameters:
  340. * value - {String} value to parse. If this string contains a construct like
  341. * "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
  342. * will be replaced by the value of the "bar" attribute of the passed
  343. * feature.
  344. * context - {Object} context to take attribute values from
  345. * feature - {<OpenLayers.Feature.Vector>} optional feature to pass to
  346. * <OpenLayers.String.format> for evaluating functions in the
  347. * context.
  348. * property - {String} optional, name of the property for which the literal is
  349. * being created for evaluating functions in the context.
  350. *
  351. * Returns:
  352. * {String} the parsed value. In the example of the value parameter above, the
  353. * result would be "foo valueOfBar", assuming that the passed feature has an
  354. * attribute named "bar" with the value "valueOfBar".
  355. */
  356. OpenLayers.Style.createLiteral = function(value, context, feature, property) {
  357. if (typeof value == "string" && value.indexOf("${") != -1) {
  358. value = OpenLayers.String.format(value, context, [feature, property]);
  359. value = (isNaN(value) || !value) ? value : parseFloat(value);
  360. }
  361. return value;
  362. };
  363. /**
  364. * Constant: OpenLayers.Style.SYMBOLIZER_PREFIXES
  365. * {Array} prefixes of the sld symbolizers. These are the
  366. * same as the main geometry types
  367. */
  368. OpenLayers.Style.SYMBOLIZER_PREFIXES = ['Point', 'Line', 'Polygon', 'Text'];