UNPKG

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