function SfmbMapsGoogle(opts) {
var divObject = opts.divObject,
polyPointCallback = opts.polyPointCallback,
getPolygonCallback = opts.getPolygonCallback,
landmarkCallback = opts.landmarkCallback,
mapLoaded = opts.mapLoaded,
streetViewOpen = opts.streetViewOpen;
google.maps.fastCommandCallback = opts.fastCommandCallback;
this.div = divObject;
var infoWindowModel = new InfoWindowModel;
/*
[{point, marker, label}...]
*/
var markers = [];
var polygons = [];
var polys = [];
// global polygon used between [get/delete/new]polygon functions
var editingPolygon = null;
var newOnly = false;
var mapType = getMapTypeFromString(opts.mapType);
var mapOptions = {
zoom: 1,
center: new google.maps.LatLng(0, 0),
mapTypeId: mapType
};
// we keep only one marker at a time
var infoBubble = new InfoBubble({
map: map,
disableAutoPan: true,
padding:4,
content : new InfoWindowView(_.extend({model:infoWindowModel}, opts)).el
});
infoBubble.close();
google.maps.event.addListener(infoBubble,'closeclick', function(){
// console.log('Info window closed...');
});
var map = new google.maps.Map(
document.getElementById(divObject.getAttribute('id')),
mapOptions);
map.setOptions({draggableCursor:'default'});
//silently update map properties center so re-center will work properly
google.maps.event.addListener(map, 'dragend', function() {
opts.properties.attributes.center = [map.getCenter().lat(), map.getCenter().lng()];
} );
google.maps.event.addListenerOnce(map,'tilesloaded', function(){mapLoaded();})
var panorama = new google.maps.StreetViewPanorama(map.getDiv(), {enableCloseButton: true, visible:false});
panorama.setOptions({enableCloseButton: true, visible:false});
map.setStreetView(panorama);
google.maps.event.addListener(panorama, 'visible_changed', function() {
streetViewOpen(panorama.getVisible());
});
google.maps.openStreetView = function(){
map.getStreetView().setVisible(true);
streetViewOpen(true);
log("am deschis street view "+map.getStreetView())
}
// close the marker bubble and geocode bubble, add point to editing polygon
google.maps.event.addListener(map, 'click', function(event) {
infoBubble.close();
if (markerGeocode != null) {
markerGeocode.setMap(null);
markerGeocode = null;
}
if (newOnly && editingPolygon != null) {
if (!editingPolygon.polygon.getPath()) {
editingPolygon.polygon.setPath([event.latLng]);
} else {
editingPolygon.polygon.getPath().push(event.latLng);
}
}
if (!newOnly && landmarkCallback) {
landmarkCallback({latitude:event.latLng.lat(),
longitude:event.latLng.lng()});
}
});
/*
Resize the map to specified position;
*/
SfmbMapsGoogle.prototype.resize = function(height, width) {
this.div.style.height = height + 'px';
this.div.style.width = width + 'px';
google.maps.event.trigger(map, "resize");
}
/*
Put the markers on map
@params
pointsArray: [{id, latitude, longitude, icon, description}...]
setAutozoom: boolean
*/
SfmbMapsGoogle.prototype.putPoints = function(pointsArray, setAutozoom) {
if (pointsArray.length == 0) return;
// console.dir(pointsArray);
var bounds = new google.maps.LatLngBounds();
var self = this;
// console.dir(markers);
// console.dir(pointsArray);
//remove markers that are not in pointsArray
markers.filter(function(m){
return (m.dataset == pointsArray[0].dataset && !_.find(pointsArray,{id:m.id}));
}).forEach(function(p){
self.removePoint(p);
});
pointsArray.forEach(function(e) {
// if (infoWindowModel.get('id') == e.id) infoWindowModel.mergePoint(e);
bounds.extend(new google.maps.LatLng(e.latitude, e.longitude));
var existingMarker = _.findWhere(markers, {id:e.id});
if (e.id != "" && !existingMarker) markers.push(addMarkerWithLabel(e));
if (existingMarker) {
var samePosition = normDecimals(existingMarker.marker.getPosition().lat()) == normDecimals(e.latitude) && normDecimals(e.longitude) == normDecimals(existingMarker.marker.getPosition().lng())
var shouldUpdate = !samePosition || (existingMarker.marker.icon.url != e.icon) || (existingMarker.point.isInCall != e.isInCall) || (existingMarker.point.address != e.address);
// console.log('===========Is in call changed ? existing = '+ existingMarker.point.isInCall+ " new one ="+e.isInCall);
if (shouldUpdate) updateMarker(existingMarker,e);
}
});
if (setAutozoom) {
map.fitBounds(bounds);
if (pointsArray.length == 1)
map.setZoom(map.getZoom()-3);
}
};
//leave only n decimals in float
function normDecimals(float, n){
n = n || 8;
return parseFloat(parseFloat(float).toFixed(n));
};
//'private' variable and functions
var isLegacyIcons = false;
//this is where Adrian will intervene for future updates to map icons
function getNewIconsSize(iconPath){
var color = "#287aab";
var anchor = new google.maps.Point(16,48);
var reg = /_[0-9A-F]{6}_[sml]\./; //test for color and size in icon name
var size = "default_size";
var sizes = {
s : new google.maps.Size(-6,-40),
m : new google.maps.Size(-2,-33),
l : new google.maps.Size(0,-24),
default_size : new google.maps.Size(0,-25)
};
if (iconPath && reg.test(iconPath)) {
var ref = iconPath.split(/[_\.]/).slice(-3,-1);
color = '#'+ref[0];
size = ref[1];
}
// console.log(color + ' ' + size);
return {
labelOffset : sizes[size],
labelColor : color,
imageMarkerAnchor : anchor
}
}
function updateMarker(marker, point){
var newPosition = new google.maps.LatLng(point.latitude, point.longitude);
marker.marker.setPosition(newPosition);
marker.marker.setIcon(point.icon);
marker.label.setPosition(newPosition);
// console.dir(marker.label);
// var sizes = getNewIconsSize(point.icon);
// marker.label.setContent(getLabelContent(sizes.labelColor, point.id));
//marker.label.setPixelOffset(sizes.labelOffset);
marker.point = point;
if (infoWindowModel.id == point.id){
infoWindowModel.mergePoint(point);
if (infoWindowModel.isOpened()) map.setCenter(newPosition);
}
}
function getLabelContent(color, name){
return '
'
+ name
+ '
'
}
function addMarkerWithLabel(point) {
var lat = point.latitude;
var lon = point.longitude;
var imgFolder = "images/";
imgFolder = "";
var imageMarker = {
url: point.icon ? imgFolder + point.icon : "",
anchor: new google.maps.Point(16, 16)
};
var labelOffset = new google.maps.Size(-20, -35);
var labelColor = "yellow";
if (!isLegacyIcons) {
var sizes = getNewIconsSize(point.icon);
labelOffset = sizes.labelOffset;
labelColor = sizes.labelColor;
imageMarker.anchor= sizes.imageMarkerAnchor;
}
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat, lon),
icon: imageMarker
});
//only add info bubble for actual units (with speed), not for landmarks or geos
if (/\d{1,3}[mk]ph/.test(point.speed))
google.maps.event.addListener(marker, 'click', function(e) {
openBubble(marker, point.id, point.description, point.dataset, point);
});
if(imageMarker.url !== "") marker.setMap(map);
var content = getLabelContent(labelColor, point.id);
var myOptions = {
content: content,
boxStyle: {
textAlign: "center",
fontSize: "8pt"
},
disableAutoPan: true,
pixelOffset: labelOffset,
position: new google.maps.LatLng(lat, lon),
closeBoxURL: "",
isHidden: false,
zIndex: google.maps.Marker.MAX_ZINDEX + 1,
pane: "floatShadow"
};
var label = new InfoBox(myOptions);
label.open(map);
var toReturn = {
marker: marker,
dataset : point.dataset,
label: label,
id : point.id,
description : point.description,
point : point, //investigate for potential leaks
hide: function(){
if (this.id == infoWindowModel.get('id'))
infoBubble.close();
this.marker.setMap(null);
this.label.setMap(null);
}
};
return toReturn;
}
//to be used with polygons and polylines and markers (calls hide() on removed item)
function removeItem(collection, itemId){
var item = _.findWhere(collection, {id:itemId});
if (item){
item.hide();
collection.splice(collection.indexOf(item),1);
console.log('Removed item with id = '+item.id);
}
}
//removes all items from collection safely (calls removeItem on each item)
function removeAllItems(collection){
var ids = _.pluck(collection, 'id');
// console.log(ids);
ids.forEach(function(id){
removeItem(collection, id);
});
}
/*
Removes all markers
*/
SfmbMapsGoogle.prototype.removeAllPoints = function() {
removeAllItems(markers);
};
SfmbMapsGoogle.prototype.removePoint = function(point) {
removeItem(markers,point.id);
};
/*
Remove points from map
@params
points: [{id, latitude, longitude, color, description}...]
*/
SfmbMapsGoogle.prototype.removePoints = function(points) {
points.forEach(function(e) {
this.removePoint(e);
}, this);
};
SfmbMapsGoogle.prototype.showLabels = function() {
showHideLabels(true);
};
SfmbMapsGoogle.prototype.hideLabels = function() {
showHideLabels(false);
}
function showHideLabels(show, points) {
var theMap = show? map : null;
if (points) {
points.forEach(function(e, i, a) {
markers.forEach(function(elem, i, a){
if (elem.id == e.id)
elem.label.setMap(theMap);
});
});
} else {
markers.forEach(function(e, i, a) {
e.label.setMap(theMap);
});
}
}
/*
@params
points: [{id, latitude, longitude, color, description}...]
*/
SfmbMapsGoogle.prototype.putLabels = function(points) {
showHideLabels(true, points);
}
/*
@params
points: [{id, latitude, longitude, color, description}...]
*/
SfmbMapsGoogle.prototype.removeLabels = function(points) {
showHideLabels(false, points);
}
/*
@params:
lat: latitude - double
lon: longitude - double
zoom: int
*/
SfmbMapsGoogle.prototype.centerZoom = function(lat, lon, zoom) {
map.panTo(new google.maps.LatLng(lat, lon));
if (zoom > 0) map.setZoom(parseInt(zoom));
}
/*
@params
mapType: string
*/
SfmbMapsGoogle.prototype.setMapType = function(mapType) {
map.setMapTypeId(getMapTypeFromString(mapType));
}
function getMapTypeFromString(mapType) {
if (mapType == "map") {
return google.maps.MapTypeId.ROADMAP;
} else if (mapType == "satellite") {
return google.maps.MapTypeId.SATELLITE;
} else if (mapType == "hybrid") {
return google.maps.MapTypeId.HYBRID;
} else if (mapType == "terrain") {
return google.maps.MapTypeId.TERRAIN;
}
}
/*
@params
*/
SfmbMapsGoogle.prototype.getMapType = function() {
result = "";
var mapType = map.getMapTypeId();
if (mapType == google.maps.MapTypeId.ROADMAP) {
result = "map";
} else if (mapType == google.maps.MapTypeId.SATELLITE) {
result = "satellite";
} else if (mapType == google.maps.MapTypeId.HYBRID) {
result = "hybrid";
} else if (mapType == google.maps.MapTypeId.TERRAIN) {
result = "terrain";
}
return result;
}
/*
@params
address: string
*/
SfmbMapsGoogle.prototype.getLocation = function(address) {
// not implemented
}
/*
@params
lat: double
lon: double
*/
SfmbMapsGoogle.prototype.getAddress = function(lat, lon) {
// not implemented
}
/*
@params
markerName: string
*/
SfmbMapsGoogle.prototype.openInfoBubble = function(markerName) {
var marker = _.findWhere(markers, {id:markerName});
if (marker) openBubble(marker.marker, marker.id,marker.description, marker.dataset, marker.point);
};
function openBubble(marker, name, description, dataset, point) {
var streetViewService = new google.maps.StreetViewService();
streetViewService.getPanoramaByLocation(marker.getPosition(), 100,
function(streetViewPanoramaData, status){
var svavailable = (status === google.maps.StreetViewStatus.OK);
// infoBubble.content = getBubbleContent(name, description, dataset, svavailable, point);
point.hasStreetView = svavailable;
// console.dir(point);
//update info window only if the info point is different
if (infoWindowModel.get('id') != point.id){
infoBubble.close();
infoWindowModel.mergePoint(point);
}
infoBubble.open(map, marker);
// setTimeout(function(){infoBubble.content.style.display = 'block';},50);
});
map.getStreetView().setPosition(marker.getPosition());
};
SfmbMapsGoogle.prototype.updatePolygon = function(id, propName, propValue){
var options = {};
var translate = {
"borderColor" : "strokeColor",
"borderOpacity" : "strokeOpacity",
"borderWidth" : "strokeWeight",
"color" : "fillColor",
"opacity" : "fillOpacity"
}
options[translate[propName]] = propValue;
var thePolygon = _(polygons).findWhere({id:id});
// console.log(thePolygon);
// console.log(options);
// thePolygon.polygon.setOptions({fillColor:'#aa0000'});
thePolygon && thePolygon.polygon.setOptions(options);
};
/*
Add a polygon to map
@params
name: string
color: string
points: [{latitude, longitude}...]
*/
SfmbMapsGoogle.prototype.setPolygon = function(name, color, points, opacity, borderColor, borderOpacity, borderWidth) {
var isNew = false;
addPolygonOnMap(name, color, points, isNew, opacity, borderColor, borderOpacity, borderWidth);
};
function addPolygonOnMap(name, color, points, isNew, opacity, borderColor, borderOpacity, borderWidth) {
console.log("borderColor = " + borderColor + " width = " + borderWidth);
var polygonAttr = {
name: name,
color: color,
opacity : opacity,
borderColor : borderColor,
borderWidth : borderWidth,
borderOpacity : borderOpacity
};
var coords = [];
if (!isNew) {
points.forEach(function(e, i, a) {
coords.push(new google.maps.LatLng(e.latitude, e.longitude));
});
}
var polygon = new google.maps.Polygon({
clickable: false,
path: coords,
strokeColor: borderColor,
strokeOpacity: borderOpacity,
strokeWeight: borderWidth,
fillColor: color,
fillOpacity: opacity
});
if (isNew) {
polygon.editable = true;
}
var toAdd = {
polygonAttr: polygonAttr,
polygon: polygon,
id:polygonAttr.name,
hide:function(){
google.maps.event.clearListeners(this.polygon.getPath(),"set_at");
google.maps.event.clearListeners(this.polygon.getPath(), "insert_at");
this.polygon.setMap(null);
if (editingPolygon && editingPolygon.id == this.id) {
editingPolygon = null;
newOnly = false;
map.setOptions({draggableCursor:'default'});
}
}
};
polygons.push(toAdd);
polygon.setMap(map);
if (isNew) return polygons[polygons.length - 1];
}
/*
name is optional. If name == null -> remove all
@params
name: string
*/
SfmbMapsGoogle.prototype.deletePolygon = function(name) {
console.log('removing polygon '+name);
if (!name) this.deleteAllPolygons();
else{
var p = _.findWhere(polygons, {polygonAttr : {name:name}});
if (p) p.polygon.setMap(null);
removeItem(polygons,name);
}
map.setOptions({draggableCursor:'default'});
}
SfmbMapsGoogle.prototype.deleteAllPolygons = function() {
polygons.forEach(function(p) {p.polygon.setMap(null);});
console.log("------------------removing all polygons....");
removeAllItems(polygons);
}
/*
Add polyline on map
@params
setAutozoom: bool
color: string
thickness: double between 0 and 1
points: [{latitude, longitude}...]
name: poly name
*/
SfmbMapsGoogle.prototype.setPoly = function(setAutozoom,
color,
thickness,
points, name) {
var polyAttr = {
name: name,
color: color,
thickness: thickness
};
var coords = [];
// console.log("Poly color = " + polyAttr.color);
points.forEach(function(e, i, a) {
coords.push(new google.maps.LatLng(e.latitude, e.longitude));
});
var poly = new google.maps.Polyline({
path: coords,
strokeColor: color,
strokeOpacity: thickness,
strokeWeight: 4
});
polys.push({
polyAttr: polyAttr,
poly: poly,
id:polyAttr.name,
hide:function(){
this.poly.setMap(null);
}
});
poly.setMap(map);
}
SfmbMapsGoogle.prototype.deletePoly = function(name) {
if (name) {
p = _.findWhere(polys,{polyAttr : {name:name}});
if (p) p.poly.setMap(null);
removeItem(polys,name);
} else {
deleteAllPolys();
}
}
function deleteAllPolys() {
polys.forEach(function(p){p.poly.setMap(null);});
removeAllItems(polys);
}
SfmbMapsGoogle.prototype.newPolygon = function(name, color, opacity, borderColor, borderOpacity, borderWidth) {
console.log("opacity = " + opacity + " borderColor = " + borderColor);
var isNew = true;
editingPolygon = addPolygonOnMap(name, color, null, isNew, opacity, borderColor, borderOpacity, borderWidth);
map.setOptions({draggableCursor:'crosshair'});
addHandlersToPolygon(editingPolygon.polygon);
newOnly = true;
}
/*
Get the polygon info
name is optional. If name == null -> remove all
@params
name: string
@return:
*/
SfmbMapsGoogle.prototype.getPolygon = function(name) {
var polygonArray = [];
if (name) {
var thePolygon = _(polygons).findWhere({id:name});
if (thePolygon) {
polygonArray = { name: thePolygon.polygonAttr.name,
color: thePolygon.polygonAttr.color,
points: getPolygonLatLongString(
thePolygon.polygon)};
}
} else {
polygons.forEach(function(e, i, a) {
polygonArray.push({ name: e.polygonAttr.name,
color:e.polygonAttr.color,
points:getPolygonLatLongString(
e.polygon)});
});
}
console.log(JSON.stringify(polygonArray));
if (getPolygonCallback) {
getPolygonCallback(polygonArray);
}
return polygonArray; //[{name, color, [{latitude, longitude}...]}...]
}
function getPolygonLatLongString(polygon) {
var pointsString = [];
points = polygon.getPath();
var length = points.getLength();
for (var i = 0; i < length; i++) {
var p = points.getAt(i);
pointsString.push({
latitude: p.lat(),
longitude: p.lng()
});
}
return pointsString;
}
/*
@params:
name: string
*/
SfmbMapsGoogle.prototype.startEditPolygon = function(name) {
var polygon = _(polygons).findWhere({id:name});
if (polygon) {
polygon.polygon.setEditable(true);
editingPolygon = polygon;
map.setOptions({draggableCursor:'crosshair'});
addHandlersToPolygon(polygon.polygon);
}
}
function addHandlersToPolygon(p) {
google.maps.event.addListener(p.getPath(),
'set_at',
function(index) {
if (polyPointCallback) {
var somePoints = getPolygonLatLongString(p);
console.log(JSON.stringify(somePoints));
polyPointCallback(somePoints);
}
});
google.maps.event.addListener(p.getPath(),
'insert_at',
function(index) {
if (polyPointCallback) {
var somePoints = getPolygonLatLongString(p);
console.log(JSON.stringify(somePoints));
polyPointCallback(somePoints);
}
});
}
SfmbMapsGoogle.prototype.endEditPolygon = function() {
google.maps.event.clearListeners(editingPolygon.polygon.getPath(),
"set_at");
google.maps.event.clearListeners(editingPolygon.polygon.getPath(),
"insert_at");
editingPolygon.polygon.setEditable(false);
editingPolygon = null;
newOnly = false;
map.setOptions({draggableCursor:'default'});
}
/*
Clear the items from map
@params
markers: [{id, latitude, longitude, color, description}...]
polygons: [[name, color, {latitude, longitude}...]...]
polys: [[{latitude, longitude}...]...]
*/
SfmbMapsGoogle.prototype.clearFromMap = function(markers, polygons, polys) {
// NOT USED
}
/*
Clear all from map
*/
SfmbMapsGoogle.prototype.resetAll = function() {
infoBubble.close();
this.removeAllPoints();
this.deletePolygon();
this.deletePoly();
}
/*
@params
name: string
color: string
*/
SfmbMapsGoogle.prototype.changePolygonColor = function(name, color) {
var polygon = _(polygons).findWhere({id:name});
if (polygon) {
polygon.polygonAttr.color = color;
polygon.polygon.setOptions({
fillColor:color,
strokeColor: color});
}
}
/*
Geocoding
*/
SfmbMapsGoogle.prototype.geocode = function(address){
var geocoder = new google.maps.Geocoder();
var self = this;
geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var place = {
lat: results[0].geometry.location.lat(),
lon: results[0].geometry.location.lng(),
display_name: results[0].formatted_address
}
self.openSimplePopup(place);
}
});
}
var markerGeocode = null;
SfmbMapsGoogle.prototype.openSimplePopup = function(place){
var path = "http://chart.apis.google.com/chart?chst=d_bubble_icon_text_small&chld=flag|bbtl|"+place.display_name+"|FFFFaa|000000";
var shadowPath = "http://chart.apis.google.com/chart?chst=d_bubble_icon_text_small_shadow&chld=flag|bbtl|"+place.display_name+"|FFFF88|000000";
map.panTo(new google.maps.LatLng(place.lat, place.lon));
var iconPath = {
anchor: new google.maps.Point(0, 0),
url: path
};
var iconShadowPath = {
anchor: new google.maps.Point(0, 0),
url: shadowPath
};
var markerGeocode = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(place.lat, place.lon),
icon: iconPath,
shadow: iconShadowPath,
anchorPoint: new google.maps.Point(0, 0),
});
google.maps.event.addListener(markerGeocode, 'click', function(event) {
markerGeocode.setMap(null);
markerGeocode = null;
});
}
var traffic = new google.maps.TrafficLayer();
SfmbMapsGoogle.prototype.setTraffic = function(bool) {
if (bool) {
traffic.setMap(map);
} else {
traffic.setMap(null);
}
}
SfmbMapsGoogle.prototype.setMapKind = function() {
// TODO NOT USED
}
SfmbMapsGoogle.prototype.getMapKind = function() {
return "Google";
}
SfmbMapsGoogle.prototype.setLegacyIcons = function(legacyIcons){
console.log("Legacy icons for Google Maps are: "+legacyIcons);
isLegacyIcons = JSON.parse(legacyIcons);
}
}
var SfmbMaps = SfmbMapsGoogle;