refinerycms-location_explorer 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/app/assets/javascripts/refinery/location_explorer/locations_map.coffee +43 -0
  2. data/app/assets/javascripts/refinery/location_explorer/map_picker.coffee +28 -0
  3. data/app/assets/javascripts/refinery/location_explorer/vendor/gmaps.js +1091 -0
  4. data/app/assets/stylesheets/refinery/location_explorer.css.scss +70 -0
  5. data/app/assets/stylesheets/refinery/location_explorer/map_picker.css.scss +26 -0
  6. data/app/controllers/refinery/location_explorer/admin/locations_controller.rb +12 -0
  7. data/app/controllers/refinery/location_explorer/locations_controller.rb +44 -0
  8. data/app/models/refinery/location_explorer/location.rb +41 -0
  9. data/app/models/refinery/location_explorer/owner_decorator.rb +46 -0
  10. data/app/views/refinery/location_explorer/admin/locations/_actions.html.erb +25 -0
  11. data/app/views/refinery/location_explorer/admin/locations/_form.html.erb +27 -0
  12. data/app/views/refinery/location_explorer/admin/locations/_location.html.erb +20 -0
  13. data/app/views/refinery/location_explorer/admin/locations/_locations.html.erb +2 -0
  14. data/app/views/refinery/location_explorer/admin/locations/_map.html.erb +29 -0
  15. data/app/views/refinery/location_explorer/admin/locations/_records.html.erb +18 -0
  16. data/app/views/refinery/location_explorer/admin/locations/_sortable_list.html.erb +5 -0
  17. data/app/views/refinery/location_explorer/admin/locations/edit.html.erb +1 -0
  18. data/app/views/refinery/location_explorer/admin/locations/index.html.erb +7 -0
  19. data/app/views/refinery/location_explorer/admin/locations/new.html.erb +1 -0
  20. data/app/views/refinery/location_explorer/locations/index.html.haml +30 -0
  21. data/app/views/refinery/location_explorer/locations/show.html.haml +16 -0
  22. data/config/locales/en.yml +30 -0
  23. data/config/locales/es.yml +31 -0
  24. data/config/locales/fr.yml +30 -0
  25. data/config/locales/nb.yml +30 -0
  26. data/config/locales/nl.yml +30 -0
  27. data/config/routes.rb +17 -0
  28. data/db/migrate/1_create_location_explorer_locations.rb +33 -0
  29. data/db/seeds.rb +25 -0
  30. data/lib/generators/refinery/location_explorer_generator.rb +23 -0
  31. data/lib/generators/refinery/templates/config/initializers/refinery/location_explorer.rb.erb +4 -0
  32. data/lib/refinery/location_explorer.rb +22 -0
  33. data/lib/refinery/location_explorer/configuration.rb +9 -0
  34. data/lib/refinery/location_explorer/engine.rb +27 -0
  35. data/lib/refinerycms-location_explorer.rb +3 -0
  36. data/lib/tasks/refinery/locations.rake +13 -0
  37. data/readme.md +51 -0
  38. metadata +148 -0
