PageRenderTime 62ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/france_geo_data/static/js/OpenLayers/lib/OpenLayers/TileManager.js

https://gitlab.com/Chedi/france_geo_queries
JavaScript | 460 lines | 232 code | 31 blank | 197 comment | 43 complexity | ed48972a8a0113d2c8e508a023f96fb7 MD5 | raw file
  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/Util.js
  7. * @requires OpenLayers/BaseTypes.js
  8. * @requires OpenLayers/BaseTypes/Element.js
  9. */
  10. /**
  11. * Class: OpenLayers.TileManager
  12. * Provides queueing of image requests and caching of image elements.
  13. *
  14. * Queueing avoids unnecessary image requests while changing zoom levels
  15. * quickly, and helps improve dragging performance on mobile devices that show
  16. * a lag in dragging when loading of new images starts. <zoomDelay> and
  17. * <moveDelay> are the configuration options to control this behavior.
  18. *
  19. * Caching avoids setting the src on image elements for images that have already
  20. * been used. Several maps can share a TileManager instance, in which case each
  21. * map gets its own tile queue, but all maps share the same tile cache.
  22. */
  23. OpenLayers.TileManager = OpenLayers.Class({
  24. /**
  25. * APIProperty: cacheSize
  26. * {Number} Number of image elements to keep referenced in this instance's
  27. * cache for fast reuse. Default is 256.
  28. */
  29. cacheSize: 256,
  30. /**
  31. * APIProperty: tilesPerFrame
  32. * {Number} Number of queued tiles to load per frame (see <frameDelay>).
  33. * Default is 2.
  34. */
  35. tilesPerFrame: 2,
  36. /**
  37. * APIProperty: frameDelay
  38. * {Number} Delay between tile loading frames (see <tilesPerFrame>) in
  39. * milliseconds. Default is 16.
  40. */
  41. frameDelay: 16,
  42. /**
  43. * APIProperty: moveDelay
  44. * {Number} Delay in milliseconds after a map's move event before loading
  45. * tiles. Default is 100.
  46. */
  47. moveDelay: 100,
  48. /**
  49. * APIProperty: zoomDelay
  50. * {Number} Delay in milliseconds after a map's zoomend event before loading
  51. * tiles. Default is 200.
  52. */
  53. zoomDelay: 200,
  54. /**
  55. * Property: maps
  56. * {Array(<OpenLayers.Map>)} The maps to manage tiles on.
  57. */
  58. maps: null,
  59. /**
  60. * Property: tileQueueId
  61. * {Object} The ids of the <drawTilesFromQueue> loop, keyed by map id.
  62. */
  63. tileQueueId: null,
  64. /**
  65. * Property: tileQueue
  66. * {Object(Array(<OpenLayers.Tile>))} Tiles queued for drawing, keyed by
  67. * map id.
  68. */
  69. tileQueue: null,
  70. /**
  71. * Property: tileCache
  72. * {Object} Cached image elements, keyed by URL.
  73. */
  74. tileCache: null,
  75. /**
  76. * Property: tileCacheIndex
  77. * {Array(String)} URLs of cached tiles. First entry is the least recently
  78. * used.
  79. */
  80. tileCacheIndex: null,
  81. /**
  82. * Constructor: OpenLayers.TileManager
  83. * Constructor for a new <OpenLayers.TileManager> instance.
  84. *
  85. * Parameters:
  86. * options - {Object} Configuration for this instance.
  87. */
  88. initialize: function(options) {
  89. OpenLayers.Util.extend(this, options);
  90. this.maps = [];
  91. this.tileQueueId = {};
  92. this.tileQueue = {};
  93. this.tileCache = {};
  94. this.tileCacheIndex = [];
  95. },
  96. /**
  97. * Method: addMap
  98. * Binds this instance to a map
  99. *
  100. * Parameters:
  101. * map - {<OpenLayers.Map>}
  102. */
  103. addMap: function(map) {
  104. if (this._destroyed || !OpenLayers.Layer.Grid) {
  105. return;
  106. }
  107. this.maps.push(map);
  108. this.tileQueue[map.id] = [];
  109. for (var i=0, ii=map.layers.length; i<ii; ++i) {
  110. this.addLayer({layer: map.layers[i]});
  111. }
  112. map.events.on({
  113. move: this.move,
  114. zoomend: this.zoomEnd,
  115. changelayer: this.changeLayer,
  116. addlayer: this.addLayer,
  117. preremovelayer: this.removeLayer,
  118. scope: this
  119. });
  120. },
  121. /**
  122. * Method: removeMap
  123. * Unbinds this instance from a map
  124. *
  125. * Parameters:
  126. * map - {<OpenLayers.Map>}
  127. */
  128. removeMap: function(map) {
  129. if (this._destroyed || !OpenLayers.Layer.Grid) {
  130. return;
  131. }
  132. window.clearTimeout(this.tileQueueId[map.id]);
  133. if (map.layers) {
  134. for (var i=0, ii=map.layers.length; i<ii; ++i) {
  135. this.removeLayer({layer: map.layers[i]});
  136. }
  137. }
  138. if (map.events) {
  139. map.events.un({
  140. move: this.move,
  141. zoomend: this.zoomEnd,
  142. changelayer: this.changeLayer,
  143. addlayer: this.addLayer,
  144. preremovelayer: this.removeLayer,
  145. scope: this
  146. });
  147. }
  148. delete this.tileQueue[map.id];
  149. delete this.tileQueueId[map.id];
  150. OpenLayers.Util.removeItem(this.maps, map);
  151. },
  152. /**
  153. * Method: move
  154. * Handles the map's move event
  155. *
  156. * Parameters:
  157. * evt - {Object} Listener argument
  158. */
  159. move: function(evt) {
  160. this.updateTimeout(evt.object, this.moveDelay, true);
  161. },
  162. /**
  163. * Method: zoomEnd
  164. * Handles the map's zoomEnd event
  165. *
  166. * Parameters:
  167. * evt - {Object} Listener argument
  168. */
  169. zoomEnd: function(evt) {
  170. this.updateTimeout(evt.object, this.zoomDelay);
  171. },
  172. /**
  173. * Method: changeLayer
  174. * Handles the map's changeLayer event
  175. *
  176. * Parameters:
  177. * evt - {Object} Listener argument
  178. */
  179. changeLayer: function(evt) {
  180. if (evt.property === 'visibility' || evt.property === 'params') {
  181. this.updateTimeout(evt.object, 0);
  182. }
  183. },
  184. /**
  185. * Method: addLayer
  186. * Handles the map's addlayer event
  187. *
  188. * Parameters:
  189. * evt - {Object} The listener argument
  190. */
  191. addLayer: function(evt) {
  192. var layer = evt.layer;
  193. if (layer instanceof OpenLayers.Layer.Grid) {
  194. layer.events.on({
  195. addtile: this.addTile,
  196. retile: this.clearTileQueue,
  197. scope: this
  198. });
  199. var i, j, tile;
  200. for (i=layer.grid.length-1; i>=0; --i) {
  201. for (j=layer.grid[i].length-1; j>=0; --j) {
  202. tile = layer.grid[i][j];
  203. this.addTile({tile: tile});
  204. if (tile.url) {
  205. this.manageTileCache({object: tile});
  206. }
  207. }
  208. }
  209. }
  210. },
  211. /**
  212. * Method: removeLayer
  213. * Handles the map's preremovelayer event
  214. *
  215. * Parameters:
  216. * evt - {Object} The listener argument
  217. */
  218. removeLayer: function(evt) {
  219. var layer = evt.layer;
  220. if (layer instanceof OpenLayers.Layer.Grid) {
  221. this.clearTileQueue({object: layer});
  222. if (layer.events) {
  223. layer.events.un({
  224. addtile: this.addTile,
  225. retile: this.clearTileQueue,
  226. scope: this
  227. });
  228. }
  229. if (layer.grid) {
  230. var i, j, tile;
  231. for (i=layer.grid.length-1; i>=0; --i) {
  232. for (j=layer.grid[i].length-1; j>=0; --j) {
  233. tile = layer.grid[i][j];
  234. this.unloadTile({object: tile});
  235. if (tile.url) {
  236. this.manageTileCache({object: tile});
  237. }
  238. }
  239. }
  240. }
  241. }
  242. },
  243. /**
  244. * Method: updateTimeout
  245. * Applies the <moveDelay> or <zoomDelay> to the <drawTilesFromQueue> loop,
  246. * and schedules more queue processing after <frameDelay> if there are still
  247. * tiles in the queue.
  248. *
  249. * Parameters:
  250. * map - {<OpenLayers.Map>} The map to update the timeout for
  251. * delay - {Number} The delay to apply
  252. * nice - {Boolean} If true, the timeout function will only be created if
  253. * the tilequeue is not empty. This is used by the move handler to
  254. * avoid impacts on dragging performance. For other events, the tile
  255. * queue may not be populated yet, so we need to set the timer
  256. * regardless of the queue size.
  257. */
  258. updateTimeout: function(map, delay, nice) {
  259. window.clearTimeout(this.tileQueueId[map.id]);
  260. var tileQueue = this.tileQueue[map.id];
  261. if (!nice || tileQueue.length) {
  262. this.tileQueueId[map.id] = window.setTimeout(
  263. OpenLayers.Function.bind(function() {
  264. this.drawTilesFromQueue(map);
  265. if (tileQueue.length) {
  266. this.updateTimeout(map, this.frameDelay);
  267. }
  268. }, this), delay
  269. );
  270. }
  271. },
  272. /**
  273. * Method: addTile
  274. * Listener for the layer's addtile event
  275. *
  276. * Parameters:
  277. * evt - {Object} The listener argument
  278. */
  279. addTile: function(evt) {
  280. evt.tile.events.on({
  281. beforedraw: this.queueTileDraw,
  282. beforeload: this.manageTileCache,
  283. loadend: this.addToCache,
  284. unload: this.unloadTile,
  285. scope: this
  286. });
  287. },
  288. /**
  289. * Method: unloadTile
  290. * Listener for the tile's unload event
  291. *
  292. * Parameters:
  293. * evt - {Object} The listener argument
  294. */
  295. unloadTile: function(evt) {
  296. var tile = evt.object;
  297. tile.events.un({
  298. beforedraw: this.queueTileDraw,
  299. beforeload: this.manageTileCache,
  300. loadend: this.addToCache,
  301. unload: this.unloadTile,
  302. scope: this
  303. });
  304. OpenLayers.Util.removeItem(this.tileQueue[tile.layer.map.id], tile);
  305. },
  306. /**
  307. * Method: queueTileDraw
  308. * Adds a tile to the queue that will draw it.
  309. *
  310. * Parameters:
  311. * evt - {Object} Listener argument of the tile's beforedraw event
  312. */
  313. queueTileDraw: function(evt) {
  314. var tile = evt.object;
  315. var queued = false;
  316. var layer = tile.layer;
  317. var url = layer.getURL(tile.bounds);
  318. var img = this.tileCache[url];
  319. if (img && img.className !== 'olTileImage') {
  320. // cached image no longer valid, e.g. because we're olTileReplacing
  321. delete this.tileCache[url];
  322. OpenLayers.Util.removeItem(this.tileCacheIndex, url);
  323. img = null;
  324. }
  325. // queue only if image with same url not cached already
  326. if (layer.url && (layer.async || !img)) {
  327. // add to queue only if not in queue already
  328. var tileQueue = this.tileQueue[layer.map.id];
  329. if (!~OpenLayers.Util.indexOf(tileQueue, tile)) {
  330. tileQueue.push(tile);
  331. }
  332. queued = true;
  333. }
  334. return !queued;
  335. },
  336. /**
  337. * Method: drawTilesFromQueue
  338. * Draws tiles from the tileQueue, and unqueues the tiles
  339. */
  340. drawTilesFromQueue: function(map) {
  341. var tileQueue = this.tileQueue[map.id];
  342. var limit = this.tilesPerFrame;
  343. var animating = map.zoomTween && map.zoomTween.playing;
  344. while (!animating && tileQueue.length && limit) {
  345. tileQueue.shift().draw(true);
  346. --limit;
  347. }
  348. },
  349. /**
  350. * Method: manageTileCache
  351. * Adds, updates, removes and fetches cache entries.
  352. *
  353. * Parameters:
  354. * evt - {Object} Listener argument of the tile's beforeload event
  355. */
  356. manageTileCache: function(evt) {
  357. var tile = evt.object;
  358. var img = this.tileCache[tile.url];
  359. // only use image from cache if it is not on a layer already
  360. if (img && (!img.parentNode ||
  361. OpenLayers.Element.hasClass(img.parentNode, 'olBackBuffer'))) {
  362. if (tile.layer.backBuffer) {
  363. if (tile.layer.backBuffer === img.parentNode) {
  364. // cached image is on the target layer's backbuffer already,
  365. // so nothing to do here
  366. return;
  367. }
  368. img.style.opacity = 0;
  369. img.style.visibility = 'hidden';
  370. }
  371. // Only backbuffer tiles have an id, so we don't want one here
  372. img.id = null;
  373. tile.setImage(img);
  374. // LRU - move tile to the end of the array to mark it as the most
  375. // recently used
  376. OpenLayers.Util.removeItem(this.tileCacheIndex, tile.url);
  377. this.tileCacheIndex.push(tile.url);
  378. }
  379. },
  380. /**
  381. * Method: addToCache
  382. *
  383. * Parameters:
  384. * evt - {Object} Listener argument for the tile's loadend event
  385. */
  386. addToCache: function(evt) {
  387. var tile = evt.object;
  388. if (!this.tileCache[tile.url]) {
  389. if (!OpenLayers.Element.hasClass(tile.imgDiv, 'olImageLoadError')) {
  390. if (this.tileCacheIndex.length >= this.cacheSize) {
  391. delete this.tileCache[this.tileCacheIndex[0]];
  392. this.tileCacheIndex.shift();
  393. }
  394. this.tileCache[tile.url] = tile.imgDiv;
  395. this.tileCacheIndex.push(tile.url);
  396. }
  397. }
  398. },
  399. /**
  400. * Method: clearTileQueue
  401. * Clears the tile queue from tiles of a specific layer
  402. *
  403. * Parameters:
  404. * evt - {Object} Listener argument of the layer's retile event
  405. */
  406. clearTileQueue: function(evt) {
  407. var layer = evt.object;
  408. var tileQueue = this.tileQueue[layer.map.id];
  409. for (var i=tileQueue.length-1; i>=0; --i) {
  410. if (tileQueue[i].layer === layer) {
  411. tileQueue.splice(i, 1);
  412. }
  413. }
  414. },
  415. /**
  416. * Method: destroy
  417. */
  418. destroy: function() {
  419. for (var i=this.maps.length-1; i>=0; --i) {
  420. this.removeMap(this.maps[i]);
  421. }
  422. this.maps = null;
  423. this.tileQueue = null;
  424. this.tileQueueId = null;
  425. this.tileCache = null;
  426. this.tileCacheIndex = null;
  427. this._destroyed = true;
  428. }
  429. });