-
Andriy Podanenko authoredAndriy Podanenko authored
gmap.js 18.65 KiB
/**
* @file
* Drupal to Google Maps API bridge.
*/
/*global jQuery, Drupal, GLatLng, GSmallZoomControl, GLargeMapControl, GMap2 */
/*global GMapTypeControl, GSmallMapControl, G_HYBRID_MAP, G_NORMAL_MAP */
/*global G_PHYSICAL_MAP, G_SATELLITE_MAP, GHierarchicalMapTypeControl */
/*global GKeyboardHandler, GLatLngBounds, GMenuMapTypeControl, GEvent */
/*global GOverviewMapControl, GScaleControl, GUnload */
(function () { // BEGIN closure
var handlers = {};
var maps = {};
var ajaxoffset = 0;
Drupal.gmap = {
/**
* Retrieve a map object for use by a non-widget.
* Use this if you need to be able to fire events against a certain map
* which you have the mapid for.
* Be a good GMap citizen! Remember to send change()s after modifying variables!
*/
getMap: function (mapid) {
if (maps[mapid]) {
return maps[mapid];
}
else {
// Perhaps the user passed a widget id instead?
mapid = mapid.split('-').slice(1, -1).join('-');
if (maps[mapid]) {
return maps[mapid];
}
}
return false;
},
unloadMap: function (mapid) {
delete maps[mapid];
},
addHandler: function (handler, callback) {
if (!handlers[handler]) {
handlers[handler] = [];
}
handlers[handler].push(callback);
},
globalChange: function (name, userdata) {
for (var mapid in Drupal.settings.gmap) {
if (Drupal.settings.gmap.hasOwnProperty(mapid)) {
// Skip maps that are set up but not shown, etc.
if (maps[mapid]) {
maps[mapid].change(name, -1, userdata);
}
}
}
},
setup: function (settings) {
var obj = this;
var initcallback = function (mapid) {
return (function () {
maps[mapid].change("bootstrap_options", -1);
maps[mapid].change("boot", -1);
maps[mapid].change("init", -1);
// Send some changed events to fire up the rest of the initial settings..
maps[mapid].change("maptypechange", -1);
maps[mapid].change("controltypechange", -1);
maps[mapid].change("alignchange", -1);
// Set ready to put the event system into action.
maps[mapid].ready = true;
maps[mapid].change("ready", -1);
});
};
if (settings || (Drupal.settings && Drupal.settings.gmap)) {
var mapid = obj.id.split('-');
if (Drupal.settings['gmap_remap_widgets']) {
if (Drupal.settings['gmap_remap_widgets'][obj.id]) {
jQuery.each(Drupal.settings['gmap_remap_widgets'][obj.id].classes, function() {
jQuery(obj).addClass(this);
});
mapid = Drupal.settings['gmap_remap_widgets'][obj.id].id.split('-');
}
}
var instanceid = mapid.pop();
mapid.shift();
mapid = mapid.join('-');
var control = instanceid.replace(/\d+$/, '');
// Lazy init the map object.
if (!maps[mapid]) {
if (settings) {
maps[mapid] = new Drupal.gmap.map(settings);
}
else {
maps[mapid] = new Drupal.gmap.map(Drupal.settings.gmap[mapid]);
}
// Prepare the initialization callback.
var callback = initcallback(mapid);
setTimeout(callback, 0);
}
if (handlers[control]) {
for (var i = 0; i < handlers[control].length; i++) {
handlers[control][i].call(maps[mapid], obj);
}
}
else {
// Element with wrong class?
}
}
}
};
jQuery.fn.createGMap = function (settings, mapid) {
return this.each(function () {
if (!mapid) {
mapid = 'auto' + ajaxoffset + 'ajax';
ajaxoffset++;
}
settings.id = mapid;
jQuery(this)
.attr('id', 'gmap-' + mapid + '-gmap0')
.css('width', settings.width)
.css('height', settings.height)
.addClass('gmap-control')
.addClass('gmap-gmap')
.addClass('gmap')
.addClass('gmap-map')
.addClass('gmap-' + mapid + '-gmap')
.addClass('gmap-processed')
.each(function() {Drupal.gmap.setup.call(this, settings)});
});
};
})(); // END closure
Drupal.gmap.factory = {};
Drupal.gmap.map = function (v) {
this.vars = v;
this.map = undefined;
this.ready = false;
var _bindings = {};
/**
* Register interest in a change.
*/
this.bind = function (name, callback) {
if (!_bindings[name]) {
_bindings[name] = [];
}
return _bindings[name].push(callback) - 1;
};
/**
* Change notification.
* Interested parties can act on changes.
*/
this.change = function (name, id, userdata) {
var c;
if (_bindings[name]) {
for (c = 0; c < _bindings[name].length; c++) {
if (c !== id) {
_bindings[name][c](userdata);
}
}
}
if (name !== 'all') {
this.change('all', -1, name, userdata);
}
};
/**
* Deferred change notification.
* This will cause a change notification to be tacked on to the *end* of the event queue.
*/
this.deferChange = function (name, id, userdata) {
var obj = this;
// This will move the function call to the end of the event loop.
setTimeout(function () {
obj.change(name, id, userdata);
}, 0);
};
this.getMapTypeName = function(type) {
if (type == 'map' || type == 'roadmap') return 'Map';
if (type == 'hybrid') return 'Hybrid';
if (type == 'physical' || type == 'terrain') return 'Physical';
if (type == 'satellite') return 'Satellite';
};
this.getMapTypeId = function(type) {
if (type == 'Map' || type == 'Roadmap') return google.maps.MapTypeId.ROADMAP;
if (type == 'Hybrid') return google.maps.MapTypeId.HYBRID;
if (type == 'Physical' || type == 'Terrain') return google.maps.MapTypeId.TERRAIN;
if (type == 'Satellite') return google.maps.MapTypeId.SATELLITE;
};
};
////////////////////////////////////////
// Map widget //
////////////////////////////////////////
Drupal.gmap.addHandler('gmap', function (elem) {
var obj = this;
var _ib = {};
// Respond to incoming zooms
_ib.zoom = obj.bind("zoom", function (zoom) {
obj.map.setZoom(obj.vars.zoom);
});
// Respond to incoming moves
_ib.move = obj.bind("move", function () {
obj.map.panTo(new google.maps.LatLng(obj.vars.latitude, obj.vars.longitude));
});
// Respond to incoming width changes.
_ib.width = obj.bind("widthchange", function (w) {
obj.map.getDiv().style.width = w;
google.maps.event.trigger(obj.map);
});
// Send out outgoing width changes.
// N/A
// Respond to incoming height changes.
_ib.height = obj.bind("heightchange", function (h) {
obj.map.getDiv().style.height = h;
google.maps.event.trigger(obj.map);
});
// Send out outgoing height changes.
// N/A
// Respond to incoming control type changes.
_ib.ctc = obj.bind("controltypechange", function () {
if (obj.vars.controltype === 'Small') {
obj.map.setOptions({navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL}});
}
else if (obj.vars.controltype === 'Large') {
obj.map.setOptions({navigationControlOptions: {style: google.maps.NavigationControlStyle.ZOOM_PAN}});
}
else if (obj.vars.controltype === 'Android') {
obj.map.setOptions({navigationControlOptions: {style: google.maps.NavigationControlStyle.ANDROID}});
}
});
// Send out outgoing control type changes.
// N/A
// Respond to incoming map type changes.
_ib.mtc = obj.bind("maptypechange", function () {
obj.map.setMapTypeId(obj.getMapTypeId(obj.vars.maptype));
});
// Send out outgoing map type changes.
// N/A
obj.bind("bootstrap_options", function () {
// Bootup options.
var opts = {}; // Object literal google.maps.MapOptions
obj.opts = opts;
// Disable default UI for custom options
opts.disableDefaultUI = true;
// Set draggable property
if (obj.vars.behavior.nodrag) {
opts.draggable = false;
}
else if (obj.vars.behavior.nokeyboard) {
opts.keyboardShortcuts = false;
}
// Set default map type (set to road map if nothing selected)
switch (obj.vars.maptype) {
case 'Hybrid':
opts.mapTypeId = google.maps.MapTypeId.HYBRID;
break;
case 'Physical':
opts.mapTypeId = google.maps.MapTypeId.TERRAIN;
break;
case 'Satellite':
opts.mapTypeId = google.maps.MapTypeId.SATELLITE;
break;
case 'Map':
default:
opts.mapTypeId = google.maps.MapTypeId.ROADMAP;
break;
}
// Null out the enabled types.
opts.mapTypeIds = [];
if (obj.vars.baselayers.Map) {
opts.mapTypeIds.push(google.maps.MapTypeId.ROADMAP);
}
if (obj.vars.baselayers.Hybrid) {
opts.mapTypeIds.push(google.maps.MapTypeId.HYBRID);
}
if (obj.vars.baselayers.Physical) {
opts.mapTypeIds.push(google.maps.MapTypeId.TERRAIN);
}
if (obj.vars.baselayers.Satellite) {
opts.mapTypeIds.push(google.maps.MapTypeId.SATELLITE);
}
if (obj.vars.draggableCursor) {
opts.draggableCursor = obj.vars.draggableCursor;
}
if (obj.vars.draggingCursor) {
opts.draggingCursor = obj.vars.draggingCursor;
}
if (obj.vars.backgroundColor) {
opts.backgroundColor = obj.vars.backgroundColor;
}
// Map type control
opts.mapTypeControl = true;
opts.mapTypeControlOptions = {};
if (obj.vars.mtc === 'standard') {
opts.mapTypeControlOptions.style = google.maps.MapTypeControlStyle.DEFAULT;
}
else if (obj.vars.mtc === 'horiz') {
opts.mapTypeControlOptions.style = google.maps.MapTypeControlStyle.HORIZONTAL_BAR;
}
else if (obj.vars.mtc === 'menu') {
opts.mapTypeControlOptions.style = google.maps.MapTypeControlStyle.DROPDOWN_MENU;
}
// Navigation control type
if (obj.vars.controltype !== 'None') {
opts.navigationControl = true;
}
if (obj.vars.controltype === 'Small') {
opts.navigationControlOptions = {style: google.maps.NavigationControlStyle.SMALL};
}
else if (obj.vars.controltype === 'Large') {
opts.navigationControlOptions = {style: google.maps.NavigationControlStyle.ZOOM_PAN};
}
// Set scale control visibility
opts.scaleControl = obj.vars.behavior.scale;
// Scroll wheel control
if (obj.vars.behavior.nomousezoom) {
opts.scrollwheel = false;
}
// Disable double-click zoom
if (obj.vars.behavior.nocontzoom) {
opts.disableDoubleClickZoom = true;
}
});
obj.bind("boot", function () {
obj.map = new google.maps.Map(elem, obj.opts);
//console.log(obj.map);
});
obj.bind("init", function () {
var map = obj.map;
// Not implemented in API v3
// if (obj.vars.behavior.overview) {
// map.addControl(new GOverviewMapControl());
// }
// if (obj.vars.behavior.googlebar) {
// map.enableGoogleBar();
// }
if (obj.vars.extent) {
var c = obj.vars.extent;
var extent = new google.maps.LatLngBounds(new google.maps.LatLng(c[0][0], c[0][1]), new google.maps.LatLng(c[1][0], c[1][1]));
obj.vars.latitude = extent.getCenter().lat();
obj.vars.longitude = extent.getCenter().lng();
obj.vars.zoom = map.getBoundsZoomLevel(extent);
}
if (obj.vars.behavior.collapsehack) {
// Modify collapsable fieldsets to make maps check dom state when the resize handle
// is clicked. This may not necessarily be the correct thing to do in all themes,
// hence it being a behavior.
setTimeout(function () {
var r = function () {
google.maps.event.trigger(map);
map.setCenter(new google.maps.LatLng(obj.vars.latitude, obj.vars.longitude), obj.vars.zoom);
};
jQuery(elem).parents('fieldset.collapsible').children('legend').children('a').click(r);
jQuery('.vertical-tab-button', jQuery(elem).parents('.vertical-tabs')).children('a').click(r);
jQuery(window).bind('hashchange', r);
// Would be nice, but doesn't work.
//$(elem).parents('fieldset.collapsible').children('.fieldset-wrapper').scroll(r);
}, 0);
}
map.setCenter(new google.maps.LatLng(obj.vars.latitude, obj.vars.longitude));
map.setZoom(obj.vars.zoom);
// Send out outgoing zooms
google.maps.event.addListener(map, "zoom_changed", function () {
obj.vars.zoom = map.getZoom();
obj.change("zoom", _ib.zoom);
});
// Send out outgoing moves
google.maps.event.addListener(map, "center_changed", function () {
var coord = map.getCenter();
obj.vars.latitude = coord.lat();
obj.vars.longitude = coord.lng();
obj.change("move", _ib.move);
});
// Send out outgoing map type changes.
google.maps.event.addListener(map, "maptypeid_changed", function () {
// If the map isn't ready yet, ignore it.
if (obj.ready) {
obj.vars.maptype = obj.getMapTypeName(map.getMapTypeId());
obj.change("maptypechange", _ib.mtc);
}
});
/*
google.maps.event.addListener(map, 'click', function(event) {
alert(Drupal.gmap.getIcon("big blue", 0));
var marker = new google.maps.Marker({
position: event.latLng,
map: map
});
google.maps.event.addListener(marker, 'click', function() {
marker.setMap(null);
});
});
*/
});
});
////////////////////////////////////////
// Zoom widget //
////////////////////////////////////////
Drupal.gmap.addHandler('zoom', function (elem) {
var obj = this;
// Respond to incoming zooms
var binding = obj.bind("zoom", function () {
elem.value = obj.vars.zoom;
});
// Send out outgoing zooms
jQuery(elem).change(function () {
obj.vars.zoom = parseInt(elem.value, 10);
obj.change("zoom", binding);
});
});
////////////////////////////////////////
// Latitude widget //
////////////////////////////////////////
Drupal.gmap.addHandler('latitude', function (elem) {
// var obj = this;
// // Respond to incoming movements.
// var binding = obj.bind("move", function () {
// elem.value = '' + obj.vars.latitude;
// });
// // Send out outgoing movements.
// $(elem).change(function () {
// obj.vars.latitude = Number(this.value);
// obj.change("move", binding);
// });
});
////////////////////////////////////////
// Longitude widget //
////////////////////////////////////////
Drupal.gmap.addHandler('longitude', function (elem) {
// var obj = this;
// // Respond to incoming movements.
// var binding = obj.bind("move", function () {
// elem.value = '' + obj.vars.longitude;
// });
// // Send out outgoing movements.
// $(elem).change(function () {
// obj.vars.longitude = Number(this.value);
// obj.change("move", binding);
// });
});
////////////////////////////////////////
// Latlon widget //
////////////////////////////////////////
Drupal.gmap.addHandler('latlon', function (elem) {
var obj = this;
// Respond to incoming movements.
var binding = obj.bind("move", function () {
elem.value = '' + obj.vars.latitude + ',' + obj.vars.longitude;
});
// Send out outgoing movements.
jQuery(elem).change(function () {
var t = this.value.split(',');
obj.vars.latitude = Number(t[0]);
obj.vars.longitude = Number(t[1]);
obj.change("move", binding);
});
});
////////////////////////////////////////
// Maptype widget //
////////////////////////////////////////
Drupal.gmap.addHandler('maptype', function (elem) {
var obj = this;
// Respond to incoming movements.
var binding = obj.bind("maptypechange", function () {
elem.value = obj.vars.maptype;
});
// Send out outgoing movements.
jQuery(elem).change(function () {
obj.vars.maptype = elem.value;
obj.change("maptypechange", binding);
});
});
(function () { // BEGIN CLOSURE
var re = /([0-9.]+)\s*(em|ex|px|in|cm|mm|pt|pc|%)/;
var normalize = function (str) {
var ar;
if ((ar = re.exec(str.toLowerCase()))) {
return ar[1] + ar[2];
}
return null;
};
////////////////////////////////////////
// Width widget //
////////////////////////////////////////
Drupal.gmap.addHandler('width', function (elem) {
var obj = this;
// Respond to incoming width changes.
var binding = obj.bind("widthchange", function (w) {
elem.value = normalize(w);
});
// Send out outgoing width changes.
jQuery(elem).change(function () {
var n;
if ((n = normalize(elem.value))) {
elem.value = n;
obj.change('widthchange', binding, n);
}
});
obj.bind('init', function () {
jQuery(elem).change();
});
});
////////////////////////////////////////
// Height widget //
////////////////////////////////////////
Drupal.gmap.addHandler('height', function (elem) {
var obj = this;
// Respond to incoming height changes.
var binding = obj.bind("heightchange", function (h) {
elem.value = normalize(h);
});
// Send out outgoing height changes.
jQuery(elem).change(function () {
var n;
if ((n = normalize(elem.value))) {
elem.value = n;
obj.change('heightchange', binding, n);
}
});
obj.bind('init', function () {
jQuery(elem).change();
});
});
})(); // END CLOSURE
////////////////////////////////////////
// Control type widget //
////////////////////////////////////////
Drupal.gmap.addHandler('controltype', function (elem) {
var obj = this;
// Respond to incoming height changes.
var binding = obj.bind("controltypechange", function () {
elem.value = obj.vars.controltype;
});
// Send out outgoing height changes.
jQuery(elem).change(function () {
obj.vars.controltype = elem.value
obj.change("controltypechange", binding);
});
});
// // Map cleanup.
// if (Drupal.jsEnabled) {
// $(document).unload(GUnload);
// }
Drupal.behaviors.GMap = {
attach: function (context, settings) {
if (Drupal.settings && Drupal.settings['gmap_remap_widgets']) {
jQuery.each(Drupal.settings['gmap_remap_widgets'], function(key, val) {
jQuery('#'+ key).addClass('gmap-control');
});
}
jQuery('.gmap-gmap:not(.gmap-processed)', context).addClass('gmap-processed').each(function () {Drupal.gmap.setup.call(this)});
jQuery('.gmap-control:not(.gmap-processed)', context).addClass('gmap-processed').each(function () {Drupal.gmap.setup.call(this)});
},
detach: function (context, settings) {
jQuery('.gmap-processed', context).each(function (element) {
//find mapid
var id = jQuery(this).attr('id');
var mapid = id.split('-', 2);
//unload map
Drupal.gmap.unloadMap(mapid[1]);
});
}
};