@@ -0,0 +1,43 @@
1
+ window.Application ||= {}
2
+
3
+ class Application.LocationsMap
4
+ constructor: (container_id, center, options = {}) ->
5
+ @map = new GMaps {
6
+ div: container_id,
7
+ zoom: options.zoom || 16,
8
+ mapType: 'Satellite'
9
+ lat: center[0],
10
+ lng: center[1]
11
+ }
12
+
13
+ updateLocation: (location, e) =>
14
+ $('#location_preview').show()
15
+ $('#location_preview .location_name').text(location['name'])
16
+ $('#location_preview .description_preview').text(location['description_preview'])
17
+ $('#location_preview .more_details').attr('href', location['detail_url'])
18
+ if location['preview_image_url']
19
+ $('#location_preview .image_container').html("<img src=\"#{location['preview_image_url']}\" class=\"location_image\"/>")
20
+ else
21
+ $('#location_preview .image_container').html("")
22
+
23
+ addLocations: (locations) ->
24
+ @locations = locations
25
+ for location in @locations
26
+ this.addLocation location
27
+
28
+ addLocation: (location) ->
29
+ pinColor = location['colour'] || "FE7569"
30
+ pinImage = new google.maps.MarkerImage("http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColor,
31
+ new google.maps.Size(21, 34),
32
+ new google.maps.Point(0,0),
33
+ new google.maps.Point(10, 34))
34
+
35
+ @map.addMarker {
36
+ lat: location['latitude'],
37
+ lng: location['longitude'],
38
+ icon: pinImage,
39
+ title: location['name'],
40
+ infoWindow: {content: location['name']}
41
+ click: (e)=>
42
+ this.updateLocation(location, e)
43
+ }
@@ -0,0 +1,28 @@
1
+ window.Application ||= {}
2
+
3
+ class Application.MapPicker
4
+ constructor: (container_id, center, initial_point) ->
5
+ @map = new GMaps {
6
+ div: container_id,
7
+ zoom: 16,
8
+ mapType: 'Satellite'
9
+ lat: center[0],
10
+ lng: center[1]
11
+ }
12
+ this.setPoint initial_point if initial_point
13
+ google.maps.event.addListener @map.map, 'click', this.pickPoint
14
+
15
+ pickPoint: (e) =>
16
+ $('#location_latitude').val e.latLng.lat()
17
+ $('#location_longitude').val e.latLng.lng()
18
+ point = [e.latLng.lat(), e.latLng.lng()]
19
+ this.setPoint point
20
+
21
+ setPoint: (point) ->
22
+ @map.removeMarkers()
23
+ @map.addMarker({
24
+ lat: point[0],
25
+ lng: point[1],
26
+ title: 'Selected point'
27
+ })
28
+
@@ -0,0 +1,1091 @@
1
+ /*!
2
+ * GMaps.js
3
+ * http://hpneo.github.com/gmaps/
4
+ *
5
+ * Copyright 2012, Gustavo Leon
6
+ * Released under the MIT License.
7
+ */
8
+
9
+ var GMaps = (function($) {
10
+ "use strict";
11
+
12
+ var GMaps = function(options) {
13
+ var self = this;
14
+ var context_menu_style = 'position:absolute;display:none;min-width:100px;' +
15
+ 'background:white;list-style:none;padding:8px;box-shadow:2px 2px 6px #ccc';
16
+ window.context_menu = {};
17
+
18
+ this.div = $(options.div)[0];
19
+ this.div.style.width = this.div.clientWidth || options.width;
20
+ this.div.style.height = this.div.clientHeight || options.height;
21
+
22
+ this.controls = [];
23
+ this.overlays = [];
24
+ this.layers = [];
25
+ this.markers = [];
26
+ this.polylines = [];
27
+ this.routes = [];
28
+ this.polygons = [];
29
+ this.infoWindow = null;
30
+ this.overlay_div = null;
31
+ this.zoom = options.zoom || 15;
32
+
33
+ //'Hybrid', 'Roadmap', 'Satellite' or 'Terrain'
34
+ var mapType;
35
+
36
+ if (options.mapType) {
37
+ mapType = google.maps.MapTypeId[options.mapType.toUpperCase()];
38
+ }
39
+ else {
40
+ mapType = google.maps.MapTypeId.ROADMAP;
41
+ }
42
+
43
+ var map_center = new google.maps.LatLng(options.lat, options.lng);
44
+
45
+ delete options.lat;
46
+ delete options.lng;
47
+ delete options.mapType;
48
+ delete options.width;
49
+ delete options.height;
50
+
51
+ var map_base_options = {
52
+ zoom: this.zoom,
53
+ center: map_center,
54
+ mapTypeId: mapType
55
+ };
56
+
57
+ var map_options = $.extend(map_base_options, options);
58
+
59
+ this.map = new google.maps.Map(this.div, map_options);
60
+
61
+ // Context menus
62
+ var buildContextMenuHTML = function(control, e) {
63
+ var html = '';
64
+ var options = window.context_menu[control];
65
+ for (var i in options){
66
+ if (options.hasOwnProperty(i)){
67
+ var option = options[i];
68
+ html += '<li><a id="' + control + '_' + i + '" href="#">' +
69
+ option.title + '</a></li>';
70
+ }
71
+ }
72
+ var $context_menu = $('#gmaps_context_menu');
73
+ $context_menu.html(html);
74
+ $context_menu.undelegate();
75
+ $context_menu.delegate('li a', 'click', function(ev) {
76
+ ev.preventDefault();
77
+ options[$(this).attr('id').replace(control + '_', '')].action.call(self, e);
78
+ self.hideContextMenu();
79
+ });
80
+
81
+ var left = $(self.div).offset().left + e.pixel.x - 15;
82
+ var top = $(self.div).offset().top + e.pixel.y - 15;
83
+ $context_menu.css({
84
+ left: left,
85
+ top: top
86
+ }).fadeIn(200);
87
+ };
88
+
89
+ var buildContextMenu = function(control, e) {
90
+ if (control === 'marker') {
91
+ e.pixel = {};
92
+ var overlay = new google.maps.OverlayView();
93
+ overlay.setMap(self.map);
94
+ overlay.draw = function() {
95
+ var projection = overlay.getProjection();
96
+ var position = e.marker.getPosition();
97
+ e.pixel = projection.fromLatLngToContainerPixel(position);
98
+
99
+ buildContextMenuHTML(control, e);
100
+ };
101
+ }
102
+ else {
103
+ buildContextMenuHTML(control, e);
104
+ }
105
+ };
106
+
107
+ this.setContextMenu = function(options) {
108
+ window.context_menu[options.control] = {};
109
+ var html = '<ul id="gmaps_context_menu" style="' + context_menu_style + '"></ul>';
110
+ for (var i in options.options){
111
+ if (options.options.hasOwnProperty(i)){
112
+ var option = options.options[i];
113
+ window.context_menu[options.control][option.name] = {
114
+ title: option.title,
115
+ action: option.action
116
+ };
117
+ }
118
+ }
119
+ $('body').append(html);
120
+ $('#gmaps_context_menu').mouseleave(function() {
121
+ $(this).delay(100).fadeOut(200);
122
+ });
123
+ };
124
+
125
+ this.hideContextMenu = function() {
126
+ $('#gmaps_context_menu').fadeOut(200);
127
+ };
128
+
129
+ //Events
130
+
131
+ var events_that_hide_context_menu = ['bounds_changed', 'center_changed', 'click', 'dblclick', 'drag', 'dragend', 'dragstart', 'idle', 'maptypeid_changed', 'projection_changed', 'resize', 'tilesloaded', 'zoom_changed'];
132
+ var events_that_doesnt_hide_context_menu = ['mousemove', 'mouseout', 'mouseover'];
133
+
134
+ for (var ev = 0; ev < events_that_hide_context_menu.length; ev++) {
135
+ (function(object, name) {
136
+ google.maps.event.addListener(object, name, function(e){
137
+ if (options[name])
138
+ options[name].apply(this, [e]);
139
+
140
+ self.hideContextMenu();
141
+ });
142
+ })(this.map, events_that_hide_context_menu[ev]);
143
+ }
144
+
145
+ for (var ev = 0; ev < events_that_doesnt_hide_context_menu.length; ev++) {
146
+ (function(object, name) {
147
+ google.maps.event.addListener(object, name, function(e){
148
+ if (options[name])
149
+ options[name].apply(this, [e]);
150
+ });
151
+ })(this.map, events_that_doesnt_hide_context_menu[ev]);
152
+ }
153
+
154
+ google.maps.event.addListener(this.map, 'rightclick', function(e) {
155
+ if (options.rightclick) {
156
+ options.rightclick.apply(this, [e]);
157
+ }
158
+
159
+ buildContextMenu('map', e);
160
+ });
161
+
162
+ this.refresh = function() {
163
+ google.maps.event.trigger(this.map, 'resize');
164
+ };
165
+
166
+ this.fitZoom = function() {
167
+ var latLngs = [];
168
+ var markers_length = this.markers.length;
169
+
170
+ for(var i=0; i < markers_length; i++) {
171
+ latLngs.push(this.markers[i].getPosition());
172
+ }
173
+
174
+ this.fitBounds(latLngs);
175
+ };
176
+
177
+ this.fitBounds = function(latLngs) {
178
+ var total = latLngs.length;
179
+ var bounds = new google.maps.LatLngBounds();
180
+
181
+ for(var i=0; i < total; i++) {
182
+ bounds.extend(latLngs[i]);
183
+ }
184
+
185
+ this.map.fitBounds(bounds);
186
+ };
187
+
188
+ // Map methods
189
+ this.setCenter = function(lat, lng, callback) {
190
+ this.map.panTo(new google.maps.LatLng(lat, lng));
191
+ if (callback) {
192
+ callback();
193
+ }
194
+ };
195
+
196
+ this.getCenter = function() {
197
+ return this.map.getCenter();
198
+ };
199
+
200
+ this.getDiv = function() {
201
+ return this.div;
202
+ };
203
+
204
+ this.setZoom = function(value) {
205
+ this.map.setZoom(value);
206
+ };
207
+
208
+ this.zoomIn = function(value) {
209
+ this.map.setZoom(this.map.getZoom() + value);
210
+ };
211
+
212
+ this.zoomOut = function(value) {
213
+ this.map.setZoom(this.map.getZoom() - value);
214
+ };
215
+
216
+ this.createControl = function(options) {
217
+ options.style.cursor = 'pointer';
218
+ options.style.fontFamily = 'Arial, sans-serif';
219
+ options.style.fontSize = '13px';
220
+ options.style.boxShadow = 'rgba(0, 0, 0, 0.398438) 0px 2px 4px';
221
+
222
+ var controlDiv = $('<div></div>');
223
+ controlDiv.css(options.style);
224
+ controlDiv.text(options.text);
225
+
226
+ var control = controlDiv[0];
227
+
228
+ for (var ev in options.events) {
229
+ (function(object, name) {
230
+ google.maps.event.addDomListener(object, name, function(){
231
+ options.events[name].apply(this, [this]);
232
+ });
233
+ })(control, ev);
234
+ }
235
+
236
+ control.index = 1;
237
+
238
+ return control;
239
+ };
240
+
241
+ this.addControl = function(options) {
242
+ var position = google.maps.ControlPosition[options.position.toUpperCase()];
243
+
244
+ delete options.position;
245
+
246
+ var control = this.createControl(options);
247
+ this.controls.push(control);
248
+ this.map.controls[position].push(control);
249
+
250
+ return control;
251
+ };
252
+
253
+ // Markers
254
+ this.createMarker = function(options) {
255
+ if (options.lat && options.lng) {
256
+ var self = this;
257
+ var details = options.details;
258
+ var fences = options.fences;
259
+ var outside = options.outside;
260
+ var base_options = {
261
+ position: new google.maps.LatLng(options.lat, options.lng),
262
+ map: null
263
+ };
264
+ delete options.lat;
265
+ delete options.lng;
266
+ delete options.fences;
267
+ delete options.outside;
268
+
269
+ var marker_options = $.extend(base_options, options);
270
+
271
+ var marker = new google.maps.Marker(marker_options);
272
+
273
+ marker.fences = fences;
274
+
275
+ if (options.infoWindow) {
276
+ marker.infoWindow = new google.maps.InfoWindow(options.infoWindow);
277
+
278
+ var info_window_events = ['closeclick', 'content_changed', 'domready', 'position_changed', 'zindex_changed'];
279
+
280
+ for (var ev = 0; ev < info_window_events.length; ev++) {
281
+ (function(object, name) {
282
+ google.maps.event.addListener(object, name, function(e){
283
+ if (options.infoWindow[name])
284
+ options.infoWindow[name].apply(this, [e]);
285
+ });
286
+ })(marker.infoWindow, info_window_events[ev]);
287
+ }
288
+ }
289
+
290
+ var marker_events = ['drag', 'dragstart', 'mouseout', 'mouseover', 'mouseup', 'position_changed'];
291
+
292
+ for (var ev = 0; ev < marker_events.length; ev++) {
293
+ (function(object, name) {
294
+ google.maps.event.addListener(object, name, function(){
295
+ if (options[name])
296
+ options[name].apply(this, [this]);
297
+ });
298
+ })(marker, marker_events[ev]);
299
+ }
300
+
301
+ google.maps.event.addListener(marker, 'click', function() {
302
+ this.details = details;
303
+
304
+ if (options.click) {
305
+ options.click.apply(this, [this]);
306
+ }
307
+
308
+ if (marker.infoWindow) {
309
+ self.hideInfoWindows();
310
+ marker.infoWindow.open(self.map, marker);
311
+ }
312
+ });
313
+
314
+ if (options.dragend || marker.fences) {
315
+ google.maps.event.addListener(marker, 'dragend', function() {
316
+ if (options.dragend) {
317
+ options.dragend.apply(this, [this]);
318
+ }
319
+ if (marker.fences) {
320
+ self.checkMarkerGeofence(marker, function(m, f) {
321
+ outside(m, f);
322
+ });
323
+ }
324
+ });
325
+ }
326
+
327
+ return marker;
328
+ }
329
+ else {
330
+ throw 'No latitude or longitude defined';
331
+ }
332
+ };
333
+
334
+ this.addMarker = function(options) {
335
+ if (options.lat && options.lng) {
336
+ var marker = this.createMarker(options);
337
+ marker.setMap(this.map);
338
+ this.markers.push(marker);
339
+
340
+ return marker;
341
+ }
342
+ else {
343
+ throw 'No latitude or longitude defined';
344
+ }
345
+ };
346
+
347
+ this.addMarkers = function(array) {
348
+ for (var i=0, marker; marker=array[i]; i++) {
349
+ this.addMarker(marker);
350
+ }
351
+ return this.markers;
352
+ };
353
+
354
+ this.hideInfoWindows = function() {
355
+ for (var i=0, marker; marker=this.markers[i]; i++){
356
+ if (marker.infoWindow){
357
+ marker.infoWindow.close();
358
+ }
359
+ }
360
+ };
361
+
362
+ this.removeMarkers = function() {
363
+ for (var i=0, marker; marker=this.markers[i]; i++){
364
+ marker.setMap(null);
365
+ }
366
+ this.markers = [];
367
+ };
368
+
369
+ // Overlays
370
+ this.drawOverlay = function(options) {
371
+ var overlay = new google.maps.OverlayView();
372
+ overlay.setMap(self.map);
373
+
374
+ overlay.onAdd = function() {
375
+ var div = document.createElement('div');
376
+ div.style.borderStyle = "none";
377
+ div.style.borderWidth = "0px";
378
+ div.style.position = "absolute";
379
+ div.innerHTML = options.content;
380
+
381
+ self.overlay_div = div;
382
+
383
+ var panes = this.getPanes();
384
+ if (!options.layer) {
385
+ options.layer = 'overlayLayer';
386
+ }
387
+ var overlayLayer = panes[options.layer];
388
+ overlayLayer.appendChild(div);
389
+ };
390
+
391
+ overlay.draw = function() {
392
+ var projection = this.getProjection();
393
+ var pixel = projection.fromLatLngToDivPixel(new google.maps.LatLng(options.lat, options.lng));
394
+
395
+ options.horizontalOffset = options.horizontalOffset || 0;
396
+ options.verticalOffset = options.verticalOffset || 0;
397
+
398
+ var div = self.overlay_div;
399
+ var content = div.children;
400
+
401
+ switch (options.verticalAlign) {
402
+ case 'top':
403
+ div.style.top = (pixel.y - $(content).height() + options.verticalOffset) + 'px';
404
+ break;
405
+ default:
406
+ case 'middle':
407
+ div.style.top = (pixel.y - ($(content).height() / 2) + options.verticalOffset) + 'px';
408
+ break;
409
+ case 'bottom':
410
+ div.style.top = (pixel.y + options.verticalOffset) + 'px';
411
+ break;
412
+ }
413
+
414
+ switch (options.horizontalAlign) {
415
+ case 'left':
416
+ div.style.left = (pixel.x - $(content).width() + options.horizontalOffset) + 'px';
417
+ break;
418
+ default:
419
+ case 'center':
420
+ div.style.left = (pixel.x - ($(content).width() / 2) + options.horizontalOffset) + 'px';
421
+ break;
422
+ case 'right':
423
+ div.style.left = (pixel.x + options.horizontalOffset) + 'px';
424
+ break;
425
+ }
426
+ };
427
+
428
+ overlay.onRemove = function() {
429
+ self.overlay_div.parentNode.removeChild(self.overlay_div);
430
+ self.overlay_div = null;
431
+ };
432
+ self.overlays.push(overlay);
433
+ return overlay;
434
+ };
435
+
436
+ this.removeOverlay = function(overlay) {
437
+ overlay.setMap(null);
438
+ };
439
+
440
+ this.removeOverlays = function() {
441
+ for (var i=0, item; item=self.overlays[i]; i++){
442
+ item.setMap(null);
443
+ }
444
+ self.overlays = [];
445
+ };
446
+
447
+ this.drawPolyline = function(options) {
448
+ var path = [];
449
+ var points = options.path;
450
+
451
+ if (points.length){
452
+ if (points[0][0] === undefined){
453
+ path = points;
454
+ }
455
+ else {
456
+ for (var i=0, latlng; latlng=points[i]; i++){
457
+ path.push(new google.maps.LatLng(latlng[0], latlng[1]));
458
+ }
459
+ }
460
+ }
461
+
462
+ var polyline = new google.maps.Polyline({
463
+ map: this.map,
464
+ path: path,
465
+ strokeColor: options.strokeColor,
466
+ strokeOpacity: options.strokeOpacity,
467
+ strokeWeight: options.strokeWeight
468
+ });
469
+
470
+ var polyline_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
471
+
472
+ for (var ev = 0; ev < polyline_events.length; ev++) {
473
+ (function(object, name) {
474
+ google.maps.event.addListener(object, name, function(e){
475
+ if (options[name])
476
+ options[name].apply(this, [e]);
477
+ });
478
+ })(polyline, polyline_events[ev]);
479
+ }
480
+
481
+ this.polylines.push(polyline);
482
+
483
+ return polyline;
484
+ };
485
+
486
+ this.drawCircle = function(options) {
487
+ options = $.extend({
488
+ map: this.map,
489
+ center: new google.maps.LatLng(options.lat, options.lng)
490
+ }, options);
491
+
492
+ delete options.lat;
493
+ delete options.lng;
494
+ var polygon = new google.maps.Circle(options);
495
+
496
+ var polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
497
+
498
+ for (var ev = 0; ev < polygon_events.length; ev++) {
499
+ (function(object, name) {
500
+ google.maps.event.addListener(object, name, function(e){
501
+ if (options[name])
502
+ options[name].apply(this, [e]);
503
+ });
504
+ })(polygon, polygon_events[ev]);
505
+ }
506
+
507
+ return polygon;
508
+ };
509
+
510
+ this.drawPolygon = function(options) {
511
+ options = $.extend({
512
+ map: this.map
513
+ }, options);
514
+
515
+ if($.isArray(options.paths)) {
516
+ if($.isArray(options.paths[0])) {
517
+ options.paths = $.map(options.paths, arrayToLatLng);
518
+ }
519
+ }
520
+
521
+ var polygon = new google.maps.Polygon(options);
522
+
523
+ var polygon_events = ['click', 'dblclick', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'rightclick'];
524
+
525
+ for (var ev = 0; ev < polygon_events.length; ev++) {
526
+ (function(object, name) {
527
+ google.maps.event.addListener(object, name, function(e){
528
+ if (options[name])
529
+ options[name].apply(this, [e]);
530
+ });
531
+ })(polygon, polygon_events[ev]);
532
+ }
533
+
534
+ this.polygons.push(polygon);
535
+
536
+ return polygon;
537
+
538
+ function arrayToLatLng(coords) {
539
+ return new google.maps.LatLng(coords[0], coords[1]);
540
+ }
541
+ };
542
+
543
+ this.getFromFusionTables = function(options) {
544
+ var events = options.events;
545
+
546
+ delete options.events;
547
+
548
+ var fusion_tables_options = options;
549
+
550
+ var layer = new google.maps.FusionTablesLayer(fusion_tables_options);
551
+
552
+ for (var ev in events) {
553
+ (function(object, name) {
554
+ google.maps.event.addListener(object, name, function(e){
555
+ events[name].apply(this, [e]);
556
+ });
557
+ })(layer, ev);
558
+ }
559
+
560
+ this.layers.push(layer);
561
+
562
+ return layer;
563
+ };
564
+
565
+ this.loadFromFusionTables = function(options) {
566
+ var layer = this.getFromFusionTables(options);
567
+ layer.setMap(this.map);
568
+
569
+ return layer;
570
+ };
571
+
572
+ this.getFromKML = function(options) {
573
+ var url = options.url;
574
+ var events = options.events;
575
+
576
+ delete options.url;
577
+ delete options.events;
578
+
579
+ var kml_options = options;
580
+
581
+ var layer = new google.maps.KmlLayer(url, kml_options);
582
+
583
+ for (var ev in events) {
584
+ (function(object, name) {
585
+ google.maps.event.addListener(object, name, function(e){
586
+ events[name].apply(this, [e]);
587
+ });
588
+ })(layer, ev);
589
+ }
590
+
591
+ this.layers.push(layer);
592
+
593
+ return layer;
594
+ };
595
+
596
+ this.loadFromKML = function(options) {
597
+ var layer = this.getFromKML(options);
598
+ layer.setMap(this.map);
599
+
600
+ return layer;
601
+ };
602
+
603
+ // Services
604
+ var travelMode, unitSystem;
605
+ this.getRoutes = function(options) {
606
+ switch (options.travelMode) {
607
+ case 'bicycling':
608
+ travelMode = google.maps.TravelMode.BICYCLING;
609
+ break;
610
+ case 'driving':
611
+ travelMode = google.maps.TravelMode.DRIVING;
612
+ break;
613
+ // case 'walking':
614
+ default:
615
+ travelMode = google.maps.TravelMode.WALKING;
616
+ break;
617
+ }
618
+
619
+ if (options.unitSystem === 'imperial') {
620
+ unitSystem = google.maps.UnitSystem.IMPERIAL;
621
+ }
622
+ else {
623
+ unitSystem = google.maps.UnitSystem.METRIC;
624
+ }
625
+
626
+ var base_options = {
627
+ avoidHighways: false,
628
+ avoidTolls: false,
629
+ optimizeWaypoints: false,
630
+ waypoints: []
631
+ };
632
+ var request_options = $.extend(base_options, options);
633
+ request_options.origin = new google.maps.LatLng(options.origin[0], options.origin[1]);
634
+ request_options.destination = new google.maps.LatLng(options.destination[0], options.destination[1]);
635
+ request_options.travelMode = travelMode;
636
+ request_options.unitSystem = unitSystem;
637
+
638
+ delete request_options.callback;
639
+
640
+ var self = this;
641
+ var service = new google.maps.DirectionsService();
642
+
643
+ service.route(request_options, function(result, status) {
644
+ if (status === google.maps.DirectionsStatus.OK) {
645
+ for (var r in result.routes) {
646
+ if (result.routes.hasOwnProperty(r)) {
647
+ self.routes.push(result.routes[r]);
648
+ }
649
+ }
650
+ }
651
+ if (options.callback) {
652
+ options.callback(self.routes);
653
+ }
654
+ });
655
+ };
656
+
657
+ this.removePolylines = function(){
658
+ var index;
659
+ for(index in this.polylines){
660
+ this.polylines[index].setMap(null);
661
+ }
662
+ this.polylines = [];
663
+ }
664
+
665
+ // Alias for the method "drawRoute"
666
+ this.cleanRoute = this.removePolylines;
667
+
668
+ this.drawRoute = function(options) {
669
+ var self = this;
670
+ this.getRoutes({
671
+ origin: options.origin,
672
+ destination: options.destination,
673
+ travelMode: options.travelMode,
674
+ callback: function(e) {
675
+ if (e.length > 0) {
676
+ self.drawPolyline({
677
+ path: e[e.length - 1].overview_path,
678
+ strokeColor: options.strokeColor,
679
+ strokeOpacity: options.strokeOpacity,
680
+ strokeWeight: options.strokeWeight
681
+ });
682
+ if (options.callback) {
683
+ options.callback(e[e.length - 1]);
684
+ }
685
+ }
686
+ }
687
+ });
688
+ };
689
+
690
+ this.travelRoute = function(options) {
691
+ if (options.origin && options.destination) {
692
+ this.getRoutes({
693
+ origin: options.origin,
694
+ destination: options.destination,
695
+ travelMode: options.travelMode,
696
+ callback: function(e) {
697
+ if (e.length > 0 && options.step) {
698
+ var route = e[e.length - 1];
699
+ if (route.legs.length > 0) {
700
+ var steps = route.legs[0].steps;
701
+ for (var i=0, step; step=steps[i]; i++) {
702
+ step.step_number = i;
703
+ options.step(step);
704
+ }
705
+ }
706
+ }
707
+ }
708
+ });
709
+ }
710
+ else if (options.route) {
711
+ if (options.route.legs.length > 0) {
712
+ var steps = options.route.legs[0].steps;
713
+ for (var i=0, step; step=steps[i]; i++) {
714
+ step.step_number = i;
715
+ options.step(step);
716
+ }
717
+ }
718
+ }
719
+ };
720
+
721
+ this.drawSteppedRoute = function(options) {
722
+ if (options.origin && options.destination) {
723
+ this.getRoutes({
724
+ origin: options.origin,
725
+ destination: options.destination,
726
+ travelMode: options.travelMode,
727
+ callback: function(e) {
728
+ if (e.length > 0 && options.step) {
729
+ var route = e[e.length - 1];
730
+ if (route.legs.length > 0) {
731
+ var steps = route.legs[0].steps;
732
+ for (var i=0, step; step=steps[i]; i++) {
733
+ step.step_number = i;
734
+ self.drawPolyline({
735
+ path: step.path,
736
+ strokeColor: options.strokeColor,
737
+ strokeOpacity: options.strokeOpacity,
738
+ strokeWeight: options.strokeWeight
739
+ });
740
+ options.step(step);
741
+ }
742
+ }
743
+ }
744
+ }
745
+ });
746
+ }
747
+ else if (options.route) {
748
+ if (options.route.legs.length > 0) {
749
+ var steps = options.route.legs[0].steps;
750
+ for (var i=0, step; step=steps[i]; i++) {
751
+ step.step_number = i;
752
+ self.drawPolyline({
753
+ path: step.path,
754
+ strokeColor: options.strokeColor,
755
+ strokeOpacity: options.strokeOpacity,
756
+ strokeWeight: options.strokeWeight
757
+ });
758
+ options.step(step);
759
+ }
760
+ }
761
+ }
762
+ };
763
+
764
+ // Geofence
765
+ this.checkGeofence = function(lat, lng, fence) {
766
+ return fence.containsLatLng(new google.maps.LatLng(lat, lng));
767
+ };
768
+
769
+ this.checkMarkerGeofence = function(marker, outside_callback) {
770
+ if (marker.fences) {
771
+ for (var i=0, fence; fence=marker.fences[i]; i++) {
772
+ var pos = marker.getPosition();
773
+ if (!self.checkGeofence(pos.lat(), pos.lng(), fence)) {
774
+ outside_callback(marker, fence);
775
+ }
776
+ }
777
+ }
778
+ };
779
+ };
780
+
781
+ GMaps.Route = function(options) {
782
+ this.map = options.map;
783
+ this.route = options.route;
784
+ this.step_count = 0;
785
+ this.steps = this.route.legs[0].steps;
786
+ this.steps_length = this.steps.length;
787
+
788
+ this.polyline = this.map.drawPolyline({
789
+ path: new google.maps.MVCArray(),
790
+ strokeColor: options.strokeColor,
791
+ strokeOpacity: options.strokeOpacity,
792
+ strokeWeight: options.strokeWeight
793
+ }).getPath();
794
+
795
+ this.back = function() {
796
+ if (this.step_count > 0) {
797
+ this.step_count--;
798
+ var path = this.route.legs[0].steps[this.step_count].path;
799
+ for (var p in path){
800
+ if (path.hasOwnProperty(p)){
801
+ this.polyline.pop();
802
+ }
803
+ }
804
+ }
805
+ };
806
+
807
+ this.forward = function() {
808
+ if (this.step_count < this.steps_length) {
809
+ var path = this.route.legs[0].steps[this.step_count].path;
810
+ for (var p in path){
811
+ if (path.hasOwnProperty(p)){
812
+ this.polyline.push(path[p]);
813
+ }
814
+ }
815
+ this.step_count++;
816
+ }
817
+ };
818
+ };
819
+
820
+ // Geolocation (Modern browsers only)
821
+ GMaps.geolocate = function(options) {
822
+ if (navigator.geolocation) {
823
+ navigator.geolocation.getCurrentPosition(function(position) {
824
+ options.success(position);
825
+ if (options.always) {
826
+ options.always();
827
+ }
828
+ }, function(error) {
829
+ options.error(error);
830
+ if (options.always) {
831
+ options.always();
832
+ }
833
+ }, options.options);
834
+ }
835
+ else {
836
+ options.not_supported();
837
+ if (options.always) {
838
+ options.always();
839
+ }
840
+ }
841
+ };
842
+
843
+ // Geocoding
844
+ GMaps.geocode = function(options) {
845
+ this.geocoder = new google.maps.Geocoder();
846
+ var callback = options.callback;
847
+ if (options.lat && options.lng) {
848
+ options.latLng = new google.maps.LatLng(options.lat, options.lng);
849
+ }
850
+
851
+ delete options.lat;
852
+ delete options.lng;
853
+ delete options.callback;
854
+ this.geocoder.geocode(options, function(results, status) {
855
+ callback(results, status);
856
+ });
857
+ };
858
+
859
+ // Static maps
860
+ GMaps.staticMapURL = function(options){
861
+ var parameters = [];
862
+ var data;
863
+
864
+ var static_root = 'http://maps.googleapis.com/maps/api/staticmap';
865
+ if (options.url){
866
+ static_root = options.url;
867
+ delete options.url;
868
+ }
869
+ static_root += '?';
870
+
871
+ var markers = options.markers;
872
+ delete options.markers;
873
+ if (!markers && options.marker){
874
+ markers = [options.marker];
875
+ delete options.marker;
876
+ }
877
+
878
+ var polyline = options.polyline;
879
+ delete options.polyline;
880
+
881
+ /** Map options **/
882
+ if (options.center){
883
+ parameters.push('center=' + options.center);
884
+ delete options.center;
885
+ }
886
+ else if (options.address){
887
+ parameters.push('center=' + options.address);
888
+ delete options.address;
889
+ }
890
+ else if (options.lat){
891
+ parameters.push(['center=', options.lat, ',', options.lng].join(''));
892
+ delete options.lat;
893
+ delete options.lng;
894
+ }
895
+ else if (options.visible){
896
+ var visible = encodeURI(options.visible.join('|'));
897
+ parameters.push('visible=' + visible);
898
+ }
899
+
900
+ var size = options.size;
901
+ if (size){
902
+ if (size.join){
903
+ size = size.join('x');
904
+ }
905
+ delete options.size;
906
+ }
907
+ else {
908
+ size = '630x300';
909
+ }
910
+ parameters.push('size=' + size);
911
+
912
+ if (!options.zoom){
913
+ options.zoom = 15;
914
+ }
915
+
916
+ var sensor = options.hasOwnProperty('sensor') ? !!options.sensor : true;
917
+ delete options.sensor;
918
+ parameters.push('sensor=' + sensor);
919
+
920
+ for (var param in options){
921
+ if (options.hasOwnProperty(param)){
922
+ parameters.push(param + '=' + options[param]);
923
+ }
924
+ }
925
+
926
+ /** Markers **/
927
+ if (markers){
928
+ var marker, loc;
929
+
930
+ for (var i=0; data=markers[i]; i++){
931
+ marker = [];
932
+
933
+ if (data.size && data.size !== 'normal'){
934
+ marker.push('size:' + data.size);
935
+ }
936
+ else if (data.icon){
937
+ marker.push('icon:' + encodeURI(data.icon));
938
+ }
939
+
940
+ if (data.color){
941
+ marker.push('color:' + data.color.replace('#', '0x'));
942
+ }
943
+
944
+ if (data.label){
945
+ marker.push('label:' + data.label[0].toUpperCase());
946
+ }
947
+
948
+ loc = (data.address ? data.address : data.lat + ',' + data.lng);
949
+
950
+ if (marker.length || i === 0){
951
+ marker.push(loc);
952
+ marker = marker.join('|');
953
+ parameters.push('markers=' + encodeURI(marker));
954
+ }
955
+ // New marker without styles
956
+ else {
957
+ marker = parameters.pop() + encodeURI('|' + loc);
958
+ parameters.push(marker);
959
+ }
960
+ }
961
+ }
962
+
963
+ /** Polylines **/
964
+ function parseColor(color, opacity){
965
+ if (color[0] === '#'){
966
+ color = color.replace('#', '0x');
967
+
968
+ if (opacity){
969
+ opacity = parseFloat(opacity);
970
+ opacity = Math.min(1, Math.max(opacity, 0));
971
+ if (opacity === 0){
972
+ return '0x00000000';
973
+ }
974
+ opacity = (opacity * 255).toString(16);
975
+ if (opacity.length === 1){
976
+ opacity += opacity;
977
+ }
978
+
979
+ color = color.slice(0,8) + opacity;
980
+ }
981
+ }
982
+ return color;
983
+ }
984
+
985
+ if (polyline){
986
+ data = polyline;
987
+ polyline = [];
988
+
989
+ if (data.strokeWeight){
990
+ polyline.push('weight:' + parseInt(data.strokeWeight, 10));
991
+ }
992
+
993
+ if (data.strokeColor){
994
+ var color = parseColor(data.strokeColor, data.strokeOpacity);
995
+ polyline.push('color:' + color);
996
+ }
997
+
998
+ if (data.fillColor){
999
+ var fillcolor = parseColor(data.fillColor, data.fillOpacity);
1000
+ polyline.push('fillcolor:' + fillcolor);
1001
+ }
1002
+
1003
+ var path = data.path;
1004
+ if (path.join){
1005
+ for (var j=0, pos; pos=path[j]; j++){
1006
+ polyline.push(pos.join(','));
1007
+ }
1008
+ }
1009
+ else {
1010
+ polyline.push('enc:' + path);
1011
+ }
1012
+
1013
+ polyline = polyline.join('|');
1014
+ parameters.push('path=' + encodeURI(polyline));
1015
+ }
1016
+
1017
+ parameters = parameters.join('&');
1018
+ return static_root + parameters;
1019
+ };
1020
+
1021
+ //==========================
1022
+ // Polygon containsLatLng
1023
+ // https://github.com/tparkin/Google-Maps-Point-in-Polygon
1024
+ // Poygon getBounds extension - google-maps-extensions
1025
+ // http://code.google.com/p/google-maps-extensions/source/browse/google.maps.Polygon.getBounds.js
1026
+ if (!google.maps.Polygon.prototype.getBounds) {
1027
+ google.maps.Polygon.prototype.getBounds = function(latLng) {
1028
+ var bounds = new google.maps.LatLngBounds();
1029
+ var paths = this.getPaths();
1030
+ var path;
1031
+
1032
+ for (var p = 0; p < paths.getLength(); p++) {
1033
+ path = paths.getAt(p);
1034
+ for (var i = 0; i < path.getLength(); i++) {
1035
+ bounds.extend(path.getAt(i));
1036
+ }
1037
+ }
1038
+
1039
+ return bounds;
1040
+ };
1041
+ }
1042
+
1043
+ // Polygon containsLatLng - method to determine if a latLng is within a polygon
1044
+ google.maps.Polygon.prototype.containsLatLng = function(latLng) {
1045
+ // Exclude points outside of bounds as there is no way they are in the poly
1046
+ var bounds = this.getBounds();
1047
+
1048
+ if (bounds !== null && !bounds.contains(latLng)) {
1049
+ return false;
1050
+ }
1051
+
1052
+ // Raycast point in polygon method
1053
+ var inPoly = false;
1054
+
1055
+ var numPaths = this.getPaths().getLength();
1056
+ for (var p = 0; p < numPaths; p++) {
1057
+ var path = this.getPaths().getAt(p);
1058
+ var numPoints = path.getLength();
1059
+ var j = numPoints - 1;
1060
+
1061
+ for (var i = 0; i < numPoints; i++) {
1062
+ var vertex1 = path.getAt(i);
1063
+ var vertex2 = path.getAt(j);
1064
+
1065
+ if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng()) {
1066
+ if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
1067
+ inPoly = !inPoly;
1068
+ }
1069
+ }
1070
+
1071
+ j = i;
1072
+ }
1073
+ }
1074
+
1075
+ return inPoly;
1076
+ };
1077
+
1078
+ google.maps.LatLngBounds.prototype.containsLatLng = function(latLng) {
1079
+ return this.contains(latLng);
1080
+ };
1081
+
1082
+ google.maps.Marker.prototype.setFences = function(fences) {
1083
+ this.fences = fences;
1084
+ };
1085
+
1086
+ google.maps.Marker.prototype.addFence = function(fence) {
1087
+ this.fences.push(fence);
1088
+ };
1089
+
1090
+ return GMaps;
1091
+ }(jQuery || $));