leaflet-hash.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. (function(window) {
  2. var HAS_HASHCHANGE = (function() {
  3. var doc_mode = window.documentMode;
  4. return ('onhashchange' in window) &&
  5. (doc_mode === undefined || doc_mode > 7);
  6. })();
  7. L.Hash = function(map) {
  8. this.onHashChange = L.Util.bind(this.onHashChange, this);
  9. if (map) {
  10. this.init(map);
  11. }
  12. };
  13. L.Hash.parseHash = function(hash) {
  14. if(hash.indexOf('#') === 0) {
  15. hash = hash.substr(1);
  16. }
  17. var args = hash.split("/");
  18. if (args.length == 3) {
  19. var zoom = parseInt(args[0], 10),
  20. lat = parseFloat(args[1]),
  21. lon = parseFloat(args[2]);
  22. if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
  23. return false;
  24. } else {
  25. return {
  26. center: new L.LatLng(lat, lon),
  27. zoom: zoom
  28. };
  29. }
  30. } else {
  31. return false;
  32. }
  33. };
  34. L.Hash.formatHash = function(map) {
  35. var center = map.getCenter(),
  36. zoom = map.getZoom(),
  37. precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
  38. return "#" + [zoom,
  39. center.lat.toFixed(precision),
  40. center.lng.toFixed(precision)
  41. ].join("/");
  42. },
  43. L.Hash.prototype = {
  44. map: null,
  45. lastHash: null,
  46. parseHash: L.Hash.parseHash,
  47. formatHash: L.Hash.formatHash,
  48. init: function(map) {
  49. this.map = map;
  50. // reset the hash
  51. this.lastHash = null;
  52. this.onHashChange();
  53. if (!this.isListening) {
  54. this.startListening();
  55. }
  56. },
  57. removeFrom: function(map) {
  58. if (this.changeTimeout) {
  59. clearTimeout(this.changeTimeout);
  60. }
  61. if (this.isListening) {
  62. this.stopListening();
  63. }
  64. this.map = null;
  65. },
  66. onMapMove: function() {
  67. // bail if we're moving the map (updating from a hash),
  68. // or if the map is not yet loaded
  69. if (this.movingMap || !this.map._loaded) {
  70. return false;
  71. }
  72. var hash = this.formatHash(this.map);
  73. if (this.lastHash != hash) {
  74. location.replace(hash);
  75. this.lastHash = hash;
  76. }
  77. },
  78. movingMap: false,
  79. update: function() {
  80. var hash = location.hash;
  81. if (hash === this.lastHash) {
  82. return;
  83. }
  84. var parsed = this.parseHash(hash);
  85. if (parsed) {
  86. this.movingMap = true;
  87. this.map.setView(parsed.center, parsed.zoom);
  88. this.movingMap = false;
  89. } else {
  90. this.onMapMove(this.map);
  91. }
  92. },
  93. // defer hash change updates every 100ms
  94. changeDefer: 100,
  95. changeTimeout: null,
  96. onHashChange: function() {
  97. // throttle calls to update() so that they only happen every
  98. // `changeDefer` ms
  99. if (!this.changeTimeout) {
  100. var that = this;
  101. this.changeTimeout = setTimeout(function() {
  102. that.update();
  103. that.changeTimeout = null;
  104. }, this.changeDefer);
  105. }
  106. },
  107. isListening: false,
  108. hashChangeInterval: null,
  109. startListening: function() {
  110. this.map.on("moveend", this.onMapMove, this);
  111. if (HAS_HASHCHANGE) {
  112. L.DomEvent.addListener(window, "hashchange", this.onHashChange);
  113. } else {
  114. clearInterval(this.hashChangeInterval);
  115. this.hashChangeInterval = setInterval(this.onHashChange, 50);
  116. }
  117. this.isListening = true;
  118. },
  119. stopListening: function() {
  120. this.map.off("moveend", this.onMapMove, this);
  121. if (HAS_HASHCHANGE) {
  122. L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
  123. } else {
  124. clearInterval(this.hashChangeInterval);
  125. }
  126. this.isListening = false;
  127. }
  128. };
  129. L.hash = function(map) {
  130. return new L.Hash(map);
  131. };
  132. L.Map.prototype.addHash = function() {
  133. this._hash = L.hash(this);
  134. };
  135. L.Map.prototype.removeHash = function() {
  136. this._hash.removeFrom();
  137. };
  138. })(window);