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 |
|
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 |
|
82 |
|
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 |
|
114 | changeDefer: 100,
|
115 | changeTimeout: null,
|
116 | onHashChange: function() {
|
117 |
|
118 |
|
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);
|