gmap-rails 3.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/LICENSE +0 -0
- data/README.md +1 -0
- data/Rakefile +2 -0
- data/gemfile +3 -0
- data/gmap-rails.gemspec +19 -0
- data/lib/gmap-rails.rb +8 -0
- data/lib/gmap-rails/version.rb +5 -0
- data/vendor/assets/javascripts/jquery.gmap.js +872 -0
- metadata +89 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pkg
|
data/LICENSE
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://www.smashinglabs.pl/gmap
|
data/Rakefile
ADDED
data/gemfile
ADDED
data/gmap-rails.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/gmap-rails/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["bokmann"]
|
6
|
+
gem.email = ["dbock@codesherpas.com"]
|
7
|
+
gem.description = %q{gmap is a helpful little Javascript library by Sebastian Poręba. I'm just turning it into an asset gem for the rails asset pipeline.}
|
8
|
+
gem.summary = %q{A simple asset pipeline bundling of the gmap javascript library.}
|
9
|
+
gem.homepage = "https://github.com/bokmann/fullcalendar-rails"
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "gmap-rails"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = Gmap::Rails::VERSION
|
17
|
+
|
18
|
+
gem.add_development_dependency "rake"
|
19
|
+
end
|
data/lib/gmap-rails.rb
ADDED
@@ -0,0 +1,872 @@
|
|
1
|
+
/**
|
2
|
+
* jQuery gMap v3
|
3
|
+
*
|
4
|
+
* @url http://www.smashinglabs.pl/gmap
|
5
|
+
* @author Sebastian Poreba <sebastian.poreba@gmail.com>
|
6
|
+
* @version 3.3.2
|
7
|
+
* @date 16.03.2011
|
8
|
+
*/
|
9
|
+
/*jslint white: false, undef: true, regexp: true, plusplus: true, bitwise: true, newcap: true, strict: true, devel: true, maxerr: 50, indent: 4 */
|
10
|
+
/*global window, jQuery, $, google, $googlemaps */
|
11
|
+
(function ($) {
|
12
|
+
"use strict";
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Internals and experimental section
|
16
|
+
*/
|
17
|
+
var Cluster = function () {
|
18
|
+
this.markers = [];
|
19
|
+
this.mainMarker = false;
|
20
|
+
this.icon = "http://www.google.com/mapfiles/marker.png";
|
21
|
+
};
|
22
|
+
|
23
|
+
/**
|
24
|
+
* For iterating over all clusters to find if any is close enough to be merged with marker
|
25
|
+
*
|
26
|
+
* @param marker
|
27
|
+
* @param currentSize - calculated as viewport percentage (opts.clusterSize)
|
28
|
+
* @return bool
|
29
|
+
*/
|
30
|
+
Cluster.prototype.dist = function (marker) {
|
31
|
+
return Math.sqrt(Math.pow(this.markers[0].latitude - marker.latitude, 2) +
|
32
|
+
Math.pow(this.markers[0].longitude - marker.longitude, 2));
|
33
|
+
};
|
34
|
+
|
35
|
+
Cluster.prototype.setIcon = function (icon) {
|
36
|
+
this.icon = icon;
|
37
|
+
};
|
38
|
+
|
39
|
+
Cluster.prototype.addMarker = function (marker) {
|
40
|
+
this.markers[this.markers.length] = marker;
|
41
|
+
};
|
42
|
+
|
43
|
+
/**
|
44
|
+
* returns one marker if there is only one or
|
45
|
+
* returns special cloister marker if there are more
|
46
|
+
*/
|
47
|
+
Cluster.prototype.getMarker = function () {
|
48
|
+
if (this.mainmarker) {return this.mainmarker; }
|
49
|
+
var gicon, title;
|
50
|
+
if (this.markers.length > 1) {
|
51
|
+
gicon = new $googlemaps.MarkerImage("http://thydzik.com/thydzikGoogleMap/markerlink.php?text=" + this.markers.length + "&color=EF9D3F");
|
52
|
+
title = "cluster of " + this.markers.length + " markers";
|
53
|
+
} else {
|
54
|
+
gicon = new $googlemaps.MarkerImage(this.icon);
|
55
|
+
title = this.markers[0].title;
|
56
|
+
}
|
57
|
+
this.mainmarker = new $googlemaps.Marker({
|
58
|
+
position: new $googlemaps.LatLng(this.markers[0].latitude, this.markers[0].longitude),
|
59
|
+
icon: gicon,
|
60
|
+
title: title,
|
61
|
+
map: null
|
62
|
+
});
|
63
|
+
return this.mainmarker;
|
64
|
+
};
|
65
|
+
|
66
|
+
// global google maps objects
|
67
|
+
var $googlemaps = google.maps,
|
68
|
+
$geocoder = new $googlemaps.Geocoder(),
|
69
|
+
$markersToLoad = 0,
|
70
|
+
overQueryLimit = 0,
|
71
|
+
methods = {};
|
72
|
+
methods = {
|
73
|
+
/**
|
74
|
+
* initialisation/internals
|
75
|
+
*/
|
76
|
+
|
77
|
+
init: function (options) {
|
78
|
+
var k,
|
79
|
+
// Build main options before element iteration
|
80
|
+
opts = $.extend({}, $.fn.gMap.defaults, options);
|
81
|
+
|
82
|
+
// recover icon array
|
83
|
+
for (k in $.fn.gMap.defaults.icon) {
|
84
|
+
if(!opts.icon[k]) {
|
85
|
+
opts.icon[k] = $.fn.gMap.defaults.icon[k];
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
// Iterate through each element
|
90
|
+
return this.each(function () {
|
91
|
+
var $this = $(this),
|
92
|
+
center = methods._getMapCenter.apply($this, [opts]),
|
93
|
+
i, $data;
|
94
|
+
|
95
|
+
if (opts.zoom == "fit") {
|
96
|
+
opts.zoomFit = true;
|
97
|
+
opts.zoom = methods._autoZoom.apply($this, [opts]);
|
98
|
+
}
|
99
|
+
|
100
|
+
var mapOptions = {
|
101
|
+
zoom: opts.zoom,
|
102
|
+
center: center,
|
103
|
+
mapTypeControl: opts.mapTypeControl,
|
104
|
+
mapTypeControlOptions: {},
|
105
|
+
zoomControl: opts.zoomControl,
|
106
|
+
zoomControlOptions: {},
|
107
|
+
panControl : opts.panControl,
|
108
|
+
panControlOptions: {},
|
109
|
+
scaleControl : opts.scaleControl,
|
110
|
+
scaleControlOptions: {},
|
111
|
+
streetViewControl: opts.streetViewControl,
|
112
|
+
streetViewControlOptions: {},
|
113
|
+
mapTypeId: opts.maptype,
|
114
|
+
scrollwheel: opts.scrollwheel,
|
115
|
+
maxZoom: opts.maxZoom,
|
116
|
+
minZoom: opts.minZoom
|
117
|
+
};
|
118
|
+
if(opts.controlsPositions.mapType) {mapOptions.mapTypeControlOptions.position = opts.controlsPositions.mapType};
|
119
|
+
if(opts.controlsPositions.zoom) {mapOptions.zoomControlOptions.position = opts.controlsPositions.zoom};
|
120
|
+
if(opts.controlsPositions.pan) {mapOptions.panControlOptions.position = opts.controlsPositions.pan};
|
121
|
+
if(opts.controlsPositions.scale) {mapOptions.scaleControlOptions.position = opts.controlsPositions.scale};
|
122
|
+
if(opts.controlsPositions.streetView) {mapOptions.streetViewControlOptions.position = opts.controlsPositions.streetView};
|
123
|
+
|
124
|
+
mapOptions.mapTypeControlOptions.style = opts.controlsStyle.mapType;
|
125
|
+
mapOptions.zoomControlOptions.style = opts.controlsStyle.zoom;
|
126
|
+
|
127
|
+
// Create map and set initial options
|
128
|
+
var $gmap = new $googlemaps.Map(this, mapOptions);
|
129
|
+
|
130
|
+
if (opts.log) {console.log('map center is:'); }
|
131
|
+
if (opts.log) {console.log(center); }
|
132
|
+
|
133
|
+
// Create map and set initial options
|
134
|
+
|
135
|
+
$this.data("$gmap", $gmap);
|
136
|
+
|
137
|
+
$this.data('gmap', {
|
138
|
+
'opts': opts,
|
139
|
+
'gmap': $gmap,
|
140
|
+
'markers': [],
|
141
|
+
'markerKeys' : {},
|
142
|
+
'infoWindow': null,
|
143
|
+
'clusters': []
|
144
|
+
});
|
145
|
+
|
146
|
+
// Check for map controls
|
147
|
+
if (opts.controls.length !== 0) {
|
148
|
+
// Add custom map controls
|
149
|
+
for (i = 0; i < opts.controls.length; i += 1) {
|
150
|
+
$gmap.controls[opts.controls[i].pos].push(opts.controls[i].div);
|
151
|
+
}
|
152
|
+
}
|
153
|
+
|
154
|
+
if (opts.clustering.enabled) {
|
155
|
+
$data = $this.data('gmap');
|
156
|
+
(function(markers) {$data.markers = markers;}(opts.markers));
|
157
|
+
methods._renderCluster.apply($this, []);
|
158
|
+
|
159
|
+
$googlemaps.event.addListener($gmap, 'bounds_changed', function () {
|
160
|
+
methods._renderCluster.apply($this, []);
|
161
|
+
});
|
162
|
+
} else {
|
163
|
+
if (opts.markers.length !== 0) {
|
164
|
+
methods.addMarkers.apply($this, [opts.markers]);
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
methods._onComplete.apply($this, []);
|
169
|
+
});
|
170
|
+
},
|
171
|
+
|
172
|
+
|
173
|
+
_delayedMode: false,
|
174
|
+
|
175
|
+
/**
|
176
|
+
* Check every 100ms if all markers were loaded, then call onComplete
|
177
|
+
*/
|
178
|
+
_onComplete: function () {
|
179
|
+
var $data = this.data('gmap'),
|
180
|
+
that = this;
|
181
|
+
if ($markersToLoad !== 0) {
|
182
|
+
window.setTimeout(function () {methods._onComplete.apply(that, []); }, 100);
|
183
|
+
return;
|
184
|
+
}
|
185
|
+
if(methods._delayedMode) {
|
186
|
+
var center = methods._getMapCenter.apply(this, [$data.opts, true]);
|
187
|
+
methods._setMapCenter.apply(this, [center]);
|
188
|
+
if($data.opts.zoomFit) {
|
189
|
+
var zoom = methods._autoZoom.apply(this, [$data.opts, true]);
|
190
|
+
$data.gmap.setZoom(zoom);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
$data.opts.onComplete();
|
194
|
+
},
|
195
|
+
|
196
|
+
/**
|
197
|
+
* set map center when map is loaded (check every 100ms)
|
198
|
+
*/
|
199
|
+
_setMapCenter: function (center) {
|
200
|
+
var $data = this.data('gmap');
|
201
|
+
if ($data.opts.log) {console.log('delayed setMapCenter called'); }
|
202
|
+
if ($data.gmap !== undefined && $markersToLoad == 0) {
|
203
|
+
$data.gmap.setCenter(center);
|
204
|
+
} else {
|
205
|
+
var that = this;
|
206
|
+
window.setTimeout(function () {methods._setMapCenter.apply(that, [center]); }, 100);
|
207
|
+
}
|
208
|
+
},
|
209
|
+
|
210
|
+
/**
|
211
|
+
* calculate boundaries, optimised and independent from Google Maps
|
212
|
+
*/
|
213
|
+
_boundaries: null,
|
214
|
+
_getBoundaries: function (opts) {
|
215
|
+
// if(methods._boundaries) {return methods._boundaries; }
|
216
|
+
var markers = opts.markers, i;
|
217
|
+
var mostN = 1000,
|
218
|
+
mostE = -1000,
|
219
|
+
mostW = 1000,
|
220
|
+
mostS = -1000;
|
221
|
+
if(markers) {
|
222
|
+
for (i = 0; i < markers.length; i += 1) {
|
223
|
+
if(!markers[i].latitude || !markers[i].longitude) continue;
|
224
|
+
|
225
|
+
if(mostN > markers[i].latitude) {mostN = markers[i].latitude; }
|
226
|
+
if(mostE < markers[i].longitude) {mostE = markers[i].longitude; }
|
227
|
+
if(mostW > markers[i].longitude) {mostW = markers[i].longitude; }
|
228
|
+
if(mostS < markers[i].latitude) {mostS = markers[i].latitude; }
|
229
|
+
console.log(markers[i].latitude, markers[i].longitude, mostN, mostE, mostW, mostS);
|
230
|
+
}
|
231
|
+
methods._boundaries = {N: mostN, E: mostE, W: mostW, S: mostS};
|
232
|
+
}
|
233
|
+
|
234
|
+
if(mostN == -1000) methods._boundaries = {N: 0, E: 0, W: 0, S: 0};
|
235
|
+
|
236
|
+
return methods._boundaries;
|
237
|
+
},
|
238
|
+
|
239
|
+
_getBoundariesFromMarkers: function () {
|
240
|
+
|
241
|
+
var markers = this.data('gmap').markers, i;
|
242
|
+
var mostN = 1000,
|
243
|
+
mostE = -1000,
|
244
|
+
mostW = 1000,
|
245
|
+
mostS = -1000;
|
246
|
+
if(markers) {
|
247
|
+
for (i = 0; i < markers.length; i += 1) {
|
248
|
+
if(mostN > markers[i].getPosition().lat()) {mostN = markers[i].getPosition().lat(); }
|
249
|
+
if(mostE < markers[i].getPosition().lng()) {mostE = markers[i].getPosition().lng(); }
|
250
|
+
if(mostW > markers[i].getPosition().lng()) {mostW = markers[i].getPosition().lng(); }
|
251
|
+
if(mostS < markers[i].getPosition().lat()) {mostS = markers[i].getPosition().lat(); }
|
252
|
+
}
|
253
|
+
methods._boundaries = {N: mostN, E: mostE, W: mostW, S: mostS};
|
254
|
+
}
|
255
|
+
|
256
|
+
if(mostN == -1000) methods._boundaries = {N: 0, E: 0, W: 0, S: 0};
|
257
|
+
|
258
|
+
return methods._boundaries;
|
259
|
+
},
|
260
|
+
|
261
|
+
/**
|
262
|
+
* Priorities order:
|
263
|
+
* - latitude & longitude in options
|
264
|
+
* - address in options
|
265
|
+
* - latitude & longitude of first marker having it
|
266
|
+
* - address of first marker having it
|
267
|
+
* - failsafe (0,0)
|
268
|
+
*
|
269
|
+
* Note: with geocoding returned value is (0,0) and callback sets map center. It's not very nice nor efficient.
|
270
|
+
* It is quite good idea to use only first option
|
271
|
+
*/
|
272
|
+
_getMapCenter: function (opts, fromMarkers) {
|
273
|
+
// Create new object to geocode addresses
|
274
|
+
|
275
|
+
var center,
|
276
|
+
that = this, // 'that' scope fix in geocoding
|
277
|
+
i,
|
278
|
+
selectedToCenter,
|
279
|
+
most; //hoisting
|
280
|
+
|
281
|
+
if (opts.markers.length && (opts.latitude == "fit" || opts.longitude == "fit")) {
|
282
|
+
if(fromMarkers) most = methods._getBoundariesFromMarkers.apply(this);
|
283
|
+
else most = methods._getBoundaries(opts);
|
284
|
+
center = new $googlemaps.LatLng((most.N + most.S)/2, (most.E + most.W)/2);
|
285
|
+
console.log(fromMarkers, most, center);
|
286
|
+
return center;
|
287
|
+
}
|
288
|
+
|
289
|
+
if (opts.latitude && opts.longitude) {
|
290
|
+
// lat & lng available, return
|
291
|
+
center = new $googlemaps.LatLng(opts.latitude, opts.longitude);
|
292
|
+
return center;
|
293
|
+
} else {
|
294
|
+
center = new $googlemaps.LatLng(0, 0);
|
295
|
+
}
|
296
|
+
|
297
|
+
// Check for address to center on
|
298
|
+
if (opts.address) {
|
299
|
+
// Get coordinates for given address and center the map
|
300
|
+
$geocoder.geocode(
|
301
|
+
{address: opts.address},
|
302
|
+
function (result, status) {
|
303
|
+
if (status === google.maps.GeocoderStatus.OK) {
|
304
|
+
methods._setMapCenter.apply(that, [result[0].geometry.location]);
|
305
|
+
} else {
|
306
|
+
if (opts.log) {console.log("Geocode was not successful for the following reason: " + status); }
|
307
|
+
}
|
308
|
+
}
|
309
|
+
);
|
310
|
+
return center;
|
311
|
+
}
|
312
|
+
|
313
|
+
// Check for a marker to center on (if no coordinates given)
|
314
|
+
if (opts.markers.length > 0) {
|
315
|
+
selectedToCenter = null;
|
316
|
+
|
317
|
+
for (i = 0; i < opts.markers.length; i += 1) {
|
318
|
+
if(opts.markers[i].setCenter) {
|
319
|
+
selectedToCenter = opts.markers[i];
|
320
|
+
break;
|
321
|
+
}
|
322
|
+
}
|
323
|
+
|
324
|
+
if (selectedToCenter === null) {
|
325
|
+
for (i = 0; i < opts.markers.length; i += 1) {
|
326
|
+
if (opts.markers[i].latitude && opts.markers[i].longitude) {
|
327
|
+
selectedToCenter = opts.markers[i];
|
328
|
+
break;
|
329
|
+
}
|
330
|
+
if (opts.markers[i].address) {
|
331
|
+
selectedToCenter = opts.markers[i];
|
332
|
+
}
|
333
|
+
}
|
334
|
+
}
|
335
|
+
// failed to find any reasonable marker (it's quite impossible BTW)
|
336
|
+
if (selectedToCenter === null) {
|
337
|
+
return center;
|
338
|
+
}
|
339
|
+
|
340
|
+
if (selectedToCenter.latitude && selectedToCenter.longitude) {
|
341
|
+
return new $googlemaps.LatLng(selectedToCenter.latitude, selectedToCenter.longitude);
|
342
|
+
}
|
343
|
+
|
344
|
+
// Check if the marker has an address
|
345
|
+
if (selectedToCenter.address) {
|
346
|
+
// Get the coordinates for given marker address and center
|
347
|
+
$geocoder.geocode(
|
348
|
+
{address: selectedToCenter.address},
|
349
|
+
function (result, status) {
|
350
|
+
if (status === google.maps.GeocoderStatus.OK) {
|
351
|
+
methods._setMapCenter.apply(that, [result[0].geometry.location]);
|
352
|
+
} else {
|
353
|
+
if (opts.log) {console.log("Geocode was not successful for the following reason: " + status); }
|
354
|
+
}
|
355
|
+
}
|
356
|
+
);
|
357
|
+
}
|
358
|
+
}
|
359
|
+
return center;
|
360
|
+
},
|
361
|
+
|
362
|
+
|
363
|
+
/**
|
364
|
+
* clustering
|
365
|
+
*/
|
366
|
+
_renderCluster: function () {
|
367
|
+
var $data = this.data('gmap'),
|
368
|
+
markers = $data.markers,
|
369
|
+
clusters = $data.clusters,
|
370
|
+
opts = $data.opts,
|
371
|
+
i,
|
372
|
+
j,
|
373
|
+
viewport;
|
374
|
+
|
375
|
+
for (i = 0; i < clusters.length; i += 1) {
|
376
|
+
clusters[i].getMarker().setMap(null);
|
377
|
+
}
|
378
|
+
clusters.length = 0;
|
379
|
+
|
380
|
+
viewport = $data.gmap.getBounds();
|
381
|
+
|
382
|
+
if (!viewport) {
|
383
|
+
var that = this;
|
384
|
+
window.setTimeout(function () {methods._renderCluster.apply(that); }, 1000);
|
385
|
+
return;
|
386
|
+
}
|
387
|
+
|
388
|
+
var ne = viewport.getNorthEast(),
|
389
|
+
sw = viewport.getSouthWest(),
|
390
|
+
width = ne.lat() - sw.lat(),
|
391
|
+
// height = ne.lng() - sw.lng(), // unused
|
392
|
+
clusterable = [],
|
393
|
+
best,
|
394
|
+
bestDist,
|
395
|
+
maxSize = width * opts.clustering.clusterSize / 100,
|
396
|
+
dist,
|
397
|
+
newCluster;
|
398
|
+
|
399
|
+
for (i = 0; i < markers.length; i += 1) {
|
400
|
+
if (markers[i].latitude < ne.lat() &&
|
401
|
+
markers[i].latitude > sw.lat() &&
|
402
|
+
markers[i].longitude < ne.lng() &&
|
403
|
+
markers[i].longitude > sw.lng()) {
|
404
|
+
clusterable[clusterable.length] = markers[i];
|
405
|
+
}
|
406
|
+
}
|
407
|
+
|
408
|
+
if (opts.log) {console.log("number of markers " + clusterable.length + "/" + markers.length); }
|
409
|
+
if (opts.log) {console.log('cluster radius: ' + maxSize); }
|
410
|
+
|
411
|
+
for (i = 0; i < clusterable.length; i += 1) {
|
412
|
+
bestDist = 10000;
|
413
|
+
best = -1;
|
414
|
+
for (j = 0; j < clusters.length; j += 1) {
|
415
|
+
dist = clusters[j].dist(clusterable[i]);
|
416
|
+
if (dist < maxSize) {
|
417
|
+
bestDist = dist;
|
418
|
+
best = j;
|
419
|
+
if (opts.clustering.fastClustering) {break; }
|
420
|
+
}
|
421
|
+
}
|
422
|
+
if (best === -1) {
|
423
|
+
newCluster = new Cluster();
|
424
|
+
newCluster.addMarker(clusterable[i]);
|
425
|
+
clusters[clusters.length] = newCluster;
|
426
|
+
} else {
|
427
|
+
clusters[best].addMarker(clusterable[i]);
|
428
|
+
}
|
429
|
+
}
|
430
|
+
|
431
|
+
if (opts.log) {console.log("Total clusters in viewport: " + clusters.length); }
|
432
|
+
|
433
|
+
for (j = 0; j < clusters.length; j += 1) {
|
434
|
+
clusters[j].getMarker().setMap($data.gmap);
|
435
|
+
}
|
436
|
+
},
|
437
|
+
|
438
|
+
_processMarker: function (marker, gicon, gshadow, location) {
|
439
|
+
var $data = this.data('gmap'),
|
440
|
+
$gmap = $data.gmap,
|
441
|
+
opts = $data.opts,
|
442
|
+
gmarker,
|
443
|
+
markeropts;
|
444
|
+
|
445
|
+
if (location === undefined) {
|
446
|
+
location = new $googlemaps.LatLng(marker.latitude, marker.longitude);
|
447
|
+
}
|
448
|
+
|
449
|
+
if (!gicon) {
|
450
|
+
|
451
|
+
// Set icon properties from global options
|
452
|
+
var _gicon = {
|
453
|
+
image: opts.icon.image,
|
454
|
+
iconSize: new $googlemaps.Size(opts.icon.iconsize[0], opts.icon.iconsize[1]),
|
455
|
+
iconAnchor: new $googlemaps.Point(opts.icon.iconanchor[0], opts.icon.iconanchor[1]),
|
456
|
+
infoWindowAnchor: new $googlemaps.Size(opts.icon.infowindowanchor[0], opts.icon.infowindowanchor[1])
|
457
|
+
};
|
458
|
+
gicon = new $googlemaps.MarkerImage(_gicon.image, _gicon.iconSize, null, _gicon.iconAnchor);
|
459
|
+
}
|
460
|
+
|
461
|
+
if (!gshadow) {
|
462
|
+
var _gshadow = {
|
463
|
+
image: opts.icon.shadow,
|
464
|
+
iconSize: new $googlemaps.Size(opts.icon.shadowsize[0], opts.icon.shadowsize[1]),
|
465
|
+
anchor: (_gicon && _gicon.iconAnchor)?_gicon.iconAnchor:new $googlemaps.Point(opts.icon.iconanchor[0], opts.icon.iconanchor[1])
|
466
|
+
};
|
467
|
+
}
|
468
|
+
|
469
|
+
markeropts = {
|
470
|
+
position: location,
|
471
|
+
icon: gicon,
|
472
|
+
title: marker.title,
|
473
|
+
map: null,
|
474
|
+
draggable: ((marker.draggable === true) ? true : false)
|
475
|
+
};
|
476
|
+
|
477
|
+
if (!opts.clustering.enabled) {markeropts.map = $gmap; }
|
478
|
+
|
479
|
+
gmarker = new $googlemaps.Marker(markeropts);
|
480
|
+
gmarker.setShadow(gshadow);
|
481
|
+
$data.markers.push(gmarker);
|
482
|
+
|
483
|
+
if(marker.key) {$data.markerKeys[marker.key] = gmarker; }
|
484
|
+
|
485
|
+
// Set HTML and check if info window should be opened
|
486
|
+
var infoWindow;
|
487
|
+
if (marker.html) {
|
488
|
+
var infoContent = typeof(marker.html) === "string" ? opts.html_prepend + marker.html + opts.html_append : marker.html;
|
489
|
+
var infoOpts = {
|
490
|
+
content: infoContent,
|
491
|
+
pixelOffset: marker.infoWindowAnchor
|
492
|
+
};
|
493
|
+
|
494
|
+
if (opts.log) {console.log('setup popup with data'); }
|
495
|
+
if (opts.log) {console.log(infoOpts); }
|
496
|
+
infoWindow = new $googlemaps.InfoWindow(infoOpts);
|
497
|
+
|
498
|
+
$googlemaps.event.addListener(gmarker, 'click', function () {
|
499
|
+
if (opts.log) {console.log('opening popup ' + marker.html); }
|
500
|
+
if (opts.singleInfoWindow && $data.infoWindow) {$data.infoWindow.close(); }
|
501
|
+
infoWindow.open($gmap, gmarker);
|
502
|
+
$data.infoWindow = infoWindow;
|
503
|
+
});
|
504
|
+
}
|
505
|
+
if (marker.html && marker.popup) {
|
506
|
+
if (opts.log) {console.log('opening popup ' + marker.html); }
|
507
|
+
infoWindow.open($gmap, gmarker);
|
508
|
+
$data.infoWindow = infoWindow;
|
509
|
+
}
|
510
|
+
|
511
|
+
if (marker.onDragEnd){
|
512
|
+
$googlemaps.event.addListener(gmarker, 'dragend', function(event) {
|
513
|
+
if (opts.log) {console.log('drag end');}
|
514
|
+
marker.onDragEnd(event);
|
515
|
+
});
|
516
|
+
}
|
517
|
+
|
518
|
+
},
|
519
|
+
|
520
|
+
_geocodeMarker: function (marker, gicon, gshadow) {
|
521
|
+
var that = this;
|
522
|
+
$geocoder.geocode({'address': marker.address}, function (results, status) {
|
523
|
+
if (status === $googlemaps.GeocoderStatus.OK) {
|
524
|
+
$markersToLoad -= 1;
|
525
|
+
if (that.data('gmap').opts.log) {console.log("Geocode was successful with point: ", results[0].geometry.location); }
|
526
|
+
methods._processMarker.apply(that, [marker, gicon, gshadow, results[0].geometry.location]);
|
527
|
+
} else {
|
528
|
+
if(status === $googlemaps.GeocoderStatus.OVER_QUERY_LIMIT) {
|
529
|
+
if ((!that.data('gmap').opts.noAlerts) && (overQueryLimit === 0)) {alert('Error: too many geocoded addresses! Switching to 1 marker/s mode.'); }
|
530
|
+
|
531
|
+
overQueryLimit+=1000;
|
532
|
+
window.setTimeout(function() {
|
533
|
+
methods._geocodeMarker.apply(that, [marker, gicon, gshadow]);
|
534
|
+
}, overQueryLimit);
|
535
|
+
}
|
536
|
+
if (that.data('gmap').opts.log) {console.log("Geocode was not successful for the following reason: " + status); }
|
537
|
+
}
|
538
|
+
});
|
539
|
+
},
|
540
|
+
|
541
|
+
_autoZoom: function (options, fromMarkers){
|
542
|
+
var data = $(this).data('gmap'),
|
543
|
+
opts = $.extend({}, data?data.opts:{}, options),
|
544
|
+
i, boundaries, resX, resY, baseScale = 39135.758482;
|
545
|
+
if (opts.log) {console.log("autozooming map");}
|
546
|
+
|
547
|
+
if(fromMarkers) boundaries = methods._getBoundariesFromMarkers.apply(this);
|
548
|
+
else boundaries = methods._getBoundaries(opts);
|
549
|
+
|
550
|
+
resX = (boundaries.E - boundaries.W) * 111000 / this.width();
|
551
|
+
resY = (boundaries.S - boundaries.N) * 111000 / this.height();
|
552
|
+
|
553
|
+
for(i = 2; i < 20; i += 1) {
|
554
|
+
if (resX > baseScale || resY > baseScale) {
|
555
|
+
break;
|
556
|
+
}
|
557
|
+
baseScale = baseScale / 2;
|
558
|
+
}
|
559
|
+
return i - 2;
|
560
|
+
},
|
561
|
+
|
562
|
+
/**
|
563
|
+
* public methods section
|
564
|
+
*/
|
565
|
+
|
566
|
+
/**
|
567
|
+
* add array of markers
|
568
|
+
* @param markers
|
569
|
+
*/
|
570
|
+
addMarkers: function (markers){
|
571
|
+
var opts = this.data('gmap').opts;
|
572
|
+
|
573
|
+
if (markers.length !== 0) {
|
574
|
+
if (opts.log) {console.log("adding " + markers.length +" markers");}
|
575
|
+
// Loop through marker array
|
576
|
+
for (var i = 0; i < markers.length; i+= 1) {
|
577
|
+
methods.addMarker.apply(this,[markers[i]]);
|
578
|
+
}
|
579
|
+
}
|
580
|
+
},
|
581
|
+
|
582
|
+
/**
|
583
|
+
* add single marker
|
584
|
+
* @param marker
|
585
|
+
*/
|
586
|
+
addMarker: function (marker) {
|
587
|
+
var opts = this.data('gmap').opts;
|
588
|
+
|
589
|
+
if (opts.log) {console.log("putting marker at " + marker.latitude + ', ' + marker.longitude + " with address " + marker.address + " and html " + marker.html); }
|
590
|
+
|
591
|
+
// Create new icon
|
592
|
+
// Set icon properties from global options
|
593
|
+
var _gicon = {
|
594
|
+
image: opts.icon.image,
|
595
|
+
iconSize: new $googlemaps.Size(opts.icon.iconsize[0], opts.icon.iconsize[1]),
|
596
|
+
iconAnchor: new $googlemaps.Point(opts.icon.iconanchor[0], opts.icon.iconanchor[1]),
|
597
|
+
infoWindowAnchor: new $googlemaps.Size(opts.icon.infowindowanchor[0], opts.icon.infowindowanchor[1])
|
598
|
+
},
|
599
|
+
_gshadow = {
|
600
|
+
image: opts.icon.shadow,
|
601
|
+
iconSize: new $googlemaps.Size(opts.icon.shadowsize[0], opts.icon.shadowsize[1]),
|
602
|
+
anchor: new $googlemaps.Point(opts.icon.shadowanchor[0], opts.icon.shadowanchor[1])
|
603
|
+
};
|
604
|
+
|
605
|
+
// not very nice, but useful
|
606
|
+
marker.infoWindowAnchor = _gicon.infoWindowAnchor;
|
607
|
+
|
608
|
+
if (marker.icon) {
|
609
|
+
// Overwrite global options
|
610
|
+
if (marker.icon.image) { _gicon.image = marker.icon.image; }
|
611
|
+
if (marker.icon.iconsize) { _gicon.iconSize = new $googlemaps.Size(marker.icon.iconsize[0], marker.icon.iconsize[1]); }
|
612
|
+
|
613
|
+
if (marker.icon.iconanchor) { _gicon.iconAnchor = new $googlemaps.Point(marker.icon.iconanchor[0], marker.icon.iconanchor[1]); }
|
614
|
+
if (marker.icon.infowindowanchor) { _gicon.infoWindowAnchor = new $googlemaps.Size(marker.icon.infowindowanchor[0], marker.icon.infowindowanchor[1]); }
|
615
|
+
|
616
|
+
if (marker.icon.shadow) { _gshadow.image = marker.icon.shadow; }
|
617
|
+
if (marker.icon.shadowsize) { _gshadow.iconSize = new $googlemaps.Size(marker.icon.shadowsize[0], marker.icon.shadowsize[1]); }
|
618
|
+
|
619
|
+
if (marker.icon.shadowanchor) { _gshadow.anchor = new $googlemaps.Point(marker.icon.shadowanchor[0], marker.icon.shadowanchor[1]); }
|
620
|
+
}
|
621
|
+
|
622
|
+
var gicon = new $googlemaps.MarkerImage(_gicon.image, _gicon.iconSize, null, _gicon.iconAnchor);
|
623
|
+
var gshadow = new $googlemaps.MarkerImage( _gshadow.image,_gshadow.iconSize, null, _gshadow.anchor);
|
624
|
+
|
625
|
+
// Check if address is available
|
626
|
+
if (marker.address) {
|
627
|
+
// Check for reference to the marker's address
|
628
|
+
if (marker.html === '_address') {
|
629
|
+
marker.html = marker.address;
|
630
|
+
}
|
631
|
+
|
632
|
+
if (marker.title == '_address') {
|
633
|
+
marker.title = marker.address;
|
634
|
+
}
|
635
|
+
|
636
|
+
if (opts.log) {console.log('geocoding marker: ' + marker.address); }
|
637
|
+
// Get the point for given address
|
638
|
+
$markersToLoad += 1;
|
639
|
+
methods._delayedMode = true;
|
640
|
+
methods._geocodeMarker.apply(this, [marker, gicon, gshadow]);
|
641
|
+
} else {
|
642
|
+
// Check for reference to the marker's latitude/longitude
|
643
|
+
if (marker.html === '_latlng') {
|
644
|
+
marker.html = marker.latitude + ', ' + marker.longitude;
|
645
|
+
}
|
646
|
+
|
647
|
+
if (marker.title == '_latlng') {
|
648
|
+
marker.title = marker.latitude + ', ' + marker.longitude;
|
649
|
+
}
|
650
|
+
|
651
|
+
// Create marker
|
652
|
+
var gpoint = new $googlemaps.LatLng(marker.latitude, marker.longitude);
|
653
|
+
methods._processMarker.apply(this, [marker, gicon, gshadow, gpoint]);
|
654
|
+
}
|
655
|
+
},
|
656
|
+
|
657
|
+
/**
|
658
|
+
*
|
659
|
+
*/
|
660
|
+
removeAllMarkers: function () {
|
661
|
+
var markers = this.data('gmap').markers, i;
|
662
|
+
|
663
|
+
for (i = 0; i < markers.length; i += 1) {
|
664
|
+
markers[i].setMap(null);
|
665
|
+
delete markers[i];
|
666
|
+
}
|
667
|
+
markers.length = 0;
|
668
|
+
},
|
669
|
+
|
670
|
+
/**
|
671
|
+
* get marker by key, if set previously
|
672
|
+
* @param key
|
673
|
+
*/
|
674
|
+
getMarker: function (key) {
|
675
|
+
return this.data('gmap').markerKeys[key];
|
676
|
+
},
|
677
|
+
|
678
|
+
/**
|
679
|
+
* should be called if DOM element was resized
|
680
|
+
* @param nasty
|
681
|
+
*/
|
682
|
+
fixAfterResize: function (nasty) {
|
683
|
+
var data = this.data('gmap');
|
684
|
+
$googlemaps.event.trigger(data.gmap, 'resize');
|
685
|
+
|
686
|
+
if(nasty) {
|
687
|
+
data.gmap.panTo(new google.maps.LatLng(0,0));
|
688
|
+
}
|
689
|
+
data.gmap.panTo(this.gMap('_getMapCenter', data.opts));
|
690
|
+
},
|
691
|
+
|
692
|
+
/**
|
693
|
+
* change zoom, works with 'fit' option as well
|
694
|
+
* @param zoom
|
695
|
+
*/
|
696
|
+
setZoom: function (zoom, opts, fromMarkers) {
|
697
|
+
var $map = this.data('gmap').gmap;
|
698
|
+
if (zoom === "fit"){
|
699
|
+
zoom = methods._autoZoom.apply(this, [opts, fromMarkers]);
|
700
|
+
}
|
701
|
+
$map.setZoom(parseInt(zoom));
|
702
|
+
},
|
703
|
+
|
704
|
+
changeSettings: function (options) {
|
705
|
+
var data = this.data('gmap'),
|
706
|
+
markers = [], i;
|
707
|
+
for (i = 0; i < data.markers.length; i += 1) {
|
708
|
+
markers[i] = {
|
709
|
+
latitude: data.markers[i].getPosition().lat(),
|
710
|
+
longitude: data.markers[i].getPosition().lng()
|
711
|
+
}
|
712
|
+
}
|
713
|
+
options.markers = markers;
|
714
|
+
|
715
|
+
if(options.zoom) methods.setZoom.apply(this,[options.zoom, options]);
|
716
|
+
if(options.latitude || options.longitude) {
|
717
|
+
data.gmap.panTo(methods._getMapCenter.apply(this,[options]));
|
718
|
+
}
|
719
|
+
|
720
|
+
// add controls and maptype
|
721
|
+
},
|
722
|
+
|
723
|
+
mapclick: function(callback) {
|
724
|
+
google.maps.event.addListener(this.data('gmap').gmap, 'click', function(event) {
|
725
|
+
callback(event.latLng);
|
726
|
+
});
|
727
|
+
},
|
728
|
+
|
729
|
+
geocode: function(address, callback, errorCallback) {
|
730
|
+
$geocoder.geocode({'address': address}, function (results, status) {
|
731
|
+
if (status === $googlemaps.GeocoderStatus.OK) {
|
732
|
+
callback(results[0].geometry.location);
|
733
|
+
} else if(errorCallback) {
|
734
|
+
errorCallback(results, status);
|
735
|
+
}
|
736
|
+
});
|
737
|
+
},
|
738
|
+
|
739
|
+
getRoute: function (options) {
|
740
|
+
|
741
|
+
var $data = this.data('gmap'),
|
742
|
+
$gmap = $data.gmap,
|
743
|
+
$directionsDisplay = new $googlemaps.DirectionsRenderer(),
|
744
|
+
$directionsService = new $googlemaps.DirectionsService(),
|
745
|
+
$travelModes = { 'BYCAR': $googlemaps.DirectionsTravelMode.DRIVING, 'BYBICYCLE': $googlemaps.DirectionsTravelMode.BICYCLING, 'BYFOOT': $googlemaps.DirectionsTravelMode.WALKING },
|
746
|
+
$travelUnits = { 'MILES': $googlemaps.DirectionsUnitSystem.IMPERIAL, 'KM': $googlemaps.DirectionsUnitSystem.METRIC },
|
747
|
+
displayObj = null,
|
748
|
+
travelMode = null,
|
749
|
+
travelUnit = null,
|
750
|
+
unitSystem = null;
|
751
|
+
|
752
|
+
// look if there is an individual or otherwise a default object for this call to display route text informations
|
753
|
+
if(options.routeDisplay !== undefined){
|
754
|
+
displayObj = (options.routeDisplay instanceof jQuery) ? options.routeDisplay[0] : ((typeof options.routeDisplay == "string") ? $(options.routeDisplay)[0] : null);
|
755
|
+
} else if($data.opts.routeFinder.routeDisplay !== null){
|
756
|
+
displayObj = ($data.opts.routeFinder.routeDisplay instanceof jQuery) ? $data.opts.routeFinder.routeDisplay[0] : ((typeof $data.opts.routeFinder.routeDisplay == "string") ? $($data.opts.routeFinder.routeDisplay)[0] : null);
|
757
|
+
}
|
758
|
+
|
759
|
+
// set route renderer to map
|
760
|
+
$directionsDisplay.setMap($gmap);
|
761
|
+
if(displayObj !== null){
|
762
|
+
$directionsDisplay.setPanel(displayObj);
|
763
|
+
}
|
764
|
+
|
765
|
+
// get travel mode and unit
|
766
|
+
travelMode = ($travelModes[$data.opts.routeFinder.travelMode] !== undefined) ? $travelModes[$data.opts.routeFinder.travelMode] : $travelModes['BYCAR'];
|
767
|
+
travelUnit = ($travelUnits[$data.opts.routeFinder.travelUnit] !== undefined) ? $travelUnits[$data.opts.routeFinder.travelUnit] : $travelUnits['KM'];
|
768
|
+
|
769
|
+
// build request
|
770
|
+
var request = {
|
771
|
+
origin: options.from,
|
772
|
+
destination: options.to,
|
773
|
+
travelMode: travelMode,
|
774
|
+
unitSystem: travelUnit
|
775
|
+
};
|
776
|
+
|
777
|
+
// send request
|
778
|
+
$directionsService.route(request, function(result, status) {
|
779
|
+
// show the rout or otherwise show an error message in a defined container for route text information
|
780
|
+
if (status == $googlemaps.DirectionsStatus.OK) {
|
781
|
+
$directionsDisplay.setDirections(result);
|
782
|
+
} else if(displayObj !== null){
|
783
|
+
$(displayObj).html($data.opts.routeFinder.routeErrors[status]);
|
784
|
+
}
|
785
|
+
});
|
786
|
+
return this;
|
787
|
+
}
|
788
|
+
};
|
789
|
+
|
790
|
+
|
791
|
+
// Main plugin function
|
792
|
+
$.fn.gMap = function (method) {
|
793
|
+
// Method calling logic
|
794
|
+
if (methods[method]) {
|
795
|
+
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
796
|
+
} else if (typeof method === 'object' || !method) {
|
797
|
+
return methods.init.apply(this, arguments);
|
798
|
+
} else {
|
799
|
+
$.error('Method ' + method + ' does not exist on jQuery.gmap');
|
800
|
+
}
|
801
|
+
};
|
802
|
+
|
803
|
+
// Default settings
|
804
|
+
$.fn.gMap.defaults = {
|
805
|
+
log: false,
|
806
|
+
address: '',
|
807
|
+
latitude: null,
|
808
|
+
longitude: null,
|
809
|
+
zoom: 3,
|
810
|
+
maxZoom: null,
|
811
|
+
minZoom: null,
|
812
|
+
markers: [],
|
813
|
+
controls: {},
|
814
|
+
scrollwheel: true,
|
815
|
+
maptype: google.maps.MapTypeId.ROADMAP,
|
816
|
+
|
817
|
+
mapTypeControl: true,
|
818
|
+
zoomControl: true,
|
819
|
+
panControl: false,
|
820
|
+
scaleControl: false,
|
821
|
+
streetViewControl: true,
|
822
|
+
|
823
|
+
controlsPositions: {
|
824
|
+
mapType: null,
|
825
|
+
zoom: null,
|
826
|
+
pan: null,
|
827
|
+
scale: null,
|
828
|
+
streetView: null
|
829
|
+
},
|
830
|
+
controlsStyle: {
|
831
|
+
mapType: google.maps.MapTypeControlStyle.DEFAULT,
|
832
|
+
zoom: google.maps.ZoomControlStyle.DEFAULT
|
833
|
+
},
|
834
|
+
|
835
|
+
singleInfoWindow: true,
|
836
|
+
|
837
|
+
html_prepend: '<div class="gmap_marker">',
|
838
|
+
html_append: '</div>',
|
839
|
+
icon: {
|
840
|
+
image: "http://www.google.com/mapfiles/marker.png",
|
841
|
+
iconsize: [20, 34],
|
842
|
+
iconanchor: [9, 34],
|
843
|
+
infowindowanchor: [9, 2],
|
844
|
+
shadow: "http://www.google.com/mapfiles/shadow50.png",
|
845
|
+
shadowsize: [37, 34],
|
846
|
+
shadowanchor: [9, 34]
|
847
|
+
},
|
848
|
+
|
849
|
+
onComplete: function () {},
|
850
|
+
|
851
|
+
routeFinder: {
|
852
|
+
travelMode: 'BYCAR',
|
853
|
+
travelUnit: 'KM',
|
854
|
+
routeDisplay: null,
|
855
|
+
routeErrors: {
|
856
|
+
'INVALID_REQUEST': 'The provided request is invalid.',
|
857
|
+
'NOT_FOUND': 'One or more of the given addresses could not be found.',
|
858
|
+
'OVER_QUERY_LIMIT': 'A temporary error occured. Please try again in a few minutes.',
|
859
|
+
'REQUEST_DENIED': 'An error occured. Please contact us.',
|
860
|
+
'UNKNOWN_ERROR': 'An unknown error occured. Please try again.',
|
861
|
+
'ZERO_RESULTS': 'No route could be found within the given addresses.'
|
862
|
+
}
|
863
|
+
},
|
864
|
+
|
865
|
+
clustering: {
|
866
|
+
enabled: false,
|
867
|
+
fastClustering: false,
|
868
|
+
clusterCount: 10,
|
869
|
+
clusterSize: 40 //radius as % of viewport width
|
870
|
+
}
|
871
|
+
};
|
872
|
+
}(jQuery));
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gmap-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 15
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 3
|
8
|
+
- 3
|
9
|
+
- 2
|
10
|
+
version: 3.3.2
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- bokmann
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-09-07 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rake
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: "gmap is a helpful little Javascript library by Sebastian Por\xC4\x99ba. I'm just turning it into an asset gem for the rails asset pipeline."
|
36
|
+
email:
|
37
|
+
- dbock@codesherpas.com
|
38
|
+
executables: []
|
39
|
+
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- LICENSE
|
47
|
+
- README.md
|
48
|
+
- Rakefile
|
49
|
+
- gemfile
|
50
|
+
- gmap-rails.gemspec
|
51
|
+
- lib/gmap-rails.rb
|
52
|
+
- lib/gmap-rails/version.rb
|
53
|
+
- vendor/assets/javascripts/jquery.gmap.js
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: https://github.com/bokmann/fullcalendar-rails
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 3
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.6.2
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: A simple asset pipeline bundling of the gmap javascript library.
|
88
|
+
test_files: []
|
89
|
+
|