Vector.js 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. /* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
  2. * full list of contributors). Published under the 2-clause BSD license.
  3. * See license.txt in the OpenLayers distribution or repository for the
  4. * full text of the license. */
  5. /**
  6. * @requires OpenLayers/Layer.js
  7. * @requires OpenLayers/Renderer.js
  8. * @requires OpenLayers/StyleMap.js
  9. * @requires OpenLayers/Feature/Vector.js
  10. * @requires OpenLayers/Console.js
  11. * @requires OpenLayers/Lang.js
  12. */
  13. /**
  14. * Class: OpenLayers.Layer.Vector
  15. * Instances of OpenLayers.Layer.Vector are used to render vector data from
  16. * a variety of sources. Create a new vector layer with the
  17. * <OpenLayers.Layer.Vector> constructor.
  18. *
  19. * Inherits from:
  20. * - <OpenLayers.Layer>
  21. */
  22. OpenLayers.Layer.Vector = OpenLayers.Class(OpenLayers.Layer, {
  23. /**
  24. * APIProperty: events
  25. * {<OpenLayers.Events>}
  26. *
  27. * Register a listener for a particular event with the following syntax:
  28. * (code)
  29. * layer.events.register(type, obj, listener);
  30. * (end)
  31. *
  32. * Listeners will be called with a reference to an event object. The
  33. * properties of this event depends on exactly what happened.
  34. *
  35. * All event objects have at least the following properties:
  36. * object - {Object} A reference to layer.events.object.
  37. * element - {DOMElement} A reference to layer.events.element.
  38. *
  39. * Supported map event types (in addition to those from <OpenLayers.Layer.events>):
  40. * beforefeatureadded - Triggered before a feature is added. Listeners
  41. * will receive an object with a *feature* property referencing the
  42. * feature to be added. To stop the feature from being added, a
  43. * listener should return false.
  44. * beforefeaturesadded - Triggered before an array of features is added.
  45. * Listeners will receive an object with a *features* property
  46. * referencing the feature to be added. To stop the features from
  47. * being added, a listener should return false.
  48. * featureadded - Triggered after a feature is added. The event
  49. * object passed to listeners will have a *feature* property with a
  50. * reference to the added feature.
  51. * featuresadded - Triggered after features are added. The event
  52. * object passed to listeners will have a *features* property with a
  53. * reference to an array of added features.
  54. * beforefeatureremoved - Triggered before a feature is removed. Listeners
  55. * will receive an object with a *feature* property referencing the
  56. * feature to be removed.
  57. * beforefeaturesremoved - Triggered before multiple features are removed.
  58. * Listeners will receive an object with a *features* property
  59. * referencing the features to be removed.
  60. * featureremoved - Triggerd after a feature is removed. The event
  61. * object passed to listeners will have a *feature* property with a
  62. * reference to the removed feature.
  63. * featuresremoved - Triggered after features are removed. The event
  64. * object passed to listeners will have a *features* property with a
  65. * reference to an array of removed features.
  66. * beforefeatureselected - Triggered before a feature is selected. Listeners
  67. * will receive an object with a *feature* property referencing the
  68. * feature to be selected. To stop the feature from being selectd, a
  69. * listener should return false.
  70. * featureselected - Triggered after a feature is selected. Listeners
  71. * will receive an object with a *feature* property referencing the
  72. * selected feature.
  73. * featureunselected - Triggered after a feature is unselected.
  74. * Listeners will receive an object with a *feature* property
  75. * referencing the unselected feature.
  76. * beforefeaturemodified - Triggered when a feature is selected to
  77. * be modified. Listeners will receive an object with a *feature*
  78. * property referencing the selected feature.
  79. * featuremodified - Triggered when a feature has been modified.
  80. * Listeners will receive an object with a *feature* property referencing
  81. * the modified feature.
  82. * afterfeaturemodified - Triggered when a feature is finished being modified.
  83. * Listeners will receive an object with a *feature* property referencing
  84. * the modified feature.
  85. * vertexmodified - Triggered when a vertex within any feature geometry
  86. * has been modified. Listeners will receive an object with a
  87. * *feature* property referencing the modified feature, a *vertex*
  88. * property referencing the vertex modified (always a point geometry),
  89. * and a *pixel* property referencing the pixel location of the
  90. * modification.
  91. * vertexremoved - Triggered when a vertex within any feature geometry
  92. * has been deleted. Listeners will receive an object with a
  93. * *feature* property referencing the modified feature, a *vertex*
  94. * property referencing the vertex modified (always a point geometry),
  95. * and a *pixel* property referencing the pixel location of the
  96. * removal.
  97. * sketchstarted - Triggered when a feature sketch bound for this layer
  98. * is started. Listeners will receive an object with a *feature*
  99. * property referencing the new sketch feature and a *vertex* property
  100. * referencing the creation point.
  101. * sketchmodified - Triggered when a feature sketch bound for this layer
  102. * is modified. Listeners will receive an object with a *vertex*
  103. * property referencing the modified vertex and a *feature* property
  104. * referencing the sketch feature.
  105. * sketchcomplete - Triggered when a feature sketch bound for this layer
  106. * is complete. Listeners will receive an object with a *feature*
  107. * property referencing the sketch feature. By returning false, a
  108. * listener can stop the sketch feature from being added to the layer.
  109. * refresh - Triggered when something wants a strategy to ask the protocol
  110. * for a new set of features.
  111. */
  112. /**
  113. * APIProperty: isBaseLayer
  114. * {Boolean} The layer is a base layer. Default is false. Set this property
  115. * in the layer options.
  116. */
  117. isBaseLayer: false,
  118. /**
  119. * APIProperty: isFixed
  120. * {Boolean} Whether the layer remains in one place while dragging the
  121. * map. Note that setting this to true will move the layer to the bottom
  122. * of the layer stack.
  123. */
  124. isFixed: false,
  125. /**
  126. * APIProperty: features
  127. * {Array(<OpenLayers.Feature.Vector>)}
  128. */
  129. features: null,
  130. /**
  131. * Property: filter
  132. * {<OpenLayers.Filter>} The filter set in this layer,
  133. * a strategy launching read requests can combined
  134. * this filter with its own filter.
  135. */
  136. filter: null,
  137. /**
  138. * Property: selectedFeatures
  139. * {Array(<OpenLayers.Feature.Vector>)}
  140. */
  141. selectedFeatures: null,
  142. /**
  143. * Property: unrenderedFeatures
  144. * {Object} hash of features, keyed by feature.id, that the renderer
  145. * failed to draw
  146. */
  147. unrenderedFeatures: null,
  148. /**
  149. * APIProperty: reportError
  150. * {Boolean} report friendly error message when loading of renderer
  151. * fails.
  152. */
  153. reportError: true,
  154. /**
  155. * APIProperty: style
  156. * {Object} Default style for the layer
  157. */
  158. style: null,
  159. /**
  160. * Property: styleMap
  161. * {<OpenLayers.StyleMap>}
  162. */
  163. styleMap: null,
  164. /**
  165. * Property: strategies
  166. * {Array(<OpenLayers.Strategy>})} Optional list of strategies for the layer.
  167. */
  168. strategies: null,
  169. /**
  170. * Property: protocol
  171. * {<OpenLayers.Protocol>} Optional protocol for the layer.
  172. */
  173. protocol: null,
  174. /**
  175. * Property: renderers
  176. * {Array(String)} List of supported Renderer classes. Add to this list to
  177. * add support for additional renderers. This list is ordered:
  178. * the first renderer which returns true for the 'supported()'
  179. * method will be used, if not defined in the 'renderer' option.
  180. */
  181. renderers: ['SVG', 'VML', 'Canvas'],
  182. /**
  183. * Property: renderer
  184. * {<OpenLayers.Renderer>}
  185. */
  186. renderer: null,
  187. /**
  188. * APIProperty: rendererOptions
  189. * {Object} Options for the renderer. See {<OpenLayers.Renderer>} for
  190. * supported options.
  191. */
  192. rendererOptions: null,
  193. /**
  194. * APIProperty: geometryType
  195. * {String} geometryType allows you to limit the types of geometries this
  196. * layer supports. This should be set to something like
  197. * "OpenLayers.Geometry.Point" to limit types.
  198. */
  199. geometryType: null,
  200. /**
  201. * Property: drawn
  202. * {Boolean} Whether the Vector Layer features have been drawn yet.
  203. */
  204. drawn: false,
  205. /**
  206. * APIProperty: ratio
  207. * {Float} This specifies the ratio of the size of the visiblity of the Vector Layer features to the size of the map.
  208. */
  209. ratio: 1,
  210. /**
  211. * Constructor: OpenLayers.Layer.Vector
  212. * Create a new vector layer
  213. *
  214. * Parameters:
  215. * name - {String} A name for the layer
  216. * options - {Object} Optional object with non-default properties to set on
  217. * the layer.
  218. *
  219. * Returns:
  220. * {<OpenLayers.Layer.Vector>} A new vector layer
  221. */
  222. initialize: function(name, options) {
  223. OpenLayers.Layer.prototype.initialize.apply(this, arguments);
  224. // allow user-set renderer, otherwise assign one
  225. if (!this.renderer || !this.renderer.supported()) {
  226. this.assignRenderer();
  227. }
  228. // if no valid renderer found, display error
  229. if (!this.renderer || !this.renderer.supported()) {
  230. this.renderer = null;
  231. this.displayError();
  232. }
  233. if (!this.styleMap) {
  234. this.styleMap = new OpenLayers.StyleMap();
  235. }
  236. this.features = [];
  237. this.selectedFeatures = [];
  238. this.unrenderedFeatures = {};
  239. // Allow for custom layer behavior
  240. if(this.strategies){
  241. for(var i=0, len=this.strategies.length; i<len; i++) {
  242. this.strategies[i].setLayer(this);
  243. }
  244. }
  245. },
  246. /**
  247. * APIMethod: destroy
  248. * Destroy this layer
  249. */
  250. destroy: function() {
  251. if (this.strategies) {
  252. var strategy, i, len;
  253. for(i=0, len=this.strategies.length; i<len; i++) {
  254. strategy = this.strategies[i];
  255. if(strategy.autoDestroy) {
  256. strategy.destroy();
  257. }
  258. }
  259. this.strategies = null;
  260. }
  261. if (this.protocol) {
  262. if(this.protocol.autoDestroy) {
  263. this.protocol.destroy();
  264. }
  265. this.protocol = null;
  266. }
  267. this.destroyFeatures();
  268. this.features = null;
  269. this.selectedFeatures = null;
  270. this.unrenderedFeatures = null;
  271. if (this.renderer) {
  272. this.renderer.destroy();
  273. }
  274. this.renderer = null;
  275. this.geometryType = null;
  276. this.drawn = null;
  277. OpenLayers.Layer.prototype.destroy.apply(this, arguments);
  278. },
  279. /**
  280. * Method: clone
  281. * Create a clone of this layer.
  282. *
  283. * Note: Features of the layer are also cloned.
  284. *
  285. * Returns:
  286. * {<OpenLayers.Layer.Vector>} An exact clone of this layer
  287. */
  288. clone: function (obj) {
  289. if (obj == null) {
  290. obj = new OpenLayers.Layer.Vector(this.name, this.getOptions());
  291. }
  292. //get all additions from superclasses
  293. obj = OpenLayers.Layer.prototype.clone.apply(this, [obj]);
  294. // copy/set any non-init, non-simple values here
  295. var features = this.features;
  296. var len = features.length;
  297. var clonedFeatures = new Array(len);
  298. for(var i=0; i<len; ++i) {
  299. clonedFeatures[i] = features[i].clone();
  300. }
  301. obj.features = clonedFeatures;
  302. return obj;
  303. },
  304. /**
  305. * Method: refresh
  306. * Ask the layer to request features again and redraw them. Triggers
  307. * the refresh event if the layer is in range and visible.
  308. *
  309. * Parameters:
  310. * obj - {Object} Optional object with properties for any listener of
  311. * the refresh event.
  312. */
  313. refresh: function(obj) {
  314. if(this.calculateInRange() && this.visibility) {
  315. this.events.triggerEvent("refresh", obj);
  316. }
  317. },
  318. /**
  319. * Method: assignRenderer
  320. * Iterates through the available renderer implementations and selects
  321. * and assigns the first one whose "supported()" function returns true.
  322. */
  323. assignRenderer: function() {
  324. for (var i=0, len=this.renderers.length; i<len; i++) {
  325. var rendererClass = this.renderers[i];
  326. var renderer = (typeof rendererClass == "function") ?
  327. rendererClass :
  328. OpenLayers.Renderer[rendererClass];
  329. if (renderer && renderer.prototype.supported()) {
  330. this.renderer = new renderer(this.div, this.rendererOptions);
  331. break;
  332. }
  333. }
  334. },
  335. /**
  336. * Method: displayError
  337. * Let the user know their browser isn't supported.
  338. */
  339. displayError: function() {
  340. if (this.reportError) {
  341. OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",
  342. {renderers: this. renderers.join('\n')}));
  343. }
  344. },
  345. /**
  346. * Method: setMap
  347. * The layer has been added to the map.
  348. *
  349. * If there is no renderer set, the layer can't be used. Remove it.
  350. * Otherwise, give the renderer a reference to the map and set its size.
  351. *
  352. * Parameters:
  353. * map - {<OpenLayers.Map>}
  354. */
  355. setMap: function(map) {
  356. OpenLayers.Layer.prototype.setMap.apply(this, arguments);
  357. if (!this.renderer) {
  358. this.map.removeLayer(this);
  359. } else {
  360. this.renderer.map = this.map;
  361. var newSize = this.map.getSize();
  362. newSize.w = newSize.w * this.ratio;
  363. newSize.h = newSize.h * this.ratio;
  364. this.renderer.setSize(newSize);
  365. }
  366. },
  367. /**
  368. * Method: afterAdd
  369. * Called at the end of the map.addLayer sequence. At this point, the map
  370. * will have a base layer. Any autoActivate strategies will be
  371. * activated here.
  372. */
  373. afterAdd: function() {
  374. if(this.strategies) {
  375. var strategy, i, len;
  376. for(i=0, len=this.strategies.length; i<len; i++) {
  377. strategy = this.strategies[i];
  378. if(strategy.autoActivate) {
  379. strategy.activate();
  380. }
  381. }
  382. }
  383. },
  384. /**
  385. * Method: removeMap
  386. * The layer has been removed from the map.
  387. *
  388. * Parameters:
  389. * map - {<OpenLayers.Map>}
  390. */
  391. removeMap: function(map) {
  392. this.drawn = false;
  393. if(this.strategies) {
  394. var strategy, i, len;
  395. for(i=0, len=this.strategies.length; i<len; i++) {
  396. strategy = this.strategies[i];
  397. if(strategy.autoActivate) {
  398. strategy.deactivate();
  399. }
  400. }
  401. }
  402. },
  403. /**
  404. * Method: onMapResize
  405. * Notify the renderer of the change in size.
  406. *
  407. */
  408. onMapResize: function() {
  409. OpenLayers.Layer.prototype.onMapResize.apply(this, arguments);
  410. var newSize = this.map.getSize();
  411. newSize.w = newSize.w * this.ratio;
  412. newSize.h = newSize.h * this.ratio;
  413. this.renderer.setSize(newSize);
  414. },
  415. /**
  416. * Method: moveTo
  417. * Reset the vector layer's div so that it once again is lined up with
  418. * the map. Notify the renderer of the change of extent, and in the
  419. * case of a change of zoom level (resolution), have the
  420. * renderer redraw features.
  421. *
  422. * If the layer has not yet been drawn, cycle through the layer's
  423. * features and draw each one.
  424. *
  425. * Parameters:
  426. * bounds - {<OpenLayers.Bounds>}
  427. * zoomChanged - {Boolean}
  428. * dragging - {Boolean}
  429. */
  430. moveTo: function(bounds, zoomChanged, dragging) {
  431. OpenLayers.Layer.prototype.moveTo.apply(this, arguments);
  432. var coordSysUnchanged = true;
  433. if (!dragging) {
  434. this.renderer.root.style.visibility = 'hidden';
  435. var viewSize = this.map.getSize(),
  436. viewWidth = viewSize.w,
  437. viewHeight = viewSize.h,
  438. offsetLeft = (viewWidth / 2 * this.ratio) - viewWidth / 2,
  439. offsetTop = (viewHeight / 2 * this.ratio) - viewHeight / 2;
  440. offsetLeft += this.map.layerContainerOriginPx.x;
  441. offsetLeft = -Math.round(offsetLeft);
  442. offsetTop += this.map.layerContainerOriginPx.y;
  443. offsetTop = -Math.round(offsetTop);
  444. this.div.style.left = offsetLeft + 'px';
  445. this.div.style.top = offsetTop + 'px';
  446. var extent = this.map.getExtent().scale(this.ratio);
  447. coordSysUnchanged = this.renderer.setExtent(extent, zoomChanged);
  448. this.renderer.root.style.visibility = 'visible';
  449. // Force a reflow on gecko based browsers to prevent jump/flicker.
  450. // This seems to happen on only certain configurations; it was originally
  451. // noticed in FF 2.0 and Linux.
  452. if (OpenLayers.IS_GECKO === true) {
  453. this.div.scrollLeft = this.div.scrollLeft;
  454. }
  455. if (!zoomChanged && coordSysUnchanged) {
  456. for (var i in this.unrenderedFeatures) {
  457. var feature = this.unrenderedFeatures[i];
  458. this.drawFeature(feature);
  459. }
  460. }
  461. }
  462. if (!this.drawn || zoomChanged || !coordSysUnchanged) {
  463. this.drawn = true;
  464. var feature;
  465. for(var i=0, len=this.features.length; i<len; i++) {
  466. this.renderer.locked = (i !== (len - 1));
  467. feature = this.features[i];
  468. this.drawFeature(feature);
  469. }
  470. }
  471. },
  472. /**
  473. * APIMethod: display
  474. * Hide or show the Layer
  475. *
  476. * Parameters:
  477. * display - {Boolean}
  478. */
  479. display: function(display) {
  480. OpenLayers.Layer.prototype.display.apply(this, arguments);
  481. // we need to set the display style of the root in case it is attached
  482. // to a foreign layer
  483. var currentDisplay = this.div.style.display;
  484. if(currentDisplay != this.renderer.root.style.display) {
  485. this.renderer.root.style.display = currentDisplay;
  486. }
  487. },
  488. /**
  489. * APIMethod: addFeatures
  490. * Add Features to the layer.
  491. *
  492. * Parameters:
  493. * features - {Array(<OpenLayers.Feature.Vector>)}
  494. * options - {Object}
  495. */
  496. addFeatures: function(features, options) {
  497. if (!(OpenLayers.Util.isArray(features))) {
  498. features = [features];
  499. }
  500. var notify = !options || !options.silent;
  501. if(notify) {
  502. var event = {features: features};
  503. var ret = this.events.triggerEvent("beforefeaturesadded", event);
  504. if(ret === false) {
  505. return;
  506. }
  507. features = event.features;
  508. }
  509. // Track successfully added features for featuresadded event, since
  510. // beforefeatureadded can veto single features.
  511. var featuresAdded = [];
  512. for (var i=0, len=features.length; i<len; i++) {
  513. if (i != (features.length - 1)) {
  514. this.renderer.locked = true;
  515. } else {
  516. this.renderer.locked = false;
  517. }
  518. var feature = features[i];
  519. if (this.geometryType &&
  520. !(feature.geometry instanceof this.geometryType)) {
  521. throw new TypeError('addFeatures: component should be an ' +
  522. this.geometryType.prototype.CLASS_NAME);
  523. }
  524. //give feature reference to its layer
  525. feature.layer = this;
  526. if (!feature.style && this.style) {
  527. feature.style = OpenLayers.Util.extend({}, this.style);
  528. }
  529. if (notify) {
  530. if(this.events.triggerEvent("beforefeatureadded",
  531. {feature: feature}) === false) {
  532. continue;
  533. }
  534. this.preFeatureInsert(feature);
  535. }
  536. featuresAdded.push(feature);
  537. this.features.push(feature);
  538. this.drawFeature(feature);
  539. if (notify) {
  540. this.events.triggerEvent("featureadded", {
  541. feature: feature
  542. });
  543. this.onFeatureInsert(feature);
  544. }
  545. }
  546. if(notify) {
  547. this.events.triggerEvent("featuresadded", {features: featuresAdded});
  548. }
  549. },
  550. /**
  551. * APIMethod: removeFeatures
  552. * Remove features from the layer. This erases any drawn features and
  553. * removes them from the layer's control. The beforefeatureremoved
  554. * and featureremoved events will be triggered for each feature. The
  555. * featuresremoved event will be triggered after all features have
  556. * been removed. To supress event triggering, use the silent option.
  557. *
  558. * Parameters:
  559. * features - {Array(<OpenLayers.Feature.Vector>)} List of features to be
  560. * removed.
  561. * options - {Object} Optional properties for changing behavior of the
  562. * removal.
  563. *
  564. * Valid options:
  565. * silent - {Boolean} Supress event triggering. Default is false.
  566. */
  567. removeFeatures: function(features, options) {
  568. if(!features || features.length === 0) {
  569. return;
  570. }
  571. if (features === this.features) {
  572. return this.removeAllFeatures(options);
  573. }
  574. if (!(OpenLayers.Util.isArray(features))) {
  575. features = [features];
  576. }
  577. if (features === this.selectedFeatures) {
  578. features = features.slice();
  579. }
  580. var notify = !options || !options.silent;
  581. if (notify) {
  582. this.events.triggerEvent(
  583. "beforefeaturesremoved", {features: features}
  584. );
  585. }
  586. for (var i = features.length - 1; i >= 0; i--) {
  587. // We remain locked so long as we're not at 0
  588. // and the 'next' feature has a geometry. We do the geometry check
  589. // because if all the features after the current one are 'null', we
  590. // won't call eraseGeometry, so we break the 'renderer functions
  591. // will always be called with locked=false *last*' rule. The end result
  592. // is a possible gratiutious unlocking to save a loop through the rest
  593. // of the list checking the remaining features every time. So long as
  594. // null geoms are rare, this is probably okay.
  595. if (i != 0 && features[i-1].geometry) {
  596. this.renderer.locked = true;
  597. } else {
  598. this.renderer.locked = false;
  599. }
  600. var feature = features[i];
  601. delete this.unrenderedFeatures[feature.id];
  602. if (notify) {
  603. this.events.triggerEvent("beforefeatureremoved", {
  604. feature: feature
  605. });
  606. }
  607. this.features = OpenLayers.Util.removeItem(this.features, feature);
  608. // feature has no layer at this point
  609. feature.layer = null;
  610. if (feature.geometry) {
  611. this.renderer.eraseFeatures(feature);
  612. }
  613. //in the case that this feature is one of the selected features,
  614. // remove it from that array as well.
  615. if (OpenLayers.Util.indexOf(this.selectedFeatures, feature) != -1){
  616. OpenLayers.Util.removeItem(this.selectedFeatures, feature);
  617. }
  618. if (notify) {
  619. this.events.triggerEvent("featureremoved", {
  620. feature: feature
  621. });
  622. }
  623. }
  624. if (notify) {
  625. this.events.triggerEvent("featuresremoved", {features: features});
  626. }
  627. },
  628. /**
  629. * APIMethod: removeAllFeatures
  630. * Remove all features from the layer.
  631. *
  632. * Parameters:
  633. * options - {Object} Optional properties for changing behavior of the
  634. * removal.
  635. *
  636. * Valid options:
  637. * silent - {Boolean} Supress event triggering. Default is false.
  638. */
  639. removeAllFeatures: function(options) {
  640. var notify = !options || !options.silent;
  641. var features = this.features;
  642. if (notify) {
  643. this.events.triggerEvent(
  644. "beforefeaturesremoved", {features: features}
  645. );
  646. }
  647. var feature;
  648. for (var i = features.length-1; i >= 0; i--) {
  649. feature = features[i];
  650. if (notify) {
  651. this.events.triggerEvent("beforefeatureremoved", {
  652. feature: feature
  653. });
  654. }
  655. feature.layer = null;
  656. if (notify) {
  657. this.events.triggerEvent("featureremoved", {
  658. feature: feature
  659. });
  660. }
  661. }
  662. this.renderer.clear();
  663. this.features = [];
  664. this.unrenderedFeatures = {};
  665. this.selectedFeatures = [];
  666. if (notify) {
  667. this.events.triggerEvent("featuresremoved", {features: features});
  668. }
  669. },
  670. /**
  671. * APIMethod: destroyFeatures
  672. * Erase and destroy features on the layer.
  673. *
  674. * Parameters:
  675. * features - {Array(<OpenLayers.Feature.Vector>)} An optional array of
  676. * features to destroy. If not supplied, all features on the layer
  677. * will be destroyed.
  678. * options - {Object}
  679. */
  680. destroyFeatures: function(features, options) {
  681. var all = (features == undefined); // evaluates to true if
  682. // features is null
  683. if(all) {
  684. features = this.features;
  685. }
  686. if(features) {
  687. this.removeFeatures(features, options);
  688. for(var i=features.length-1; i>=0; i--) {
  689. features[i].destroy();
  690. }
  691. }
  692. },
  693. /**
  694. * APIMethod: drawFeature
  695. * Draw (or redraw) a feature on the layer. If the optional style argument
  696. * is included, this style will be used. If no style is included, the
  697. * feature's style will be used. If the feature doesn't have a style,
  698. * the layer's style will be used.
  699. *
  700. * This function is not designed to be used when adding features to
  701. * the layer (use addFeatures instead). It is meant to be used when
  702. * the style of a feature has changed, or in some other way needs to
  703. * visually updated *after* it has already been added to a layer. You
  704. * must add the feature to the layer for most layer-related events to
  705. * happen.
  706. *
  707. * Parameters:
  708. * feature - {<OpenLayers.Feature.Vector>}
  709. * style - {String | Object} Named render intent or full symbolizer object.
  710. */
  711. drawFeature: function(feature, style) {
  712. // don't try to draw the feature with the renderer if the layer is not
  713. // drawn itself
  714. if (!this.drawn) {
  715. return;
  716. }
  717. if (typeof style != "object") {
  718. if(!style && feature.state === OpenLayers.State.DELETE) {
  719. style = "delete";
  720. }
  721. var renderIntent = style || feature.renderIntent;
  722. style = feature.style || this.style;
  723. if (!style) {
  724. style = this.styleMap.createSymbolizer(feature, renderIntent);
  725. }
  726. }
  727. var drawn = this.renderer.drawFeature(feature, style);
  728. //TODO remove the check for null when we get rid of Renderer.SVG
  729. if (drawn === false || drawn === null) {
  730. this.unrenderedFeatures[feature.id] = feature;
  731. } else {
  732. delete this.unrenderedFeatures[feature.id];
  733. }
  734. },
  735. /**
  736. * Method: eraseFeatures
  737. * Erase features from the layer.
  738. *
  739. * Parameters:
  740. * features - {Array(<OpenLayers.Feature.Vector>)}
  741. */
  742. eraseFeatures: function(features) {
  743. this.renderer.eraseFeatures(features);
  744. },
  745. /**
  746. * Method: getFeatureFromEvent
  747. * Given an event, return a feature if the event occurred over one.
  748. * Otherwise, return null.
  749. *
  750. * Parameters:
  751. * evt - {Event}
  752. *
  753. * Returns:
  754. * {<OpenLayers.Feature.Vector>} A feature if one was under the event.
  755. */
  756. getFeatureFromEvent: function(evt) {
  757. if (!this.renderer) {
  758. throw new Error('getFeatureFromEvent called on layer with no ' +
  759. 'renderer. This usually means you destroyed a ' +
  760. 'layer, but not some handler which is associated ' +
  761. 'with it.');
  762. }
  763. var feature = null;
  764. var featureId = this.renderer.getFeatureIdFromEvent(evt);
  765. if (featureId) {
  766. if (typeof featureId === "string") {
  767. feature = this.getFeatureById(featureId);
  768. } else {
  769. feature = featureId;
  770. }
  771. }
  772. return feature;
  773. },
  774. /**
  775. * APIMethod: getFeatureBy
  776. * Given a property value, return the feature if it exists in the features array
  777. *
  778. * Parameters:
  779. * property - {String}
  780. * value - {String}
  781. *
  782. * Returns:
  783. * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
  784. * property value or null if there is no such feature.
  785. */
  786. getFeatureBy: function(property, value) {
  787. //TBD - would it be more efficient to use a hash for this.features?
  788. var feature = null;
  789. for(var i=0, len=this.features.length; i<len; ++i) {
  790. if(this.features[i][property] == value) {
  791. feature = this.features[i];
  792. break;
  793. }
  794. }
  795. return feature;
  796. },
  797. /**
  798. * APIMethod: getFeatureById
  799. * Given a feature id, return the feature if it exists in the features array
  800. *
  801. * Parameters:
  802. * featureId - {String}
  803. *
  804. * Returns:
  805. * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
  806. * featureId or null if there is no such feature.
  807. */
  808. getFeatureById: function(featureId) {
  809. return this.getFeatureBy('id', featureId);
  810. },
  811. /**
  812. * APIMethod: getFeatureByFid
  813. * Given a feature fid, return the feature if it exists in the features array
  814. *
  815. * Parameters:
  816. * featureFid - {String}
  817. *
  818. * Returns:
  819. * {<OpenLayers.Feature.Vector>} A feature corresponding to the given
  820. * featureFid or null if there is no such feature.
  821. */
  822. getFeatureByFid: function(featureFid) {
  823. return this.getFeatureBy('fid', featureFid);
  824. },
  825. /**
  826. * APIMethod: getFeaturesByAttribute
  827. * Returns an array of features that have the given attribute key set to the
  828. * given value. Comparison of attribute values takes care of datatypes, e.g.
  829. * the string '1234' is not equal to the number 1234.
  830. *
  831. * Parameters:
  832. * attrName - {String}
  833. * attrValue - {Mixed}
  834. *
  835. * Returns:
  836. * Array({<OpenLayers.Feature.Vector>}) An array of features that have the
  837. * passed named attribute set to the given value.
  838. */
  839. getFeaturesByAttribute: function(attrName, attrValue) {
  840. var i,
  841. feature,
  842. len = this.features.length,
  843. foundFeatures = [];
  844. for(i = 0; i < len; i++) {
  845. feature = this.features[i];
  846. if(feature && feature.attributes) {
  847. if (feature.attributes[attrName] === attrValue) {
  848. foundFeatures.push(feature);
  849. }
  850. }
  851. }
  852. return foundFeatures;
  853. },
  854. /**
  855. * Unselect the selected features
  856. * i.e. clears the featureSelection array
  857. * change the style back
  858. clearSelection: function() {
  859. var vectorLayer = this.map.vectorLayer;
  860. for (var i = 0; i < this.map.featureSelection.length; i++) {
  861. var featureSelection = this.map.featureSelection[i];
  862. vectorLayer.drawFeature(featureSelection, vectorLayer.style);
  863. }
  864. this.map.featureSelection = [];
  865. },
  866. */
  867. /**
  868. * APIMethod: onFeatureInsert
  869. * method called after a feature is inserted.
  870. * Does nothing by default. Override this if you
  871. * need to do something on feature updates.
  872. *
  873. * Parameters:
  874. * feature - {<OpenLayers.Feature.Vector>}
  875. */
  876. onFeatureInsert: function(feature) {
  877. },
  878. /**
  879. * APIMethod: preFeatureInsert
  880. * method called before a feature is inserted.
  881. * Does nothing by default. Override this if you
  882. * need to do something when features are first added to the
  883. * layer, but before they are drawn, such as adjust the style.
  884. *
  885. * Parameters:
  886. * feature - {<OpenLayers.Feature.Vector>}
  887. */
  888. preFeatureInsert: function(feature) {
  889. },
  890. /**
  891. * APIMethod: getDataExtent
  892. * Calculates the max extent which includes all of the features.
  893. *
  894. * Returns:
  895. * {<OpenLayers.Bounds>} or null if the layer has no features with
  896. * geometries.
  897. */
  898. getDataExtent: function () {
  899. var maxExtent = null;
  900. var features = this.features;
  901. if(features && (features.length > 0)) {
  902. var geometry = null;
  903. for(var i=0, len=features.length; i<len; i++) {
  904. geometry = features[i].geometry;
  905. if (geometry) {
  906. if (maxExtent === null) {
  907. maxExtent = new OpenLayers.Bounds();
  908. }
  909. maxExtent.extend(geometry.getBounds());
  910. }
  911. }
  912. }
  913. return maxExtent;
  914. },
  915. CLASS_NAME: "OpenLayers.Layer.Vector"
  916. });