Administrator
2022-09-14 58d006e05dcf2a20d0ec5367dd03d66a61db6849
提交 | 用户 | 时间
58d006 1 if (!(typeof window.google === 'object' && window.google.maps)) {
A 2   throw 'Google Maps API is required. Please register the following JavaScript library http://maps.google.com/maps/api/js?sensor=true.'
3 }
4
5 var extend_object = function(obj, new_obj) {
6   var name;
7
8   if (obj === new_obj) {
9     return obj;
10   }
11
12   for (name in new_obj) {
13     obj[name] = new_obj[name];
14   }
15
16   return obj;
17 };
18
19 var replace_object = function(obj, replace) {
20   var name;
21
22   if (obj === replace) {
23     return obj;
24   }
25
26   for (name in replace) {
27     if (obj[name] != undefined) {
28       obj[name] = replace[name];
29     }
30   }
31
32   return obj;
33 };
34
35 var array_map = function(array, callback) {
36   var original_callback_params = Array.prototype.slice.call(arguments, 2),
37       array_return = [],
38       array_length = array.length,
39       i;
40
41   if (Array.prototype.map && array.map === Array.prototype.map) {
42     array_return = Array.prototype.map.call(array, function(item) {
43       callback_params = original_callback_params;
44       callback_params.splice(0, 0, item);
45
46       return callback.apply(this, callback_params);
47     });
48   }
49   else {
50     for (i = 0; i < array_length; i++) {
51       callback_params = original_callback_params;
52       callback_params.splice(0, 0, array[i]);
53       array_return.push(callback.apply(this, callback_params));
54     }
55   }
56
57   return array_return;
58 };
59
60 var array_flat = function(array) {
61   var new_array = [],
62       i;
63
64   for (i = 0; i < array.length; i++) {
65     new_array = new_array.concat(array[i]);
66   }
67
68   return new_array;
69 };
70
71 var coordsToLatLngs = function(coords, useGeoJSON) {
72   var first_coord = coords[0],
73       second_coord = coords[1];
74
75   if (useGeoJSON) {
76     first_coord = coords[1];
77     second_coord = coords[0];
78   }
79
80   return new google.maps.LatLng(first_coord, second_coord);
81 };
82
83 var arrayToLatLng = function(coords, useGeoJSON) {
84   var i;
85
86   for (i = 0; i < coords.length; i++) {
87     if (coords[i].length > 0 && typeof(coords[i][0]) == "object") {
88       coords[i] = arrayToLatLng(coords[i], useGeoJSON);
89     }
90     else {
91       coords[i] = coordsToLatLngs(coords[i], useGeoJSON);
92     }
93   }
94
95   return coords;
96 };
97
98 var getElementById = function(id, context) {
99   var element,
100   id = id.replace('#', '');
101
102   if ('jQuery' in this && context) {
103     element = $("#" + id, context)[0];
104   } else {
105     element = document.getElementById(id);
106   };
107
108   return element;
109 };
110
111 var findAbsolutePosition = function(obj)  {
112   var curleft = 0,
113       curtop = 0;
114
115   if (obj.offsetParent) {
116     do {
117       curleft += obj.offsetLeft;
118       curtop += obj.offsetTop;
119     } while (obj = obj.offsetParent);
120   }
121
122   return [curleft, curtop];
123 };
124
125 var GMaps = (function(global) {
126   "use strict";
127
128   var doc = document;
129
130   var GMaps = function(options) {
131     if (!this) return new GMaps(options);
132
133     options.zoom = options.zoom || 15;
134     options.mapType = options.mapType || 'roadmap';
135
136     var self = this,
137         i,
138         events_that_hide_context_menu = ['bounds_changed', 'center_changed', 'click', 'dblclick', 'drag', 'dragend', 'dragstart', 'idle', 'maptypeid_changed', 'projection_changed', 'resize', 'tilesloaded', 'zoom_changed'],
139         events_that_doesnt_hide_context_menu = ['mousemove', 'mouseout', 'mouseover'],
140         options_to_be_deleted = ['el', 'lat', 'lng', 'mapType', 'width', 'height', 'markerClusterer', 'enableNewStyle'],
141         container_id = options.el || options.div,
142         markerClustererFunction = options.markerClusterer,
143         mapType = google.maps.MapTypeId[options.mapType.toUpperCase()],
144         map_center = new google.maps.LatLng(options.lat, options.lng),
145         zoomControl = options.zoomControl || true,
146         zoomControlOpt = options.zoomControlOpt || {
147           style: 'DEFAULT',
148           position: 'TOP_LEFT'
149         },
150         zoomControlStyle = zoomControlOpt.style || 'DEFAULT',
151         zoomControlPosition = zoomControlOpt.position || 'TOP_LEFT',
152         panControl = options.panControl || true,
153         mapTypeControl = options.mapTypeControl || true,
154         scaleControl = options.scaleControl || true,
155         streetViewControl = options.streetViewControl || true,
156         overviewMapControl = overviewMapControl || true,
157         map_options = {},
158         map_base_options = {
159           zoom: this.zoom,
160           center: map_center,
161           mapTypeId: mapType
162         },
163         map_controls_options = {
164           panControl: panControl,
165           zoomControl: zoomControl,
166           zoomControlOptions: {
167             style: google.maps.ZoomControlStyle[zoomControlStyle],
168             position: google.maps.ControlPosition[zoomControlPosition]
169           },
170           mapTypeControl: mapTypeControl,
171           scaleControl: scaleControl,
172           streetViewControl: streetViewControl,
173           overviewMapControl: overviewMapControl
174         };
175
176     if (typeof(options.el) === 'string' || typeof(options.div) === 'string') {
177       this.el = getElementById(container_id, options.context);
178     } else {
179       this.el = container_id;
180     }
181
182     if (typeof(this.el) === 'undefined' || this.el === null) {
183       throw 'No element defined.';
184     }
185
186     window.context_menu = window.context_menu || {};
187     window.context_menu[self.el.id] = {};
188
189     this.controls = [];
190     this.overlays = [];
191     this.layers = []; // array with kml/georss and fusiontables layers, can be as many
192     this.singleLayers = {}; // object with the other layers, only one per layer
193     this.markers = [];
194     this.polylines = [];
195     this.routes = [];
196     this.polygons = [];
197     this.infoWindow = null;
198     this.overlay_el = null;
199     this.zoom = options.zoom;
200     this.registered_events = {};
201
202     this.el.style.width = options.width || this.el.scrollWidth || this.el.offsetWidth;
203     this.el.style.height = options.height || this.el.scrollHeight || this.el.offsetHeight;
204
205     google.maps.visualRefresh = options.enableNewStyle;
206
207     for (i = 0; i < options_to_be_deleted.length; i++) {
208       delete options[options_to_be_deleted[i]];
209     }
210
211     if(options.disableDefaultUI != true) {
212       map_base_options = extend_object(map_base_options, map_controls_options);
213     }
214
215     map_options = extend_object(map_base_options, options);
216
217     for (i = 0; i < events_that_hide_context_menu.length; i++) {
218       delete map_options[events_that_hide_context_menu[i]];
219     }
220
221     for (i = 0; i < events_that_doesnt_hide_context_menu.length; i++) {
222       delete map_options[events_that_doesnt_hide_context_menu[i]];
223     }
224
225     this.map = new google.maps.Map(this.el, map_options);
226
227     if (markerClustererFunction) {
228       this.markerClusterer = markerClustererFunction.apply(this, [this.map]);
229     }
230
231     var buildContextMenuHTML = function(control, e) {
232       var html = '',
233           options = window.context_menu[self.el.id][control];
234
235       for (var i in options){
236         if (options.hasOwnProperty(i)) {
237           var option = options[i];
238
239           html += '<li><a id="' + control + '_' + i + '" href="#">' + option.title + '</a></li>';
240         }
241       }
242
243       if (!getElementById('gmaps_context_menu')) return;
244
245       var context_menu_element = getElementById('gmaps_context_menu');
246       
247       context_menu_element.innerHTML = html;
248
249       var context_menu_items = context_menu_element.getElementsByTagName('a'),
250           context_menu_items_count = context_menu_items.length
251           i;
252
253       for (i = 0; i < context_menu_items_count; i++) {
254         var context_menu_item = context_menu_items[i];
255
256         var assign_menu_item_action = function(ev){
257           ev.preventDefault();
258
259           options[this.id.replace(control + '_', '')].action.apply(self, [e]);
260           self.hideContextMenu();
261         };
262
263         google.maps.event.clearListeners(context_menu_item, 'click');
264         google.maps.event.addDomListenerOnce(context_menu_item, 'click', assign_menu_item_action, false);
265       }
266
267       var position = findAbsolutePosition.apply(this, [self.el]),
268           left = position[0] + e.pixel.x - 15,
269           top = position[1] + e.pixel.y- 15;
270
271       context_menu_element.style.left = left + "px";
272       context_menu_element.style.top = top + "px";
273
274       context_menu_element.style.display = 'block';
275     };
276
277     this.buildContextMenu = function(control, e) {
278       if (control === 'marker') {
279         e.pixel = {};
280
281         var overlay = new google.maps.OverlayView();
282         overlay.setMap(self.map);
283         
284         overlay.draw = function() {
285           var projection = overlay.getProjection(),
286               position = e.marker.getPosition();
287           
288           e.pixel = projection.fromLatLngToContainerPixel(position);
289
290           buildContextMenuHTML(control, e);
291         };
292       }
293       else {
294         buildContextMenuHTML(control, e);
295       }
296     };
297
298     this.setContextMenu = function(options) {
299       window.context_menu[self.el.id][options.control] = {};
300
301       var i,
302           ul = doc.createElement('ul');
303
304       for (i in options.options) {
305         if (options.options.hasOwnProperty(i)) {
306           var option = options.options[i];
307
308           window.context_menu[self.el.id][options.control][option.name] = {
309             title: option.title,
310             action: option.action
311           };
312         }
313       }
314
315       ul.id = 'gmaps_context_menu';
316       ul.style.display = 'none';
317       ul.style.position = 'absolute';
318       ul.style.minWidth = '100px';
319       ul.style.background = 'white';
320       ul.style.listStyle = 'none';
321       ul.style.padding = '8px';
322       ul.style.boxShadow = '2px 2px 6px #ccc';
323
324       doc.body.appendChild(ul);
325
326       var context_menu_element = getElementById('gmaps_context_menu')
327
328       google.maps.event.addDomListener(context_menu_element, 'mouseout', function(ev) {
329         if (!ev.relatedTarget || !this.contains(ev.relatedTarget)) {
330           window.setTimeout(function(){
331             context_menu_element.style.display = 'none';
332           }, 400);
333         }
334       }, false);
335     };
336
337     this.hideContextMenu = function() {
338       var context_menu_element = getElementById('gmaps_context_menu');
339
340       if (context_menu_element) {
341         context_menu_element.style.display = 'none';
342       }
343     };
344
345     var setupListener = function(object, name) {
346       google.maps.event.addListener(object, name, function(e){
347         if (e == undefined) {
348           e = this;
349         }
350
351         options[name].apply(this, [e]);
352
353         self.hideContextMenu();
354       });
355     };
356
357     for (var ev = 0; ev < events_that_hide_context_menu.length; ev++) {
358       var name = events_that_hide_context_menu[ev];
359
360       if (name in options) {
361         setupListener(this.map, name);
362       }
363     }
364
365     for (var ev = 0; ev < events_that_doesnt_hide_context_menu.length; ev++) {
366       var name = events_that_doesnt_hide_context_menu[ev];
367
368       if (name in options) {
369         setupListener(this.map, name);
370       }
371     }
372
373     google.maps.event.addListener(this.map, 'rightclick', function(e) {
374       if (options.rightclick) {
375         options.rightclick.apply(this, [e]);
376       }
377
378       if(window.context_menu[self.el.id]['map'] != undefined) {
379         self.buildContextMenu('map', e);
380       }
381     });
382
383     this.refresh = function() {
384       google.maps.event.trigger(this.map, 'resize');
385     };
386
387     this.fitZoom = function() {
388       var latLngs = [],
389           markers_length = this.markers.length,
390           i;
391
392       for (i = 0; i < markers_length; i++) {
393         latLngs.push(this.markers[i].getPosition());
394       }
395
396       this.fitLatLngBounds(latLngs);
397     };
398
399     this.fitLatLngBounds = function(latLngs) {
400       var total = latLngs.length;
401       var bounds = new google.maps.LatLngBounds();
402
403       for(var i=0; i < total; i++) {
404         bounds.extend(latLngs[i]);
405       }
406
407       this.map.fitBounds(bounds);
408     };
409
410     this.setCenter = function(lat, lng, callback) {
411       this.map.panTo(new google.maps.LatLng(lat, lng));
412
413       if (callback) {
414         callback();
415       }
416     };
417
418     this.getElement = function() {
419       return this.el;
420     };
421
422     this.zoomIn = function(value) {
423       value = value || 1;
424
425       this.zoom = this.map.getZoom() + value;
426       this.map.setZoom(this.zoom);
427     };
428
429     this.zoomOut = function(value) {
430       value = value || 1;
431
432       this.zoom = this.map.getZoom() - value;
433       this.map.setZoom(this.zoom);
434     };
435
436     var native_methods = [],
437         method;
438
439     for (method in this.map) {
440       if (typeof(this.map[method]) == 'function' && !this[method]) {
441         native_methods.push(method);
442       }
443     }
444
445     for (i=0; i < native_methods.length; i++) {
446       (function(gmaps, scope, method_name) {
447         gmaps[method_name] = function(){
448           return scope[method_name].apply(scope, arguments);
449         };
450       })(this, this.map, native_methods[i]);
451     }
452   };
453
454   return GMaps;
455 })(this);