Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
(function(root, factory) {
2
  if(typeof exports === 'object') {
3
    module.exports = factory();
4
  }
5
  else if(typeof define === 'function' && define.amd) {
6
    define('GMaps', [], factory);
7
  }
8
 
9
  root.GMaps = factory();
10
 
11
}(this, function() {
12
 
13
/*!
14
 * GMaps.js v0.4.15
15
 * http://hpneo.github.com/gmaps/
16
 *
17
 * Copyright 2014, Gustavo Leon
18
 * Released under the MIT License.
19
 */
20
 
21
if (!(typeof window.google === 'object' && window.google.maps)) {
22
  throw 'Google Maps API is required. Please register the following JavaScript library http://maps.google.com/maps/api/js?sensor=true.'
23
}
24
 
25
var extend_object = function(obj, new_obj) {
26
  var name;
27
 
28
  if (obj === new_obj) {
29
    return obj;
30
  }
31
 
32
  for (name in new_obj) {
33
    obj[name] = new_obj[name];
34
  }
35
 
36
  return obj;
37
};
38
 
39
var replace_object = function(obj, replace) {
40
  var name;
41
 
42
  if (obj === replace) {
43
    return obj;
44
  }
45
 
46
  for (name in replace) {
47
    if (obj[name] != undefined) {
48
      obj[name] = replace[name];
49
    }
50
  }
51
 
52
  return obj;
53
};
54
 
55
var array_map = function(array, callback) {
56
  var original_callback_params = Array.prototype.slice.call(arguments, 2),
57
      array_return = [],
58
      array_length = array.length,
59
      i;
60
 
61
  if (Array.prototype.map && array.map === Array.prototype.map) {
62
    array_return = Array.prototype.map.call(array, function(item) {
63
      callback_params = original_callback_params;
64
      callback_params.splice(0, 0, item);
65
 
66
      return callback.apply(this, callback_params);
67
    });
68
  }
69
  else {
70
    for (i = 0; i < array_length; i++) {
71
      callback_params = original_callback_params;
72
      callback_params.splice(0, 0, array[i]);
73
      array_return.push(callback.apply(this, callback_params));
74
    }
75
  }
76
 
77
  return array_return;
78
};
79
 
80
var array_flat = function(array) {
81
  var new_array = [],
82
      i;
83
 
84
  for (i = 0; i < array.length; i++) {
85
    new_array = new_array.concat(array[i]);
86
  }
87
 
88
  return new_array;
89
};
90
 
91
var coordsToLatLngs = function(coords, useGeoJSON) {
92
  var first_coord = coords[0],
93
      second_coord = coords[1];
94
 
95
  if (useGeoJSON) {
96
    first_coord = coords[1];
97
    second_coord = coords[0];
98
  }
99
 
100
  return new google.maps.LatLng(first_coord, second_coord);
101
};
102
 
103
var arrayToLatLng = function(coords, useGeoJSON) {
104
  var i;
105
 
106
  for (i = 0; i < coords.length; i++) {
107
    if (!(coords[i] instanceof google.maps.LatLng)) {
108
      if (coords[i].length > 0 && typeof(coords[i][0]) == "object") {
109
        coords[i] = arrayToLatLng(coords[i], useGeoJSON);
110
      }
111
      else {
112
        coords[i] = coordsToLatLngs(coords[i], useGeoJSON);
113
      }
114
    }
115
  }
116
 
117
  return coords;
118
};
119
 
120
var getElementById = function(id, context) {
121
  var element,
122
  id = id.replace('#', '');
123
 
124
  if ('jQuery' in this && context) {
125
    element = $("#" + id, context)[0];
126
  } else {
127
    element = document.getElementById(id);
128
  };
129
 
130
  return element;
131
};
132
 
133
var findAbsolutePosition = function(obj)  {
134
  var curleft = 0,
135
      curtop = 0;
136
 
137
  if (obj.offsetParent) {
138
    do {
139
      curleft += obj.offsetLeft;
140
      curtop += obj.offsetTop;
141
    } while (obj = obj.offsetParent);
142
  }
143
 
144
  return [curleft, curtop];
145
};
146
 
147
var GMaps = (function(global) {
148
  "use strict";
149
 
150
  var doc = document;
151
 
152
  var GMaps = function(options) {
153
    if (!this) return new GMaps(options);
154
 
155
    options.zoom = options.zoom || 15;
156
    options.mapType = options.mapType || 'roadmap';
157
 
158
    var self = this,
159
        i,
160
        events_that_hide_context_menu = ['bounds_changed', 'center_changed', 'click', 'dblclick', 'drag', 'dragend', 'dragstart', 'idle', 'maptypeid_changed', 'projection_changed', 'resize', 'tilesloaded', 'zoom_changed'],
161
        events_that_doesnt_hide_context_menu = ['mousemove', 'mouseout', 'mouseover'],
162
        options_to_be_deleted = ['el', 'lat', 'lng', 'mapType', 'width', 'height', 'markerClusterer', 'enableNewStyle'],
163
        container_id = options.el || options.div,
164
        markerClustererFunction = options.markerClusterer,
165
        mapType = google.maps.MapTypeId[options.mapType.toUpperCase()],
166
        map_center = new google.maps.LatLng(options.lat, options.lng),
167
        zoomControl = options.zoomControl || true,
168
        zoomControlOpt = options.zoomControlOpt || {
169
          style: 'DEFAULT',
170
          position: 'TOP_LEFT'
171
        },
172
        zoomControlStyle = zoomControlOpt.style || 'DEFAULT',
173
        zoomControlPosition = zoomControlOpt.position || 'TOP_LEFT',
174
        panControl = options.panControl || true,
175
        mapTypeControl = options.mapTypeControl || true,
176
        scaleControl = options.scaleControl || true,
177
        streetViewControl = options.streetViewControl || true,
178
        overviewMapControl = overviewMapControl || true,
179
        map_options = {},
180
        map_base_options = {
181
          zoom: this.zoom,
182
          center: map_center,
183
          mapTypeId: mapType
184
        },
185
        map_controls_options = {
186
          panControl: panControl,
187
          zoomControl: zoomControl,
188
          zoomControlOptions: {
189
            style: google.maps.ZoomControlStyle[zoomControlStyle],
190
            position: google.maps.ControlPosition[zoomControlPosition]
191
          },
192
          mapTypeControl: mapTypeControl,
193
          scaleControl: scaleControl,
194
          streetViewControl: streetViewControl,
195
          overviewMapControl: overviewMapControl
196
        };
197
 
198
    if (typeof(options.el) === 'string' || typeof(options.div) === 'string') {
199
      this.el = getElementById(container_id, options.context);
200
    } else {
201
      this.el = container_id;
202
    }
203
 
204
    if (typeof(this.el) === 'undefined' || this.el === null) {
205
      throw 'No element defined.';
206
    }
207
 
208
    window.context_menu = window.context_menu || {};
209
    window.context_menu[self.el.id] = {};
210
 
211
    this.controls = [];
212
    this.overlays = [];
213
    this.layers = []; // array with kml/georss and fusiontables layers, can be as many
214
    this.singleLayers = {}; // object with the other layers, only one per layer
215
    this.markers = [];
216
    this.polylines = [];
217
    this.routes = [];
218
    this.polygons = [];
219
    this.infoWindow = null;
220
    this.overlay_el = null;
221
    this.zoom = options.zoom;
222
    this.registered_events = {};
223
 
224
    this.el.style.width = options.width || this.el.scrollWidth || this.el.offsetWidth;
225
    this.el.style.height = options.height || this.el.scrollHeight || this.el.offsetHeight;
226
 
227
    google.maps.visualRefresh = options.enableNewStyle;
228
 
229
    for (i = 0; i < options_to_be_deleted.length; i++) {
230
      delete options[options_to_be_deleted[i]];
231
    }
232
 
233
    if(options.disableDefaultUI != true) {
234
      map_base_options = extend_object(map_base_options, map_controls_options);
235
    }
236
 
237
    map_options = extend_object(map_base_options, options);
238
 
239
    for (i = 0; i < events_that_hide_context_menu.length; i++) {
240
      delete map_options[events_that_hide_context_menu[i]];
241
    }
242
 
243
    for (i = 0; i < events_that_doesnt_hide_context_menu.length; i++) {
244
      delete map_options[events_that_doesnt_hide_context_menu[i]];
245
    }
246
 
247
    this.map = new google.maps.Map(this.el, map_options);
248
 
249
    if (markerClustererFunction) {
250
      this.markerClusterer = markerClustererFunction.apply(this, [this.map]);
251
    }
252
 
253
    var buildContextMenuHTML = function(control, e) {
254
      var html = '',
255
          options = window.context_menu[self.el.id][control];
256
 
257
      for (var i in options){
258
        if (options.hasOwnProperty(i)) {
259
          var option = options[i];
260
 
261
          html += '<li><a id="' + control + '_' + i + '" href="#">' + option.title + '</a></li>';
262
        }
263
      }
264
 
265
      if (!getElementById('gmaps_context_menu')) return;
266
 
267
      var context_menu_element = getElementById('gmaps_context_menu');
268
 
269
      context_menu_element.innerHTML = html;
270
 
271
      var context_menu_items = context_menu_element.getElementsByTagName('a'),
272
          context_menu_items_count = context_menu_items.length,
273
          i;
274
 
275
      for (i = 0; i < context_menu_items_count; i++) {
276
        var context_menu_item = context_menu_items[i];
277
 
278
        var assign_menu_item_action = function(ev){
279
          ev.preventDefault();
280
 
281
          options[this.id.replace(control + '_', '')].action.apply(self, [e]);
282
          self.hideContextMenu();
283
        };
284
 
285
        google.maps.event.clearListeners(context_menu_item, 'click');
286
        google.maps.event.addDomListenerOnce(context_menu_item, 'click', assign_menu_item_action, false);
287
      }
288
 
289
      var position = findAbsolutePosition.apply(this, [self.el]),
290
          left = position[0] + e.pixel.x - 15,
291
          top = position[1] + e.pixel.y- 15;
292
 
293
      context_menu_element.style.left = left + "px";
294
      context_menu_element.style.top = top + "px";
295
 
296
      context_menu_element.style.display = 'block';
297
    };
298
 
299
    this.buildContextMenu = function(control, e) {
300
      if (control === 'marker') {
301
        e.pixel = {};
302
 
303
        var overlay = new google.maps.OverlayView();
304
        overlay.setMap(self.map);
305
 
306
        overlay.draw = function() {
307
          var projection = overlay.getProjection(),
308
              position = e.marker.getPosition();
309
 
310
          e.pixel = projection.fromLatLngToContainerPixel(position);
311
 
312
          buildContextMenuHTML(control, e);
313
        };
314
      }
315
      else {
316
        buildContextMenuHTML(control, e);
317
      }
318
    };
319
 
320
    this.setContextMenu = function(options) {
321
      window.context_menu[self.el.id][options.control] = {};
322
 
323
      var i,
324
          ul = doc.createElement('ul');
325
 
326
      for (i in options.options) {
327
        if (options.options.hasOwnProperty(i)) {
328
          var option = options.options[i];
329
 
330
          window.context_menu[self.el.id][options.control][option.name] = {
331
            title: option.title,
332
            action: option.action
333
          };
334
        }
335
      }
336
 
337
      ul.id = 'gmaps_context_menu';
338
      ul.style.display = 'none';
339
      ul.style.position = 'absolute';
340
      ul.style.minWidth = '100px';
341
      ul.style.background = 'white';
342
      ul.style.listStyle = 'none';
343
      ul.style.padding = '8px';
344
      ul.style.boxShadow = '2px 2px 6px #ccc';
345
 
346
      doc.body.appendChild(ul);
347
 
348
      var context_menu_element = getElementById('gmaps_context_menu')
349
 
350
      google.maps.event.addDomListener(context_menu_element, 'mouseout', function(ev) {
351
        if (!ev.relatedTarget || !this.contains(ev.relatedTarget)) {
352
          window.setTimeout(function(){
353
            context_menu_element.style.display = 'none';
354
          }, 400);
355
        }
356
      }, false);
357
    };
358
 
359
    this.hideContextMenu = function() {
360
      var context_menu_element = getElementById('gmaps_context_menu');
361
 
362
      if (context_menu_element) {
363
        context_menu_element.style.display = 'none';
364
      }
365
    };
366
 
367
    var setupListener = function(object, name) {
368
      google.maps.event.addListener(object, name, function(e){
369
        if (e == undefined) {
370
          e = this;
371
        }
372
 
373
        options[name].apply(this, [e]);
374
 
375
        self.hideContextMenu();
376
      });
377
    };
378
 
379
    //google.maps.event.addListener(this.map, 'idle', this.hideContextMenu);
380
    google.maps.event.addListener(this.map, 'zoom_changed', this.hideContextMenu);
381
 
382
    for (var ev = 0; ev < events_that_hide_context_menu.length; ev++) {
383
      var name = events_that_hide_context_menu[ev];
384
 
385
      if (name in options) {
386
        setupListener(this.map, name);
387
      }
388
    }
389
 
390
    for (var ev = 0; ev < events_that_doesnt_hide_context_menu.length; ev++) {
391
      var name = events_that_doesnt_hide_context_menu[ev];
392
 
393
      if (name in options) {
394
        setupListener(this.map, name);
395
      }
396
    }
397
 
398
    google.maps.event.addListener(this.map, 'rightclick', function(e) {
399
      if (options.rightclick) {
400
        options.rightclick.apply(this, [e]);
401
      }
402
 
403
      if(window.context_menu[self.el.id]['map'] != undefined) {
404
        self.buildContextMenu('map', e);
405
      }
406
    });
407
 
408
    this.refresh = function() {
409
      google.maps.event.trigger(this.map, 'resize');
410
    };
411
 
412
    this.fitZoom = function() {
413
      var latLngs = [],
414
          markers_length = this.markers.length,
415
          i;
416
 
417
      for (i = 0; i < markers_length; i++) {
418
        if(typeof(this.markers[i].visible) === 'boolean' && this.markers[i].visible) {
419
          latLngs.push(this.markers[i].getPosition());
420
        }
421
      }
422
 
423
      this.fitLatLngBounds(latLngs);
424
    };
425
 
426
    this.fitLatLngBounds = function(latLngs) {
427
      var total = latLngs.length;
428
      var bounds = new google.maps.LatLngBounds();
429
 
430
      for(var i=0; i < total; i++) {
431
        bounds.extend(latLngs[i]);
432
      }
433
 
434
      this.map.fitBounds(bounds);
435
    };
436
 
437
    this.setCenter = function(lat, lng, callback) {
438
      this.map.panTo(new google.maps.LatLng(lat, lng));
439
 
440
      if (callback) {
441
        callback();
442
      }
443
    };
444
 
445
    this.getElement = function() {
446
      return this.el;
447
    };
448
 
449
    this.zoomIn = function(value) {
450
      value = value || 1;
451
 
452
      this.zoom = this.map.getZoom() + value;
453
      this.map.setZoom(this.zoom);
454
    };
455
 
456
    this.zoomOut = function(value) {
457
      value = value || 1;
458
 
459
      this.zoom = this.map.getZoom() - value;
460
      this.map.setZoom(this.zoom);
461
    };
462
 
463
    var native_methods = [],
464
        method;
465
 
466
    for (method in this.map) {
467
      if (typeof(this.map[method]) == 'function' && !this[method]) {
468
        native_methods.push(method);
469
      }
470
    }
471
 
472
    for (i=0; i < native_methods.length; i++) {
473
      (function(gmaps, scope, method_name) {
474
        gmaps[method_name] = function(){
475
          return scope[method_name].apply(scope, arguments);
476
        };
477
      })(this, this.map, native_methods[i]);
478
    }
479
  };
480
 
481
  return GMaps;
482
})(this);
483
 
484
GMaps.prototype.createControl = function(options) {
485
  var control = document.createElement('div');
486
 
487
  control.style.cursor = 'pointer';
488
 
489
  if (options.disableDefaultStyles !== true) {
490
    control.style.fontFamily = 'Roboto, Arial, sans-serif';
491
    control.style.fontSize = '11px';
492
    control.style.boxShadow = 'rgba(0, 0, 0, 0.298039) 0px 1px 4px -1px';
493
  }
494
 
495
  for (var option in options.style) {
496
    control.style[option] = options.style[option];
497
  }
498
 
499
  if (options.id) {
500
    control.id = options.id;
501
  }
502
 
503
  if (options.classes) {
504
    control.className = options.classes;
505
  }
506
 
507
  if (options.content) {
508
    if (typeof options.content === 'string') {
509
      control.innerHTML = options.content;
510
    }
511
    else if (options.content instanceof HTMLElement) {
512
      control.appendChild(options.content);
513
    }
514
  }
515
 
516
  if (options.position) {
517
    control.position = google.maps.ControlPosition[options.position.toUpperCase()];
518
  }
519
 
520
  for (var ev in options.events) {
521
    (function(object, name) {
522
      google.maps.event.addDomListener(object, name, function(){
523
        options.events[name].apply(this, [this]);
524
      });
525
    })(control, ev);
526
  }
527
 
528
  control.index = 1;
529
 
530
  return control;
531
};
532
 
533
GMaps.prototype.addControl = function(options) {
534
  var control = this.createControl(options);
535
  this.controls.push(control);
536
  this.map.controls[control.position].push(control);
537
 
538
  return control;
539
};
540
 
541
GMaps.prototype.removeControl = function(control) {
542
  var position = null;
543
 
544
  for (var i = 0; i < this.controls.length; i++) {
545
    if (this.controls[i] == control) {
546
      position = this.controls[i].position;
547
      this.controls.splice(i, 1);
548
    }
549
  }
550
 
551
  if (position) {
552
    for (i = 0; i < this.map.controls.length; i++) {
553
      var controlsForPosition = this.map.controls[control.position]
554
      if (controlsForPosition.getAt(i) == control) {
555
        controlsForPosition.removeAt(i);
556
        break;
557
      }
558
    }
559
  }
560
 
561
  return control;
562
};
563
 
564
GMaps.prototype.createMarker = function(options) {
565
  if (options.lat == undefined && options.lng == undefined && options.position == undefined) {
566
    throw 'No latitude or longitude defined.';
567
  }
568
 
569
  var self = this,
570
      details = options.details,
571
      fences = options.fences,
572
      outside = options.outside,
573
      base_options = {
574
        position: new google.maps.LatLng(options.lat, options.lng),
575
        map: null
576
      },
577
      marker_options = extend_object(base_options, options);
578
 
579
  delete marker_options.lat;
580
  delete marker_options.lng;
581
  delete marker_options.fences;
582
  delete marker_options.outside;
583
 
584
  var marker = new google.maps.Marker(marker_options);
585
 
586
  marker.fences = fences;
587
 
588
  if (options.infoWindow) {
589
    marker.infoWindow = new google.maps.InfoWindow(options.infoWindow);
590
 
591
    var info_window_events = ['closeclick', 'content_changed', 'domready', 'position_changed', 'zindex_changed'];
592
 
593
    for (var ev = 0; ev < info_window_events.length; ev++) {
594
      (function(object, name) {
595
        if (options.infoWindow[name]) {
596
          google.maps.event.addListener(object, name, function(e){
597
            options.infoWindow[name].apply(this, [e]);
598
          });
599
        }
600
      })(marker.infoWindow, info_window_events[ev]);
601
    }
602
  }
603
 
604
  var marker_events = ['animation_changed', 'clickable_changed', 'cursor_changed', 'draggable_changed', 'flat_changed', 'icon_changed', 'position_changed', 'shadow_changed', 'shape_changed', 'title_changed', 'visible_changed', 'zindex_changed'];
605
 
606
  var marker_events_with_mouse = ['dblclick', 'drag', 'dragend', 'dragstart', 'mousedown', 'mouseout', 'mouseover', 'mouseup'];
607
 
608
  for (var ev = 0; ev < marker_events.length; ev++) {
609
    (function(object, name) {
610
      if (options[name]) {
611
        google.maps.event.addListener(object, name, function(){
612
          options[name].apply(this, [this]);
613
        });
614
      }
615
    })(marker, marker_events[ev]);
616
  }
617
 
618
  for (var ev = 0; ev < marker_events_with_mouse.length; ev++) {
619
    (function(map, object, name) {
620
      if (options[name]) {
621
        google.maps.event.addListener(object, name, function(me){
622
          if(!me.pixel){
623
            me.pixel = map.getProjection().fromLatLngToPoint(me.latLng)
624
          }
625
 
626
          options[name].apply(this, [me]);
627
        });
628
      }
629
    })(this.map, marker, marker_events_with_mouse[ev]);
630
  }
631
 
632
  google.maps.event.addListener(marker, 'click', function() {
633
    this.details = details;
634
 
635
    if (options.click) {
636
      options.click.apply(this, [this]);
637
    }
638
 
639
    if (marker.infoWindow) {
640
      self.hideInfoWindows();
641
      marker.infoWindow.open(self.map, marker);
642
    }
643
  });
644
 
645
  google.maps.event.addListener(marker, 'rightclick', function(e) {
646
    e.marker = this;
647
 
648
    if (options.rightclick) {
649
      options.rightclick.apply(this, [e]);
650
    }
651
 
652
    if (window.context_menu[self.el.id]['marker'] != undefined) {
653
      self.buildContextMenu('marker', e);
654
    }
655
  });
656
 
657
  if (marker.fences) {
658
    google.maps.event.addListener(marker, 'dragend', function() {
659
      self.checkMarkerGeofence(marker, function(m, f) {
660
        outside(m, f);
661
      });
662
    });
663
  }
664
 
665
  return marker;
666
};
667
 
668
GMaps.prototype.addMarker = function(options) {
669
  var marker;
670
  if(options.hasOwnProperty('gm_accessors_')) {
671
    // Native google.maps.Marker object
672
    marker = options;
673
  }
674
  else {
675
    if ((options.hasOwnProperty('lat') && options.hasOwnProperty('lng')) || options.position) {
676
      marker = this.createMarker(options);
677
    }
678
    else {
679
      throw 'No latitude or longitude defined.';
680
    }
681
  }
682
 
683
  marker.setMap(this.map);
684
 
685
  if(this.markerClusterer) {
686
    this.markerClusterer.addMarker(marker);
687
  }
688
 
689
  this.markers.push(marker);
690
 
691
  GMaps.fire('marker_added', marker, this);
692
 
693
  return marker;
694
};
695
 
696
GMaps.prototype.addMarkers = function(array) {
697
  for (var i = 0, marker; marker=array[i]; i++) {
698
    this.addMarker(marker);
699
  }
700
 
701
  return this.markers;
702
};
703
 
704
GMaps.prototype.hideInfoWindows = function() {
705
  for (var i = 0, marker; marker = this.markers[i]; i++){
706
    if (marker.infoWindow) {
707
      marker.infoWindow.close();
708
    }
709
  }
710
};
711
 
712
GMaps.prototype.removeMarker = function(marker) {
713
  for (var i = 0; i < this.markers.length; i++) {
714
    if (this.markers[i] === marker) {
715
      this.markers[i].setMap(null);
716
      this.markers.splice(i, 1);
717
 
718
      if(this.markerClusterer) {
719
        this.markerClusterer.removeMarker(marker);
720
      }
721
 
722
      GMaps.fire('marker_removed', marker, this);
723
 
724
      break;
725
    }
726
  }
727
 
728
  return marker;
729
};
730
 
731
GMaps.prototype.removeMarkers = function (collection) {
732
  var new_markers = [];
733
 
734
  if (typeof collection == 'undefined') {
735
    for (var i = 0; i < this.markers.length; i++) {
736
      this.markers[i].setMap(null);
737
    }
738
 
739
    this.markers = new_markers;
740
  }
741
  else {
742
    for (var i = 0; i < collection.length; i++) {
743
      if (this.markers.indexOf(collection[i]) > -1) {
744
        this.markers[i].setMap(null);
745
      }
746
    }
747
 
748
    for (var i = 0; i < this.markers.length; i++) {
749
      if (this.markers[i].getMap() != null) {
750
        new_markers.push(this.markers[i]);
751
      }
752
    }
753
 
754
    this.markers = new_markers;
755
  }
756
};
757
 
758
GMaps.prototype.drawOverlay = function(options) {
759
  var overlay = new google.maps.OverlayView(),
760
      auto_show = true;
761
 
762
  overlay.setMap(this.map);
763
 
764
  if (options.auto_show != null) {
765
    auto_show = options.auto_show;
766
  }
767
 
768
  overlay.onAdd = function() {
769
    var el = document.createElement('div');
770
 
771
    el.style.borderStyle = "none";
772
    el.style.borderWidth = "0px";
773
    el.style.position = "absolute";
774
    el.style.zIndex = 100;
775
    el.innerHTML = options.content;
776
 
777
    overlay.el = el;
778
 
779
    if (!options.layer) {
780
      options.layer = 'overlayLayer';
781
    }
782
 
783
    var panes = this.getPanes(),
784
        overlayLayer = panes[options.layer],
785
        stop_overlay_events = ['contextmenu', 'DOMMouseScroll', 'dblclick', 'mousedown'];
786
 
787
    overlayLayer.appendChild(el);
788
 
789
    for (var ev = 0; ev < stop_overlay_events.length; ev++) {
790
      (function(object, name) {
791
        google.maps.event.addDomListener(object, name, function(e){
792
          if (navigator.userAgent.toLowerCase().indexOf('msie') != -1 && document.all) {
793
            e.cancelBubble = true;
794
            e.returnValue = false;
795
          }
796
          else {
797
            e.stopPropagation();
798
          }
799
        });
800
      })(el, stop_overlay_events[ev]);
801
    }
802
 
803
    if (options.click) {
804
      panes.overlayMouseTarget.appendChild(overlay.el);
805
      google.maps.event.addDomListener(overlay.el, 'click', function() {
806
        options.click.apply(overlay, [overlay]);
807
      });
808
    }
809
 
810
    google.maps.event.trigger(this, 'ready');
811
  };
812
 
813
  overlay.draw = function() {
814
    var projection = this.getProjection(),
815
        pixel = projection.fromLatLngToDivPixel(new google.maps.LatLng(options.lat, options.lng));
816
 
817
    options.horizontalOffset = options.horizontalOffset || 0;
818
    options.verticalOffset = options.verticalOffset || 0;
819
 
820
    var el = overlay.el,
821
        content = el.children[0],
822
        content_height = content.clientHeight,
823
        content_width = content.clientWidth;
824
 
825
    switch (options.verticalAlign) {
826
      case 'top':
827
        el.style.top = (pixel.y - content_height + options.verticalOffset) + 'px';
828
        break;
829
      default:
830
      case 'middle':
831
        el.style.top = (pixel.y - (content_height / 2) + options.verticalOffset) + 'px';
832
        break;
833
      case 'bottom':
834
        el.style.top = (pixel.y + options.verticalOffset) + 'px';
835
        break;
836
    }
837
 
838
    switch (options.horizontalAlign) {
839
      case 'left':
840
        el.style.left = (pixel.x - content_width + options.horizontalOffset) + 'px';
841
        break;
842
      default:
843
      case 'center':
844
        el.style.left = (pixel.x - (content_width / 2) + options.horizontalOffset) + 'px';
845
        break;
846
      case 'right':
847
        el.style.left = (pixel.x + options.horizontalOffset) + 'px';
848
        break;
849
    }
850
 
851
    el.style.display = auto_show ? 'block' : 'none';
852
 
853
    if (!auto_show) {
854
      options.show.apply(this, [el]);
855
    }
856
  };
857
 
858
  overlay.onRemove = function() {
859
    var el = overlay.el;
860
 
861
    if (options.remove) {
862
      options.remove.apply(this, [el]);
863
    }
864
    else {
865
      overlay.el.parentNode.removeChild(overlay.el);
866
      overlay.el = null;
867
    }
868
  };
869
 
870
  this.overlays.push(overlay);
871
  return overlay;
872
};
873
 
874
GMaps.prototype.removeOverlay = function(overlay) {
875
  for (var i = 0; i < this.overlays.length; i++) {
876
    if (this.overlays[i] === overlay) {
877
      this.overlays[i].setMap(null);
878
      this.overlays.splice(i, 1);
879
 
880
      break;
881
    }
882
  }
883
};
884
 
885
GMaps.prototype.removeOverlays = function() {
886
  for (var i = 0, item; item = this.overlays[i]; i++) {
887
    item.setMap(null);
888
  }
889
 
890
  this.overlays = [];
891
};
892
 
893
GMaps.prototype.drawPolyline = function(options) {
894
  var path = [],
895
      points = options.path;
896
 
897
  if (points.length) {
898
    if (points[0][0] === undefined) {
899
      path = points;
900
    }
901
    else {
902
      for (var i=0, latlng; latlng=points[i]; i++) {
903
        path.push(new google.maps.LatLng(latlng[0], latlng[1]));
904
      }
905
    }
906
  }
907
 
908
  var polyline_options = {
909
    map: this.map,
910
    path: path,
911
    strokeColor: options.strokeColor,
912
    strokeOpacity: options.strokeOpacity,
913
    strokeWeight: options.strokeWeight,
914
    geodesic: options.geodesic,
915
    clickable: true,
916
    editable: false,
917
    visible: true
918
  };
919
 
920
  if (options.hasOwnProperty("clickable")) {
921
    polyline_options.clickable = options.clickable;
922
  }
923
 
924
  if (options.hasOwnProperty("editable")) {
925
    polyline_options.editable = options.editable;
926
  }
927
 
928
  if (options.hasOwnProperty("icons")) {
929
    polyline_options.icons = options.icons;
930
  }
931
 
932
  if (options.hasOwnProperty("zIndex")) {
933
    polyline_options.zIndex = options.zIndex;
934
  }
935
 
936
  var polyline = new google.maps.Polyline(polyline_options);
937
 
938
  var polyline_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
939
 
940
  for (var ev = 0; ev < polyline_events.length; ev++) {
941
    (function(object, name) {
942
      if (options[name]) {
943
        google.maps.event.addListener(object, name, function(e){
944
          options[name].apply(this, [e]);
945
        });
946
      }
947
    })(polyline, polyline_events[ev]);
948
  }
949
 
950
  this.polylines.push(polyline);
951
 
952
  GMaps.fire('polyline_added', polyline, this);
953
 
954
  return polyline;
955
};
956
 
957
GMaps.prototype.removePolyline = function(polyline) {
958
  for (var i = 0; i < this.polylines.length; i++) {
959
    if (this.polylines[i] === polyline) {
960
      this.polylines[i].setMap(null);
961
      this.polylines.splice(i, 1);
962
 
963
      GMaps.fire('polyline_removed', polyline, this);
964
 
965
      break;
966
    }
967
  }
968
};
969
 
970
GMaps.prototype.removePolylines = function() {
971
  for (var i = 0, item; item = this.polylines[i]; i++) {
972
    item.setMap(null);
973
  }
974
 
975
  this.polylines = [];
976
};
977
 
978
GMaps.prototype.drawCircle = function(options) {
979
  options =  extend_object({
980
    map: this.map,
981
    center: new google.maps.LatLng(options.lat, options.lng)
982
  }, options);
983
 
984
  delete options.lat;
985
  delete options.lng;
986
 
987
  var polygon = new google.maps.Circle(options),
988
      polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
989
 
990
  for (var ev = 0; ev < polygon_events.length; ev++) {
991
    (function(object, name) {
992
      if (options[name]) {
993
        google.maps.event.addListener(object, name, function(e){
994
          options[name].apply(this, [e]);
995
        });
996
      }
997
    })(polygon, polygon_events[ev]);
998
  }
999
 
1000
  this.polygons.push(polygon);
1001
 
1002
  return polygon;
1003
};
1004
 
1005
GMaps.prototype.drawRectangle = function(options) {
1006
  options = extend_object({
1007
    map: this.map
1008
  }, options);
1009
 
1010
  var latLngBounds = new google.maps.LatLngBounds(
1011
    new google.maps.LatLng(options.bounds[0][0], options.bounds[0][1]),
1012
    new google.maps.LatLng(options.bounds[1][0], options.bounds[1][1])
1013
  );
1014
 
1015
  options.bounds = latLngBounds;
1016
 
1017
  var polygon = new google.maps.Rectangle(options),
1018
      polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
1019
 
1020
  for (var ev = 0; ev < polygon_events.length; ev++) {
1021
    (function(object, name) {
1022
      if (options[name]) {
1023
        google.maps.event.addListener(object, name, function(e){
1024
          options[name].apply(this, [e]);
1025
        });
1026
      }
1027
    })(polygon, polygon_events[ev]);
1028
  }
1029
 
1030
  this.polygons.push(polygon);
1031
 
1032
  return polygon;
1033
};
1034
 
1035
GMaps.prototype.drawPolygon = function(options) {
1036
  var useGeoJSON = false;
1037
 
1038
  if(options.hasOwnProperty("useGeoJSON")) {
1039
    useGeoJSON = options.useGeoJSON;
1040
  }
1041
 
1042
  delete options.useGeoJSON;
1043
 
1044
  options = extend_object({
1045
    map: this.map
1046
  }, options);
1047
 
1048
  if (useGeoJSON == false) {
1049
    options.paths = [options.paths.slice(0)];
1050
  }
1051
 
1052
  if (options.paths.length > 0) {
1053
    if (options.paths[0].length > 0) {
1054
      options.paths = array_flat(array_map(options.paths, arrayToLatLng, useGeoJSON));
1055
    }
1056
  }
1057
 
1058
  var polygon = new google.maps.Polygon(options),
1059
      polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
1060
 
1061
  for (var ev = 0; ev < polygon_events.length; ev++) {
1062
    (function(object, name) {
1063
      if (options[name]) {
1064
        google.maps.event.addListener(object, name, function(e){
1065
          options[name].apply(this, [e]);
1066
        });
1067
      }
1068
    })(polygon, polygon_events[ev]);
1069
  }
1070
 
1071
  this.polygons.push(polygon);
1072
 
1073
  GMaps.fire('polygon_added', polygon, this);
1074
 
1075
  return polygon;
1076
};
1077
 
1078
GMaps.prototype.removePolygon = function(polygon) {
1079
  for (var i = 0; i < this.polygons.length; i++) {
1080
    if (this.polygons[i] === polygon) {
1081
      this.polygons[i].setMap(null);
1082
      this.polygons.splice(i, 1);
1083
 
1084
      GMaps.fire('polygon_removed', polygon, this);
1085
 
1086
      break;
1087
    }
1088
  }
1089
};
1090
 
1091
GMaps.prototype.removePolygons = function() {
1092
  for (var i = 0, item; item = this.polygons[i]; i++) {
1093
    item.setMap(null);
1094
  }
1095
 
1096
  this.polygons = [];
1097
};
1098
 
1099
GMaps.prototype.getFromFusionTables = function(options) {
1100
  var events = options.events;
1101
 
1102
  delete options.events;
1103
 
1104
  var fusion_tables_options = options,
1105
      layer = new google.maps.FusionTablesLayer(fusion_tables_options);
1106
 
1107
  for (var ev in events) {
1108
    (function(object, name) {
1109
      google.maps.event.addListener(object, name, function(e) {
1110
        events[name].apply(this, [e]);
1111
      });
1112
    })(layer, ev);
1113
  }
1114
 
1115
  this.layers.push(layer);
1116
 
1117
  return layer;
1118
};
1119
 
1120
GMaps.prototype.loadFromFusionTables = function(options) {
1121
  var layer = this.getFromFusionTables(options);
1122
  layer.setMap(this.map);
1123
 
1124
  return layer;
1125
};
1126
 
1127
GMaps.prototype.getFromKML = function(options) {
1128
  var url = options.url,
1129
      events = options.events;
1130
 
1131
  delete options.url;
1132
  delete options.events;
1133
 
1134
  var kml_options = options,
1135
      layer = new google.maps.KmlLayer(url, kml_options);
1136
 
1137
  for (var ev in events) {
1138
    (function(object, name) {
1139
      google.maps.event.addListener(object, name, function(e) {
1140
        events[name].apply(this, [e]);
1141
      });
1142
    })(layer, ev);
1143
  }
1144
 
1145
  this.layers.push(layer);
1146
 
1147
  return layer;
1148
};
1149
 
1150
GMaps.prototype.loadFromKML = function(options) {
1151
  var layer = this.getFromKML(options);
1152
  layer.setMap(this.map);
1153
 
1154
  return layer;
1155
};
1156
 
1157
GMaps.prototype.addLayer = function(layerName, options) {
1158
  //var default_layers = ['weather', 'clouds', 'traffic', 'transit', 'bicycling', 'panoramio', 'places'];
1159
  options = options || {};
1160
  var layer;
1161
 
1162
  switch(layerName) {
1163
    case 'weather': this.singleLayers.weather = layer = new google.maps.weather.WeatherLayer();
1164
      break;
1165
    case 'clouds': this.singleLayers.clouds = layer = new google.maps.weather.CloudLayer();
1166
      break;
1167
    case 'traffic': this.singleLayers.traffic = layer = new google.maps.TrafficLayer();
1168
      break;
1169
    case 'transit': this.singleLayers.transit = layer = new google.maps.TransitLayer();
1170
      break;
1171
    case 'bicycling': this.singleLayers.bicycling = layer = new google.maps.BicyclingLayer();
1172
      break;
1173
    case 'panoramio':
1174
        this.singleLayers.panoramio = layer = new google.maps.panoramio.PanoramioLayer();
1175
        layer.setTag(options.filter);
1176
        delete options.filter;
1177
 
1178
        //click event
1179
        if (options.click) {
1180
          google.maps.event.addListener(layer, 'click', function(event) {
1181
            options.click(event);
1182
            delete options.click;
1183
          });
1184
        }
1185
      break;
1186
      case 'places':
1187
        this.singleLayers.places = layer = new google.maps.places.PlacesService(this.map);
1188
 
1189
        //search, nearbySearch, radarSearch callback, Both are the same
1190
        if (options.search || options.nearbySearch || options.radarSearch) {
1191
          var placeSearchRequest  = {
1192
            bounds : options.bounds || null,
1193
            keyword : options.keyword || null,
1194
            location : options.location || null,
1195
            name : options.name || null,
1196
            radius : options.radius || null,
1197
            rankBy : options.rankBy || null,
1198
            types : options.types || null
1199
          };
1200
 
1201
          if (options.radarSearch) {
1202
            layer.radarSearch(placeSearchRequest, options.radarSearch);
1203
          }
1204
 
1205
          if (options.search) {
1206
            layer.search(placeSearchRequest, options.search);
1207
          }
1208
 
1209
          if (options.nearbySearch) {
1210
            layer.nearbySearch(placeSearchRequest, options.nearbySearch);
1211
          }
1212
        }
1213
 
1214
        //textSearch callback
1215
        if (options.textSearch) {
1216
          var textSearchRequest  = {
1217
            bounds : options.bounds || null,
1218
            location : options.location || null,
1219
            query : options.query || null,
1220
            radius : options.radius || null
1221
          };
1222
 
1223
          layer.textSearch(textSearchRequest, options.textSearch);
1224
        }
1225
      break;
1226
  }
1227
 
1228
  if (layer !== undefined) {
1229
    if (typeof layer.setOptions == 'function') {
1230
      layer.setOptions(options);
1231
    }
1232
    if (typeof layer.setMap == 'function') {
1233
      layer.setMap(this.map);
1234
    }
1235
 
1236
    return layer;
1237
  }
1238
};
1239
 
1240
GMaps.prototype.removeLayer = function(layer) {
1241
  if (typeof(layer) == "string" && this.singleLayers[layer] !== undefined) {
1242
     this.singleLayers[layer].setMap(null);
1243
 
1244
     delete this.singleLayers[layer];
1245
  }
1246
  else {
1247
    for (var i = 0; i < this.layers.length; i++) {
1248
      if (this.layers[i] === layer) {
1249
        this.layers[i].setMap(null);
1250
        this.layers.splice(i, 1);
1251
 
1252
        break;
1253
      }
1254
    }
1255
  }
1256
};
1257
 
1258
var travelMode, unitSystem;
1259
 
1260
GMaps.prototype.getRoutes = function(options) {
1261
  switch (options.travelMode) {
1262
    case 'bicycling':
1263
      travelMode = google.maps.TravelMode.BICYCLING;
1264
      break;
1265
    case 'transit':
1266
      travelMode = google.maps.TravelMode.TRANSIT;
1267
      break;
1268
    case 'driving':
1269
      travelMode = google.maps.TravelMode.DRIVING;
1270
      break;
1271
    default:
1272
      travelMode = google.maps.TravelMode.WALKING;
1273
      break;
1274
  }
1275
 
1276
  if (options.unitSystem === 'imperial') {
1277
    unitSystem = google.maps.UnitSystem.IMPERIAL;
1278
  }
1279
  else {
1280
    unitSystem = google.maps.UnitSystem.METRIC;
1281
  }
1282
 
1283
  var base_options = {
1284
        avoidHighways: false,
1285
        avoidTolls: false,
1286
        optimizeWaypoints: false,
1287
        waypoints: []
1288
      },
1289
      request_options =  extend_object(base_options, options);
1290
 
1291
  request_options.origin = /string/.test(typeof options.origin) ? options.origin : new google.maps.LatLng(options.origin[0], options.origin[1]);
1292
  request_options.destination = /string/.test(typeof options.destination) ? options.destination : new google.maps.LatLng(options.destination[0], options.destination[1]);
1293
  request_options.travelMode = travelMode;
1294
  request_options.unitSystem = unitSystem;
1295
 
1296
  delete request_options.callback;
1297
  delete request_options.error;
1298
 
1299
  var self = this,
1300
      service = new google.maps.DirectionsService();
1301
 
1302
  service.route(request_options, function(result, status) {
1303
    if (status === google.maps.DirectionsStatus.OK) {
1304
      for (var r in result.routes) {
1305
        if (result.routes.hasOwnProperty(r)) {
1306
          self.routes.push(result.routes[r]);
1307
        }
1308
      }
1309
 
1310
      if (options.callback) {
1311
        options.callback(self.routes);
1312
      }
1313
    }
1314
    else {
1315
      if (options.error) {
1316
        options.error(result, status);
1317
      }
1318
    }
1319
  });
1320
};
1321
 
1322
GMaps.prototype.removeRoutes = function() {
1323
  this.routes = [];
1324
};
1325
 
1326
GMaps.prototype.getElevations = function(options) {
1327
  options = extend_object({
1328
    locations: [],
1329
    path : false,
1330
    samples : 256
1331
  }, options);
1332
 
1333
  if (options.locations.length > 0) {
1334
    if (options.locations[0].length > 0) {
1335
      options.locations = array_flat(array_map([options.locations], arrayToLatLng,  false));
1336
    }
1337
  }
1338
 
1339
  var callback = options.callback;
1340
  delete options.callback;
1341
 
1342
  var service = new google.maps.ElevationService();
1343
 
1344
  //location request
1345
  if (!options.path) {
1346
    delete options.path;
1347
    delete options.samples;
1348
 
1349
    service.getElevationForLocations(options, function(result, status) {
1350
      if (callback && typeof(callback) === "function") {
1351
        callback(result, status);
1352
      }
1353
    });
1354
  //path request
1355
  } else {
1356
    var pathRequest = {
1357
      path : options.locations,
1358
      samples : options.samples
1359
    };
1360
 
1361
    service.getElevationAlongPath(pathRequest, function(result, status) {
1362
     if (callback && typeof(callback) === "function") {
1363
        callback(result, status);
1364
      }
1365
    });
1366
  }
1367
};
1368
 
1369
GMaps.prototype.cleanRoute = GMaps.prototype.removePolylines;
1370
 
1371
GMaps.prototype.drawRoute = function(options) {
1372
  var self = this;
1373
 
1374
  this.getRoutes({
1375
    origin: options.origin,
1376
    destination: options.destination,
1377
    travelMode: options.travelMode,
1378
    waypoints: options.waypoints,
1379
    unitSystem: options.unitSystem,
1380
    error: options.error,
1381
    callback: function(e) {
1382
      if (e.length > 0) {
1383
        self.drawPolyline({
1384
          path: e[e.length - 1].overview_path,
1385
          strokeColor: options.strokeColor,
1386
          strokeOpacity: options.strokeOpacity,
1387
          strokeWeight: options.strokeWeight
1388
        });
1389
 
1390
        if (options.callback) {
1391
          options.callback(e[e.length - 1]);
1392
        }
1393
      }
1394
    }
1395
  });
1396
};
1397
 
1398
GMaps.prototype.travelRoute = function(options) {
1399
  if (options.origin && options.destination) {
1400
    this.getRoutes({
1401
      origin: options.origin,
1402
      destination: options.destination,
1403
      travelMode: options.travelMode,
1404
      waypoints : options.waypoints,
1405
      unitSystem: options.unitSystem,
1406
      error: options.error,
1407
      callback: function(e) {
1408
        //start callback
1409
        if (e.length > 0 && options.start) {
1410
          options.start(e[e.length - 1]);
1411
        }
1412
 
1413
        //step callback
1414
        if (e.length > 0 && options.step) {
1415
          var route = e[e.length - 1];
1416
          if (route.legs.length > 0) {
1417
            var steps = route.legs[0].steps;
1418
            for (var i=0, step; step=steps[i]; i++) {
1419
              step.step_number = i;
1420
              options.step(step, (route.legs[0].steps.length - 1));
1421
            }
1422
          }
1423
        }
1424
 
1425
        //end callback
1426
        if (e.length > 0 && options.end) {
1427
           options.end(e[e.length - 1]);
1428
        }
1429
      }
1430
    });
1431
  }
1432
  else if (options.route) {
1433
    if (options.route.legs.length > 0) {
1434
      var steps = options.route.legs[0].steps;
1435
      for (var i=0, step; step=steps[i]; i++) {
1436
        step.step_number = i;
1437
        options.step(step);
1438
      }
1439
    }
1440
  }
1441
};
1442
 
1443
GMaps.prototype.drawSteppedRoute = function(options) {
1444
  var self = this;
1445
 
1446
  if (options.origin && options.destination) {
1447
    this.getRoutes({
1448
      origin: options.origin,
1449
      destination: options.destination,
1450
      travelMode: options.travelMode,
1451
      waypoints : options.waypoints,
1452
      error: options.error,
1453
      callback: function(e) {
1454
        //start callback
1455
        if (e.length > 0 && options.start) {
1456
          options.start(e[e.length - 1]);
1457
        }
1458
 
1459
        //step callback
1460
        if (e.length > 0 && options.step) {
1461
          var route = e[e.length - 1];
1462
          if (route.legs.length > 0) {
1463
            var steps = route.legs[0].steps;
1464
            for (var i=0, step; step=steps[i]; i++) {
1465
              step.step_number = i;
1466
              self.drawPolyline({
1467
                path: step.path,
1468
                strokeColor: options.strokeColor,
1469
                strokeOpacity: options.strokeOpacity,
1470
                strokeWeight: options.strokeWeight
1471
              });
1472
              options.step(step, (route.legs[0].steps.length - 1));
1473
            }
1474
          }
1475
        }
1476
 
1477
        //end callback
1478
        if (e.length > 0 && options.end) {
1479
           options.end(e[e.length - 1]);
1480
        }
1481
      }
1482
    });
1483
  }
1484
  else if (options.route) {
1485
    if (options.route.legs.length > 0) {
1486
      var steps = options.route.legs[0].steps;
1487
      for (var i=0, step; step=steps[i]; i++) {
1488
        step.step_number = i;
1489
        self.drawPolyline({
1490
          path: step.path,
1491
          strokeColor: options.strokeColor,
1492
          strokeOpacity: options.strokeOpacity,
1493
          strokeWeight: options.strokeWeight
1494
        });
1495
        options.step(step);
1496
      }
1497
    }
1498
  }
1499
};
1500
 
1501
GMaps.Route = function(options) {
1502
  this.origin = options.origin;
1503
  this.destination = options.destination;
1504
  this.waypoints = options.waypoints;
1505
 
1506
  this.map = options.map;
1507
  this.route = options.route;
1508
  this.step_count = 0;
1509
  this.steps = this.route.legs[0].steps;
1510
  this.steps_length = this.steps.length;
1511
 
1512
  this.polyline = this.map.drawPolyline({
1513
    path: new google.maps.MVCArray(),
1514
    strokeColor: options.strokeColor,
1515
    strokeOpacity: options.strokeOpacity,
1516
    strokeWeight: options.strokeWeight
1517
  }).getPath();
1518
};
1519
 
1520
GMaps.Route.prototype.getRoute = function(options) {
1521
  var self = this;
1522
 
1523
  this.map.getRoutes({
1524
    origin : this.origin,
1525
    destination : this.destination,
1526
    travelMode : options.travelMode,
1527
    waypoints : this.waypoints || [],
1528
    error: options.error,
1529
    callback : function() {
1530
      self.route = e[0];
1531
 
1532
      if (options.callback) {
1533
        options.callback.call(self);
1534
      }
1535
    }
1536
  });
1537
};
1538
 
1539
GMaps.Route.prototype.back = function() {
1540
  if (this.step_count > 0) {
1541
    this.step_count--;
1542
    var path = this.route.legs[0].steps[this.step_count].path;
1543
 
1544
    for (var p in path){
1545
      if (path.hasOwnProperty(p)){
1546
        this.polyline.pop();
1547
      }
1548
    }
1549
  }
1550
};
1551
 
1552
GMaps.Route.prototype.forward = function() {
1553
  if (this.step_count < this.steps_length) {
1554
    var path = this.route.legs[0].steps[this.step_count].path;
1555
 
1556
    for (var p in path){
1557
      if (path.hasOwnProperty(p)){
1558
        this.polyline.push(path[p]);
1559
      }
1560
    }
1561
    this.step_count++;
1562
  }
1563
};
1564
 
1565
GMaps.prototype.checkGeofence = function(lat, lng, fence) {
1566
  return fence.containsLatLng(new google.maps.LatLng(lat, lng));
1567
};
1568
 
1569
GMaps.prototype.checkMarkerGeofence = function(marker, outside_callback) {
1570
  if (marker.fences) {
1571
    for (var i = 0, fence; fence = marker.fences[i]; i++) {
1572
      var pos = marker.getPosition();
1573
      if (!this.checkGeofence(pos.lat(), pos.lng(), fence)) {
1574
        outside_callback(marker, fence);
1575
      }
1576
    }
1577
  }
1578
};
1579
 
1580
GMaps.prototype.toImage = function(options) {
1581
  var options = options || {},
1582
      static_map_options = {};
1583
 
1584
  static_map_options['size'] = options['size'] || [this.el.clientWidth, this.el.clientHeight];
1585
  static_map_options['lat'] = this.getCenter().lat();
1586
  static_map_options['lng'] = this.getCenter().lng();
1587
 
1588
  if (this.markers.length > 0) {
1589
    static_map_options['markers'] = [];
1590
 
1591
    for (var i = 0; i < this.markers.length; i++) {
1592
      static_map_options['markers'].push({
1593
        lat: this.markers[i].getPosition().lat(),
1594
        lng: this.markers[i].getPosition().lng()
1595
      });
1596
    }
1597
  }
1598
 
1599
  if (this.polylines.length > 0) {
1600
    var polyline = this.polylines[0];
1601
 
1602
    static_map_options['polyline'] = {};
1603
    static_map_options['polyline']['path'] = google.maps.geometry.encoding.encodePath(polyline.getPath());
1604
    static_map_options['polyline']['strokeColor'] = polyline.strokeColor
1605
    static_map_options['polyline']['strokeOpacity'] = polyline.strokeOpacity
1606
    static_map_options['polyline']['strokeWeight'] = polyline.strokeWeight
1607
  }
1608
 
1609
  return GMaps.staticMapURL(static_map_options);
1610
};
1611
 
1612
GMaps.staticMapURL = function(options){
1613
  var parameters = [],
1614
      data,
1615
      static_root = 'http://maps.googleapis.com/maps/api/staticmap';
1616
 
1617
  if (options.url) {
1618
    static_root = options.url;
1619
    delete options.url;
1620
  }
1621
 
1622
  static_root += '?';
1623
 
1624
  var markers = options.markers;
1625
 
1626
  delete options.markers;
1627
 
1628
  if (!markers && options.marker) {
1629
    markers = [options.marker];
1630
    delete options.marker;
1631
  }
1632
 
1633
  var styles = options.styles;
1634
 
1635
  delete options.styles;
1636
 
1637
  var polyline = options.polyline;
1638
  delete options.polyline;
1639
 
1640
  /** Map options **/
1641
  if (options.center) {
1642
    parameters.push('center=' + options.center);
1643
    delete options.center;
1644
  }
1645
  else if (options.address) {
1646
    parameters.push('center=' + options.address);
1647
    delete options.address;
1648
  }
1649
  else if (options.lat) {
1650
    parameters.push(['center=', options.lat, ',', options.lng].join(''));
1651
    delete options.lat;
1652
    delete options.lng;
1653
  }
1654
  else if (options.visible) {
1655
    var visible = encodeURI(options.visible.join('|'));
1656
    parameters.push('visible=' + visible);
1657
  }
1658
 
1659
  var size = options.size;
1660
  if (size) {
1661
    if (size.join) {
1662
      size = size.join('x');
1663
    }
1664
    delete options.size;
1665
  }
1666
  else {
1667
    size = '630x300';
1668
  }
1669
  parameters.push('size=' + size);
1670
 
1671
  if (!options.zoom && options.zoom !== false) {
1672
    options.zoom = 15;
1673
  }
1674
 
1675
  var sensor = options.hasOwnProperty('sensor') ? !!options.sensor : true;
1676
  delete options.sensor;
1677
  parameters.push('sensor=' + sensor);
1678
 
1679
  for (var param in options) {
1680
    if (options.hasOwnProperty(param)) {
1681
      parameters.push(param + '=' + options[param]);
1682
    }
1683
  }
1684
 
1685
  /** Markers **/
1686
  if (markers) {
1687
    var marker, loc;
1688
 
1689
    for (var i=0; data=markers[i]; i++) {
1690
      marker = [];
1691
 
1692
      if (data.size && data.size !== 'normal') {
1693
        marker.push('size:' + data.size);
1694
        delete data.size;
1695
      }
1696
      else if (data.icon) {
1697
        marker.push('icon:' + encodeURI(data.icon));
1698
        delete data.icon;
1699
      }
1700
 
1701
      if (data.color) {
1702
        marker.push('color:' + data.color.replace('#', '0x'));
1703
        delete data.color;
1704
      }
1705
 
1706
      if (data.label) {
1707
        marker.push('label:' + data.label[0].toUpperCase());
1708
        delete data.label;
1709
      }
1710
 
1711
      loc = (data.address ? data.address : data.lat + ',' + data.lng);
1712
      delete data.address;
1713
      delete data.lat;
1714
      delete data.lng;
1715
 
1716
      for(var param in data){
1717
        if (data.hasOwnProperty(param)) {
1718
          marker.push(param + ':' + data[param]);
1719
        }
1720
      }
1721
 
1722
      if (marker.length || i === 0) {
1723
        marker.push(loc);
1724
        marker = marker.join('|');
1725
        parameters.push('markers=' + encodeURI(marker));
1726
      }
1727
      // New marker without styles
1728
      else {
1729
        marker = parameters.pop() + encodeURI('|' + loc);
1730
        parameters.push(marker);
1731
      }
1732
    }
1733
  }
1734
 
1735
  /** Map Styles **/
1736
  if (styles) {
1737
    for (var i = 0; i < styles.length; i++) {
1738
      var styleRule = [];
1739
      if (styles[i].featureType){
1740
        styleRule.push('feature:' + styles[i].featureType.toLowerCase());
1741
      }
1742
 
1743
      if (styles[i].elementType) {
1744
        styleRule.push('element:' + styles[i].elementType.toLowerCase());
1745
      }
1746
 
1747
      for (var j = 0; j < styles[i].stylers.length; j++) {
1748
        for (var p in styles[i].stylers[j]) {
1749
          var ruleArg = styles[i].stylers[j][p];
1750
          if (p == 'hue' || p == 'color') {
1751
            ruleArg = '0x' + ruleArg.substring(1);
1752
          }
1753
          styleRule.push(p + ':' + ruleArg);
1754
        }
1755
      }
1756
 
1757
      var rule = styleRule.join('|');
1758
      if (rule != '') {
1759
        parameters.push('style=' + rule);
1760
      }
1761
    }
1762
  }
1763
 
1764
  /** Polylines **/
1765
  function parseColor(color, opacity) {
1766
    if (color[0] === '#'){
1767
      color = color.replace('#', '0x');
1768
 
1769
      if (opacity) {
1770
        opacity = parseFloat(opacity);
1771
        opacity = Math.min(1, Math.max(opacity, 0));
1772
        if (opacity === 0) {
1773
          return '0x00000000';
1774
        }
1775
        opacity = (opacity * 255).toString(16);
1776
        if (opacity.length === 1) {
1777
          opacity += opacity;
1778
        }
1779
 
1780
        color = color.slice(0,8) + opacity;
1781
      }
1782
    }
1783
    return color;
1784
  }
1785
 
1786
  if (polyline) {
1787
    data = polyline;
1788
    polyline = [];
1789
 
1790
    if (data.strokeWeight) {
1791
      polyline.push('weight:' + parseInt(data.strokeWeight, 10));
1792
    }
1793
 
1794
    if (data.strokeColor) {
1795
      var color = parseColor(data.strokeColor, data.strokeOpacity);
1796
      polyline.push('color:' + color);
1797
    }
1798
 
1799
    if (data.fillColor) {
1800
      var fillcolor = parseColor(data.fillColor, data.fillOpacity);
1801
      polyline.push('fillcolor:' + fillcolor);
1802
    }
1803
 
1804
    var path = data.path;
1805
    if (path.join) {
1806
      for (var j=0, pos; pos=path[j]; j++) {
1807
        polyline.push(pos.join(','));
1808
      }
1809
    }
1810
    else {
1811
      polyline.push('enc:' + path);
1812
    }
1813
 
1814
    polyline = polyline.join('|');
1815
    parameters.push('path=' + encodeURI(polyline));
1816
  }
1817
 
1818
  /** Retina support **/
1819
  var dpi = window.devicePixelRatio || 1;
1820
  parameters.push('scale=' + dpi);
1821
 
1822
  parameters = parameters.join('&');
1823
  return static_root + parameters;
1824
};
1825
 
1826
GMaps.prototype.addMapType = function(mapTypeId, options) {
1827
  if (options.hasOwnProperty("getTileUrl") && typeof(options["getTileUrl"]) == "function") {
1828
    options.tileSize = options.tileSize || new google.maps.Size(256, 256);
1829
 
1830
    var mapType = new google.maps.ImageMapType(options);
1831
 
1832
    this.map.mapTypes.set(mapTypeId, mapType);
1833
  }
1834
  else {
1835
    throw "'getTileUrl' function required.";
1836
  }
1837
};
1838
 
1839
GMaps.prototype.addOverlayMapType = function(options) {
1840
  if (options.hasOwnProperty("getTile") && typeof(options["getTile"]) == "function") {
1841
    var overlayMapTypeIndex = options.index;
1842
 
1843
    delete options.index;
1844
 
1845
    this.map.overlayMapTypes.insertAt(overlayMapTypeIndex, options);
1846
  }
1847
  else {
1848
    throw "'getTile' function required.";
1849
  }
1850
};
1851
 
1852
GMaps.prototype.removeOverlayMapType = function(overlayMapTypeIndex) {
1853
  this.map.overlayMapTypes.removeAt(overlayMapTypeIndex);
1854
};
1855
 
1856
GMaps.prototype.addStyle = function(options) {
1857
  var styledMapType = new google.maps.StyledMapType(options.styles, { name: options.styledMapName });
1858
 
1859
  this.map.mapTypes.set(options.mapTypeId, styledMapType);
1860
};
1861
 
1862
GMaps.prototype.setStyle = function(mapTypeId) {
1863
  this.map.setMapTypeId(mapTypeId);
1864
};
1865
 
1866
GMaps.prototype.createPanorama = function(streetview_options) {
1867
  if (!streetview_options.hasOwnProperty('lat') || !streetview_options.hasOwnProperty('lng')) {
1868
    streetview_options.lat = this.getCenter().lat();
1869
    streetview_options.lng = this.getCenter().lng();
1870
  }
1871
 
1872
  this.panorama = GMaps.createPanorama(streetview_options);
1873
 
1874
  this.map.setStreetView(this.panorama);
1875
 
1876
  return this.panorama;
1877
};
1878
 
1879
GMaps.createPanorama = function(options) {
1880
  var el = getElementById(options.el, options.context);
1881
 
1882
  options.position = new google.maps.LatLng(options.lat, options.lng);
1883
 
1884
  delete options.el;
1885
  delete options.context;
1886
  delete options.lat;
1887
  delete options.lng;
1888
 
1889
  var streetview_events = ['closeclick', 'links_changed', 'pano_changed', 'position_changed', 'pov_changed', 'resize', 'visible_changed'],
1890
      streetview_options = extend_object({visible : true}, options);
1891
 
1892
  for (var i = 0; i < streetview_events.length; i++) {
1893
    delete streetview_options[streetview_events[i]];
1894
  }
1895
 
1896
  var panorama = new google.maps.StreetViewPanorama(el, streetview_options);
1897
 
1898
  for (var i = 0; i < streetview_events.length; i++) {
1899
    (function(object, name) {
1900
      if (options[name]) {
1901
        google.maps.event.addListener(object, name, function(){
1902
          options[name].apply(this);
1903
        });
1904
      }
1905
    })(panorama, streetview_events[i]);
1906
  }
1907
 
1908
  return panorama;
1909
};
1910
 
1911
GMaps.prototype.on = function(event_name, handler) {
1912
  return GMaps.on(event_name, this, handler);
1913
};
1914
 
1915
GMaps.prototype.off = function(event_name) {
1916
  GMaps.off(event_name, this);
1917
};
1918
 
1919
GMaps.custom_events = ['marker_added', 'marker_removed', 'polyline_added', 'polyline_removed', 'polygon_added', 'polygon_removed', 'geolocated', 'geolocation_failed'];
1920
 
1921
GMaps.on = function(event_name, object, handler) {
1922
  if (GMaps.custom_events.indexOf(event_name) == -1) {
1923
    if(object instanceof GMaps) object = object.map;
1924
    return google.maps.event.addListener(object, event_name, handler);
1925
  }
1926
  else {
1927
    var registered_event = {
1928
      handler : handler,
1929
      eventName : event_name
1930
    };
1931
 
1932
    object.registered_events[event_name] = object.registered_events[event_name] || [];
1933
    object.registered_events[event_name].push(registered_event);
1934
 
1935
    return registered_event;
1936
  }
1937
};
1938
 
1939
GMaps.off = function(event_name, object) {
1940
  if (GMaps.custom_events.indexOf(event_name) == -1) {
1941
    if(object instanceof GMaps) object = object.map;
1942
    google.maps.event.clearListeners(object, event_name);
1943
  }
1944
  else {
1945
    object.registered_events[event_name] = [];
1946
  }
1947
};
1948
 
1949
GMaps.fire = function(event_name, object, scope) {
1950
  if (GMaps.custom_events.indexOf(event_name) == -1) {
1951
    google.maps.event.trigger(object, event_name, Array.prototype.slice.apply(arguments).slice(2));
1952
  }
1953
  else {
1954
    if(event_name in scope.registered_events) {
1955
      var firing_events = scope.registered_events[event_name];
1956
 
1957
      for(var i = 0; i < firing_events.length; i++) {
1958
        (function(handler, scope, object) {
1959
          handler.apply(scope, [object]);
1960
        })(firing_events[i]['handler'], scope, object);
1961
      }
1962
    }
1963
  }
1964
};
1965
 
1966
GMaps.geolocate = function(options) {
1967
  var complete_callback = options.always || options.complete;
1968
 
1969
  if (navigator.geolocation) {
1970
    navigator.geolocation.getCurrentPosition(function(position) {
1971
      options.success(position);
1972
 
1973
      if (complete_callback) {
1974
        complete_callback();
1975
      }
1976
    }, function(error) {
1977
      options.error(error);
1978
 
1979
      if (complete_callback) {
1980
        complete_callback();
1981
      }
1982
    }, options.options);
1983
  }
1984
  else {
1985
    options.not_supported();
1986
 
1987
    if (complete_callback) {
1988
      complete_callback();
1989
    }
1990
  }
1991
};
1992
 
1993
GMaps.geocode = function(options) {
1994
  this.geocoder = new google.maps.Geocoder();
1995
  var callback = options.callback;
1996
  if (options.hasOwnProperty('lat') && options.hasOwnProperty('lng')) {
1997
    options.latLng = new google.maps.LatLng(options.lat, options.lng);
1998
  }
1999
 
2000
  delete options.lat;
2001
  delete options.lng;
2002
  delete options.callback;
2003
 
2004
  this.geocoder.geocode(options, function(results, status) {
2005
    callback(results, status);
2006
  });
2007
};
2008
 
2009
//==========================
2010
// Polygon containsLatLng
2011
// https://github.com/tparkin/Google-Maps-Point-in-Polygon
2012
// Poygon getBounds extension - google-maps-extensions
2013
// http://code.google.com/p/google-maps-extensions/source/browse/google.maps.Polygon.getBounds.js
2014
if (!google.maps.Polygon.prototype.getBounds) {
2015
  google.maps.Polygon.prototype.getBounds = function(latLng) {
2016
    var bounds = new google.maps.LatLngBounds();
2017
    var paths = this.getPaths();
2018
    var path;
2019
 
2020
    for (var p = 0; p < paths.getLength(); p++) {
2021
      path = paths.getAt(p);
2022
      for (var i = 0; i < path.getLength(); i++) {
2023
        bounds.extend(path.getAt(i));
2024
      }
2025
    }
2026
 
2027
    return bounds;
2028
  };
2029
}
2030
 
2031
if (!google.maps.Polygon.prototype.containsLatLng) {
2032
  // Polygon containsLatLng - method to determine if a latLng is within a polygon
2033
  google.maps.Polygon.prototype.containsLatLng = function(latLng) {
2034
    // Exclude points outside of bounds as there is no way they are in the poly
2035
    var bounds = this.getBounds();
2036
 
2037
    if (bounds !== null && !bounds.contains(latLng)) {
2038
      return false;
2039
    }
2040
 
2041
    // Raycast point in polygon method
2042
    var inPoly = false;
2043
 
2044
    var numPaths = this.getPaths().getLength();
2045
    for (var p = 0; p < numPaths; p++) {
2046
      var path = this.getPaths().getAt(p);
2047
      var numPoints = path.getLength();
2048
      var j = numPoints - 1;
2049
 
2050
      for (var i = 0; i < numPoints; i++) {
2051
        var vertex1 = path.getAt(i);
2052
        var vertex2 = path.getAt(j);
2053
 
2054
        if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng()) {
2055
          if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
2056
            inPoly = !inPoly;
2057
          }
2058
        }
2059
 
2060
        j = i;
2061
      }
2062
    }
2063
 
2064
    return inPoly;
2065
  };
2066
}
2067
 
2068
if (!google.maps.Circle.prototype.containsLatLng) {
2069
  google.maps.Circle.prototype.containsLatLng = function(latLng) {
2070
    if (google.maps.geometry) {
2071
      return google.maps.geometry.spherical.computeDistanceBetween(this.getCenter(), latLng) <= this.getRadius();
2072
    }
2073
    else {
2074
      return true;
2075
    }
2076
  };
2077
}
2078
 
2079
google.maps.LatLngBounds.prototype.containsLatLng = function(latLng) {
2080
  return this.contains(latLng);
2081
};
2082
 
2083
google.maps.Marker.prototype.setFences = function(fences) {
2084
  this.fences = fences;
2085
};
2086
 
2087
google.maps.Marker.prototype.addFence = function(fence) {
2088
  this.fences.push(fence);
2089
};
2090
 
2091
google.maps.Marker.prototype.getId = function() {
2092
  return this['__gm_id'];
2093
};
2094
 
2095
//==========================
2096
// Array indexOf
2097
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf
2098
if (!Array.prototype.indexOf) {
2099
  Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
2100
      "use strict";
2101
      if (this == null) {
2102
          throw new TypeError();
2103
      }
2104
      var t = Object(this);
2105
      var len = t.length >>> 0;
2106
      if (len === 0) {
2107
          return -1;
2108
      }
2109
      var n = 0;
2110
      if (arguments.length > 1) {
2111
          n = Number(arguments[1]);
2112
          if (n != n) { // shortcut for verifying if it's NaN
2113
              n = 0;
2114
          } else if (n != 0 && n != Infinity && n != -Infinity) {
2115
              n = (n > 0 || -1) * Math.floor(Math.abs(n));
2116
          }
2117
      }
2118
      if (n >= len) {
2119
          return -1;
2120
      }
2121
      var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
2122
      for (; k < len; k++) {
2123
          if (k in t && t[k] === searchElement) {
2124
              return k;
2125
          }
2126
      }
2127
      return -1;
2128
  }
2129
}
2130
 
2131
return GMaps;
2132
}));