get google maps v3 area, perimeter and length - google-maps-api-3

I'm trying to implement measuring tools to calculate the area and perimeter of a polygon or the length of a polyline. I've adapted existing code which works with polygons (commented out in the code), but I don't get it to work with both polygons and polylines.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map_div {
height: 100%;
}
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3.17&sensor=false&libraries=drawing"></script>
<script>
function initialize() {
map = new google.maps.Map(document.getElementById('map_div'), {
center: {lat: 49.820, lng: 6.100},
zoom: 8
});
// create a dialog box but dont bind it to anything yet
// myInfoWindow = new google.maps.InfoWindow();
// show drawing tools
DrawingTools();
}
function DrawingTools() {
myDrawingManager = new google.maps.drawing.DrawingManager({
drawingMode: null,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_LEFT,
drawingModes: [
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.POLYLINE
]
},
polygonOptions: {
draggable: true,
editable: true,
fillColor: '#fb0a2a',
fillOpacity: 0.2,
strokeColor: '#fb0a2a',
zIndex: 2000
},
polylineOptions: {
draggable: true,
editable: true,
strokeColor: '#fb0a2a',
zIndex:2000
}
});
myDrawingManager.setMap(map);
// when polygon drawing is complete, an event is raised by the map
// this function will listen to the event and work appropriately
DrawingCompletionListener();
};
/* Code that already works for polygones
function DrawingCompletionListener() {
// capture the field, set selector back to hand, remove drawing
google.maps.event.addListener(
myDrawingManager,
'polygoncomplete',
function(polygon) {
myField = polygon;
ShowDrawingTools(false);
ObjectEditable(false);
FieldClickListener();
}
);
}
*/
// Code I tried to get work for both polygones AND polylines
function DrawingCompletionListener() {
// capture the field, set selector back to hand, remove drawing
google.maps.event.addListener(
myDrawingManager,
'overlaycomplete',
function(event) {
if (event.type == google.maps.drawing.OverlayType.POLYGON) {
function pg (polygon) {
myField = polygon;
ShowDrawingTools(false);
ObjectEditable(false);
FieldClickListener();
}}
else if (event.type == google.maps.drawing.OverlayType.POLYLINE) {
function pl (polyline) {
myField = polyline;
ShowDrawingTools(false);
ObjectEditable(false);
AddPropertyToField();
FieldClickListener();
}}
}
);
}
/**
* Show or hide drawing tools
*/
function ShowDrawingTools(val) {
myDrawingManager.setOptions({
drawingMode: null,
drawingControl: val
});
}
/**
* Allow or disallow polygon/polyline to be editable and draggable
*/
function ObjectEditable(val) {
myField.setOptions({
editable: val,
draggable: val
});
myInfoWindow.close();
return false;
}
/**
* Attach an event listener to the polygon/polyline. When a user clicks on the
* object, get a formatted message that contains links to re-edit the
* object, mark it as complete, or delete it. The message
* appears as a dialog box
*/
function FieldClickListener() {
google.maps.event.addListener(
myField,
'click',
function(event) {
var message = GetMessage(myField);
myInfoWindow.setOptions({ content: message });
myInfoWindow.setPosition(event.latLng);
myInfoWindow.open(map);
}
);
}
/**
* Delete the polygon and show the drawing tools so that new polygon can be
* created
*/
function DeleteField() {
myInfoWindow.close();
myField.setMap(null);
ShowDrawingTools(true);
}
/**
* Get coordinates of the polygon/polyline and display information that should
* appear in the polygons dialog box when it is clicked
*/
function GetMessage(polygon) {
var coordinates = polygon.getPath().getArray();
var message = '';
message += '<div>'
+ 'area : ~' + GetArea(polygon) + ' ar<br />'
+ 'perimeter : ~' + GetPerimeter(polygon) + ' m'
+ 'length : ~' + GetLength(polyline) + ' m'
+ '</div>';
message += '<hr><div class="btn-group"><button type="button" class="btn btn-primary btn-xs" onclick="PolygonEditable(true);">Edit</button>'
+ '<button type="button" class="btn btn-primary btn-xs" onclick="ObjectEditable(false);">OK</button>'
+ '<button type="button" class="btn btn-primary btn-xs" onclick="DeleteField(myField);">Löschen</button></div>';
return message;
}
/**
* Get area / perimeter of the drawn polygon
*/
function GetArea(poly) {
var result = parseFloat(google.maps.geometry.spherical.computeArea(poly.getPath()))/100;
return result.toFixed(2);
}
function GetPerimeter(poly) {
var perimeter = parseFloat(google.maps.geometry.spherical.computeLength(poly.getPath()));
return perimeter.toFixed(0);
}
function GetLenght(poly) {
var length = parseFloat(google.maps.geometry.spherical.computeLength(poly.getPath()));
return length.toFixed(0);
}
</script>
</head>
<body onload="initialize()">
<div id="map_div">
</div>
</body>
</html>

I've changed the 'DrawingCompletionListener()' function to work.
I still have a little problem. I want to display different informations depending on the type of object, that is drawn. I don't get the correct syntax in my GetMessage(obj)-function to check whether the obj is a polygon or a polyline?
Here the complete code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#map_div {
height: 100%;
}
</style>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3.17&sensor=false&libraries=drawing"></script>
<script>
function initialize() {
map = new google.maps.Map(document.getElementById('map_div'), {
center: {lat: 49.820, lng: 6.100},
zoom: 8
});
// create a dialog box but dont bind it to anything yet
myInfoWindow = new google.maps.InfoWindow();
// show drawing tools
DrawingTools();
}
function DrawingTools() {
myDrawingManager = new google.maps.drawing.DrawingManager({
drawingMode: null,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_LEFT,
drawingModes: [
google.maps.drawing.OverlayType.POLYGON,
google.maps.drawing.OverlayType.POLYLINE
]
},
polygonOptions: {
draggable: true,
editable: true,
fillColor: '#fb0a2a',
fillOpacity: 0.2,
strokeColor: '#fb0a2a',
zIndex: 2000
},
polylineOptions: {
draggable: true,
editable: true,
strokeColor: '#fb0a2a',
zIndex:2000
}
});
myDrawingManager.setMap(map);
// when polygon drawing is complete, an event is raised by the map
// this function will listen to the event and work appropriately
DrawingCompletionListener();
};
// Draw polygones or polylines and add clicklistener to open infoWindow
function DrawingCompletionListener() {
// capture the field, set selector back to hand, remove drawing
google.maps.event.addListener(
myDrawingManager,
'overlaycomplete',
function(event) {
if (event.type == google.maps.drawing.OverlayType.POLYGON) {
myField = event.overlay;
ShowDrawingTools(false);
ObjectEditable(false);
FieldClickListener();
}
else if (event.type == google.maps.drawing.OverlayType.POLYLINE) {
myField = event.overlay;
ShowDrawingTools(false);
ObjectEditable(false);
FieldClickListener();
}
}
);
}
/**
* Show or hide drawing tools
*/
function ShowDrawingTools(val) {
myDrawingManager.setOptions({
drawingMode: null,
drawingControl: val
});
}
/**
* Allow or disallow polygon/polyline to be editable and draggable
*/
function ObjectEditable(val) {
myField.setOptions({
editable: val,
draggable: val
});
myInfoWindow.close();
return false;
}
/**
* Attach an event listener to the polygon/polyline. When a user clicks on the
* object, get a formatted message that contains links to re-edit the
* object, mark it as complete, or delete it. The message
* appears as a dialog box
*/
function FieldClickListener() {
google.maps.event.addListener(
myField,
'click',
function(event) {
var message = GetMessage(myField);
myInfoWindow.setOptions({ content: message });
myInfoWindow.setPosition(event.latLng);
myInfoWindow.open(map);
}
);
}
/**
* Delete the polygon / polyline and show the drawing tools again
*/
function DeleteField() {
myInfoWindow.close();
myField.setMap(null);
ShowDrawingTools(true);
}
/**
* Display information that should
* appear in the polygons / polylines dialog box when it is clicked
*/
function GetMessage(obj) {
var message = '';
// this is not yet working
if (obj.type == google.maps.drawing.OverlayType.POLYGON) {
message += '<div>'
+ 'area : ' + GetArea(obj) + ' ar<br />'
+ 'perimeter : ' + GetLength(obj) + ' m <br />'
+ '</div>';
}
else if (obj.type == google.maps.drawing.OverlayType.POLYLINE) {
message += '<div>'
+ 'length : ' + GetLength(obj) + ' m <br />'
+ '</div>';
}
message += '<hr><div class="btn-group"><button type="button" class="btn btn-primary btn-xs" onclick="ObjectEditable(true);">Edit</button>'
+ '<button type="button" class="btn btn-primary btn-xs" onclick="ObjectEditable(false);">OK</button>'
+ '<button type="button" class="btn btn-primary btn-xs" onclick="DeleteField(myField);">Delete</button></div>';
return message;
}
/**
* Get area / perimeter / lenght of the drawn polygon / polyline
*/
function GetArea(obj) {
var result = parseFloat(google.maps.geometry.spherical.computeArea(obj.getPath()))/100;
return result.toFixed(2);
}
function GetLength(obj) {
var length = parseFloat(google.maps.geometry.spherical.computeLength(obj.getPath()));
return length.toFixed(0);
}
</script>
</head>
<body onload="initialize()">
<div id="map_div">
</div>
</body>
</html>

Related

Trouble creating Google Map infowindow by passing information into an IIFE

I am trying to create an infowindow with an IIFE. I am having quite a bit of trouble passing information into it.
As you can see I retrieved an array of places using the searchBox Class, which was instantiated and correctly implemented in order to properly use the getPlaces() method.
Places is an array of objects and I use the information to create a marker and infowindow. The markers show up! However, I can't seem to pass the object, places[i], into the IIFE.
There's NOT even an error in the console, which is why I am in desperate need of your help.
My ultimate goal is to have an infowindow open on the clicked marker with the the corresponding information.
Can anyone spot what I am doing wrong here?
var places = searchBox.getPlaces(); // array of place objects
var placeMarkers = [];
var placeInfoWindow = new google.maps.InfoWindow();
var placeBounds = new google.maps.LatLngBounds();
if (!places || places === null || places.length === 0) {
alert("No Places Founds");
} else {
for (var i = 0, l = places.length; i < l; i++) {
// MARKER
var loc = places[i].geometry.location;
var placeMarker = new google.maps.Marker({
position: loc,
title: places[i].name,
animation: google.maps.Animation.DROP,
icon: places[i].icon
});
placeMarkers.push(placeMarker); // save each marker
placeMarker.setMap(map); // display marker immediately
// extend boundary to include each marker location
placeBounds.extend(loc);
//REGISTER MARKER CLICK HANDLER WITH CURRENT places[i] INFO
placeMarker.addListener("click", (function(placeCopy) {
return function() {
var infoWindowContentStr = '<div>';
if (placeCopy.name) {
infoWindowContentStr += '<div>' + placeCopy.name + '</div><br>';
}
if (placeCopy.formatted_address) {
infoWindowContentStr += '<div>' + placeCopy.formatted_address + '</div>';
}
infoWindowContentStr += '</div>';
placeInfoWindow.setContent(infoWindowContentStr);
placeInfoWindow.open(map, this);
};
}), places[i]);
}
map.fitBounds(placeBounds);
}
You have a typo in your IIFE function definition, it isn't executing the function and getting closure until the click happens.
related question: Google Maps API Places Library SearchBox (used to create the MCVE)
placeMarker.addListener("click", (function(placeCopy) {
return function() {
var infoWindowContentStr = '<div>';
if (placeCopy.name) {
infoWindowContentStr += '<div>' + placeCopy.name + '</div><br>';
}
if (placeCopy.formatted_address) {
infoWindowContentStr += '<div>' + placeCopy.formatted_address + '</div>';
}
infoWindowContentStr += '</div>';
placeInfoWindow.setContent(infoWindowContentStr);
placeInfoWindow.open(map, this);
};
})(places[i])); // you had }), places[i]);
proof of concept fiddle
code snippet:
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
mapTypeId: google.maps.MapTypeId.ROADMAP,
streetViewControl: false
});
var defaultBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(41.7033177, -93.0573533),
new google.maps.LatLng(41, -93)
);
map.fitBounds(defaultBounds);
var input = document.getElementById('target');
var searchBox = new google.maps.places.SearchBox(input);
searchBox.setBounds(defaultBounds);
var markers = [];
service = new google.maps.places.PlacesService(map);
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces(); // array of place objects
var placeMarkers = [];
var placeInfoWindow = new google.maps.InfoWindow();
var placeBounds = new google.maps.LatLngBounds();
if (!places || places === null || places.length === 0) {
alert("No Places Founds");
} else {
for (var i = 0, l = places.length; i < l; i++) {
// MARKER
var loc = places[i].geometry.location;
var placeMarker = new google.maps.Marker({
position: loc,
title: places[i].name,
animation: google.maps.Animation.DROP,
icon: places[i].icon
});
placeMarkers.push(placeMarker); // save each marker
placeMarker.setMap(map); // display marker immediately
// extend boundary to include each marker location
placeBounds.extend(loc);
//REGISTER MARKER CLICK HANDLER WITH CURRENT places[i] INFO
placeMarker.addListener("click", (function(placeCopy) {
return function() {
var infoWindowContentStr = '<div>';
if (placeCopy.name) {
infoWindowContentStr += '<div>' + placeCopy.name + '</div><br>';
}
if (placeCopy.formatted_address) {
infoWindowContentStr += '<div>' + placeCopy.formatted_address + '</div>';
}
infoWindowContentStr += '</div>';
placeInfoWindow.setContent(infoWindowContentStr);
placeInfoWindow.open(map, this);
};
})(places[i]));
}
map.fitBounds(placeBounds);
}
});
google.maps.event.addListener(map, 'bounds_changed', function() {
var bounds = map.getBounds();
searchBox.setBounds(bounds);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#search-panel {
position: absolute;
top: 5px;
left: 50%;
margin-left: -180px;
width: 350px;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
}
#target {
width: 345px;
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=places"></script>
<div id="search-panel">
<input id="target" type="text" placeholder="Search Box">
</div>
<div id="map_canvas"></div>

How to add google map and other charts in the gridstack widget using knockout.js

I am using Gridstack with Knockout.js. I am using http://troolee.github.io/gridstack.js/demo/knockout.html to create Gridstack widgets. I added a Google map in one of these widgets. The map appears with a scroll bar. Also, I need to have some kind of heading, as it is in its present state. The main problem is that the dimension of the map is fixed and when I resize the widget, the map does not fit in the widget automatically. Here is my full code:
ko.components.register('dashboard-grid', {
viewModel: {
createViewModel: function (controller, componentInfo) {
var ViewModel = function (controller, componentInfo) {
var grid = null;
this.widgets = controller.widgets;
this.id = controller.id;
this.afterAddWidget = function (items) {
if (grid == null) {
grid = $(componentInfo.element).find('.grid-stack').gridstack({
auto: false,
animate: true
}).data('gridstack');
}
var item = _.find(items, function (i) { return i.nodeType == 1 });
grid.addWidget(item);
ko.utils.domNodeDisposal.addDisposeCallback(item, function () {
grid.removeWidget(item);
});
};
};
return new ViewModel(controller, componentInfo);
}
},
template:
[
'<div class="grid-stack" data-bind="foreach: {data: widgets, afterRender: afterAddWidget}">',
' <div class="grid-stack-item" data-bind="attr: {\'data-gs-x\': $data.x, \'data-gs-y\': $data.y, \'data-gs-width\': $data.width, \'data-gs-height\': $data.height, \'data-gs-auto-position\': $data.auto_position}">',
' <div class="grid-stack-item-content" >',
' <header style="background-color: green;"> ',
' <button data-bind="click: $root.deleteWidget">Delete me</button><br>',
' <label><strong data-bind="text: $root.ids"></strong></label>',
' </header>',
' <div data-bind="attr: {id: $root.ids}">',
' </div>',
' </div>',
' </div>',
'</div> '
].join('')
});
$(function () {
var ids;
var Controller = function () {
var self = this;
this.widgets = ko.observableArray([]);
this.id = ko.observable("google-map");
this.ids = "";
this.addNewWidget = function () {
this.ids = this.id(); // this.ids is used to give id to div elements
this.widgets.push({
x: 0,
y: 0,
width:4,
height:5,
auto_position: true,
});
// calling method to draw map
createWidget(this.ids);
return false;
};
this.deleteWidget = function (item) {
self.widgets.remove(item);
return false;
};
};
ko.applyBindings(new Controller());
});
function createWidget(id) {
var dataArray, latitude, longitude, speed;
// Load the Visualization API and the corechart package.
try {
google.charts.load('current', {'packages':['map', 'gauge']});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart);
}
catch ( err ) {
//console.log(err);
}
function drawChart() {
latitude = Number(12.93213);
longitude = Number(77.695185);
var mapOptions = {
showTooltip: true,
showInfoWindow: true,
zoomLevel: 16, // range: 0-21 for "roadmap" map type
mapType: 'roadmap',
enableScrollWheel: true,
draggable: false,
};
var coordinates = "Latitude : " + latitude + "\nLongitude : "+ longitude;
var mapData = google.visualization.arrayToDataTable([
['Lat', 'Long', 'Name'],
[latitude, longitude, coordinates]
] );
try {
//var chart = new google.visualization.Gauge(document.getElementById('gauge'));
var map = new google.visualization.Map(document.getElementById(id));
map.draw(mapData, mapOptions);
}
catch (err) {
console.log(err);
}
} // drawChart() ends here
} // createWidgets() ends here

No lines drawn when drawing Polyline with MVCArray, with API v3.16 and later

If you use Google Maps API v3.16 and later, polyline are not drawn when a new marker is added to the polyline path and MVCArray, only markers plotted on a map.
My program based on code from http://nettique.free.fr/gmap/toolbar.html
html file :
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>map toolbar implementation</title>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3.exp&sensor=true"></script>
<style type="text/css">
--- truncate ----
</style>
<script type="text/javascript" src="toolbarv3_files/mapToolbar.js"></script>
<script type="text/javascript">
// Register an event listener to fire when the page finishes loading.
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
body section
drawing toolbar :
<div id="hand_b" onclick="MapToolbar.stopEditing()"/>
<div id="line_b" onclick="MapToolbar.initFeature('line')"/>
canvas :
<div id="map" style="width: 85%; height: 100%; position: absolute;"></div>
script file (mapToolbar.js):
var map;
var MapToolbar = {
//reorder index of a poly markers array
reindex:function(markers){
markers.forEach(function(marker, index){
marker.index = index;
});
},
//add a point to a poly, 'e' can be a click event or a latLng object
addPoint : function(e, poly, index) {
var e = (typeof e.latLng != "undefined")? e.latLng : e,
image = new google.maps.MarkerImage('images/marker-edition.png',
new google.maps.Size(9, 9),
new google.maps.Point(0, 0),
new google.maps.Point(5, 5)),
imageover = new google.maps.MarkerImage('images/marker-edition-over.png',
new google.maps.Size(9, 9),
new google.maps.Point(0, 0),
new google.maps.Point(5, 5)),
path = poly.getPath(),
index = (typeof index != "undefined")? index : path.length,
markers = (poly.markers)? poly.markers : new google.maps.MVCArray,
marker = new google.maps.Marker({
position: e,
map: map,
draggable: true,
icon: image
});
marker.index = index;
path.insertAt(index, e);
markers.insertAt(index, marker)
if(arguments[2]){
MapToolbar.reindex(markers);
}
features:{
.....
lineTab: {},
.....
},
//instanciate a new Feature instance and create a reference
initFeature: function(type){
new MapToolbar.Feature(type);
},
//check if a toolbar button is selected
isSelected: function(el){
return (el.className == "selected");
},
//the map DOM node container
....
lineCounter:0,
....
//select hand button
stopEditing: function() {
this.removeClickEvent();
this.select("hand_b");
},
//create new polyline function
MapToolbar.Feature.prototype.poly = function(type) {
var color = MapToolbar.getColor(false),
path = new google.maps.MVCArray,
poly,
self = this,
el = type + "_b";
if(type=="shape"){
poly = self.createShape( {strokeWeight: 3, fillColor: color}, path );
}else if(type=="line"){
poly = self.createLine( {strokeWeight: 3, strokeColor: color }, path );
}
poly.markers = new google.maps.MVCArray;
if(MapToolbar.isSelected(document.getElementById(el))) return;
MapToolbar.select(el);
MapToolbar.currentFeature = poly;
poly.setMap(map);
if(!poly.$el){
++MapToolbar[type+"Counter"];
poly.id = type + '_'+ MapToolbar[type+"Counter"];
poly.$el = MapToolbar.addFeatureEntry(poly.id, color);
MapToolbar.features[type+"Tab"][poly.id] = poly;
}
}
MapToolbar.Feature.prototype.createLine = function(opts, path) {
var poly = new google.maps.Polyline({
strokeWeight: opts.strokeWeight,
strokeColor: opts.strokeColor
}), self = this;
poly.setPath(new google.maps.MVCArray(path));
return poly;
}
//initialization function
function initialize(container) {
var options = {
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, google.maps.MapTypeId.TERRAIN],
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
}
}
map = new google.maps.Map(document.getElementById('map'));
map.setCenter(new google.maps.LatLng(47.9, 1.9 ));
map.setZoom(12);
map.setMapTypeId( google.maps.MapTypeId.ROADMAP );
with(MapToolbar){
with(buttons){
.....
$hand = document.getElementById("hand_b");
$line = document.getElementById("line_b");
....
}
....
select("hand_b");
}
MapToolbar.polyClickEvent = google.maps.event.addListener(map, 'click', function(event){
if( !MapToolbar.isSelected(MapToolbar.buttons.$shape) && !MapToolbar.isSelected(MapToolbar.buttons.$line) ) return;
if(MapToolbar.currentFeature){
MapToolbar.addPoint(event, MapToolbar.currentFeature);
}
});
}
complete version of "mapToolbar.js" script file is also available at : https://code.google.com/p/js2shapefile/source/browse/trunk/lib/mapToolbar.js?r=2
an error occurred when executing line "path.insertAt(index, e);" (addPoint function).
TypeError: this.j[qd] is not a function
...his[gd](a,b)}};L.insertAt=function(a,b){this.j[qd](a,0,b);bg(this);S[n](this,"in...
{main,g...try}.js (line 26, col 1473)
I had the same problem. I've solved changing poly.setPath in createLine function.
MapToolbar.Feature.prototype.createLine = function(opts, path) {
var poly = new google.maps.Polyline({
strokeWeight: opts.strokeWeight,
strokeColor: opts.strokeColor
}), self = this;
// 27/08/2014 - This not work
//poly.setPath(new google.maps.MVCArray(path));
poly.setPath(path);
return poly;
}

Capture Coordinates in Google Map on User Click

I'm using this code to capture the co-ordinates when user clicks on the map by using below event listener:
google.maps.event.addListener(map, 'click', function(event) {
placeMarker(event.latLng);
});
However this function doesn't get called when user click on already marked location in Map.
Meaning this function is not called for points where mouse pointer changes to hand icon on Google Map.
Need help on capturing these kind of locations.
You should add the click listener on marker will give you the position of marker.
//Add listener
google.maps.event.addListener(marker, "click", function (event) {
var latitude = event.latLng.lat();
var longitude = event.latLng.lng();
console.log( latitude + ', ' + longitude );
}); //end addListener
Edit:
You need something like this
//Add listener
google.maps.event.addListener(marker, "click", function (event) {
var latitude = event.latLng.lat();
var longitude = event.latLng.lng();
console.log( latitude + ', ' + longitude );
radius = new google.maps.Circle({map: map,
radius: 100,
center: event.latLng,
fillColor: '#777',
fillOpacity: 0.1,
strokeColor: '#AA0000',
strokeOpacity: 0.8,
strokeWeight: 2,
draggable: true, // Dragable
editable: true // Resizable
});
// Center of map
map.panTo(new google.maps.LatLng(latitude,longitude));
}); //end addListener
Another solution is to place a polygon over the map, same size as the map rectangle, and collect this rectangles clicks.
function initialize() {
var mapDiv = document.getElementById('map-canvas');
var map = new google.maps.Map(mapDiv, {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
google.maps.event.addListener(map, 'bounds_changed', function() {
var lat1 = 37.41463623043073;
var lat2 = 37.46915383933881;
var lng1 = -122.1848153442383;
var lng2 = -122.09898465576174;
var rectangle = new google.maps.Polygon({
paths : [
new google.maps.LatLng(lat1, lng1),
new google.maps.LatLng(lat2, lng1),
new google.maps.LatLng(lat2, lng2),
new google.maps.LatLng(lat1, lng2)
],
strokeOpacity: 0,
fillOpacity : 0,
map : map
});
google.maps.event.addListener(rectangle, 'click', function(args) {
console.log('latlng', args.latLng);
});
});
}
Now you get LatLng's for places of interest (and their likes) also.
demo -> http://jsfiddle.net/qmhku4dh/
You're talking about the Point of Interest icons that Google puts on the map.
Would it work for you to remove these icons entirely? You can do that with a Styled Map. To see what this would look like, open the Styled Map Wizard and navigate the map to the area you're interested in.
Click Point of interest under Feature type, and then click Labels under Element type. Finally, click Visibility under Stylers and click the Off radio button under that.
This should remove all of the point of interest icons without affecting the rest of the map styling. With those gone, clicks there will respond to your normal map click event listener.
The Map Style box on the right should show:
Feature type: poi
Element type: labels
Visibility: off
If the result looks like what you want, then click Show JSON at the bottom of the Map Style box. The resulting JSON should like this this:
[
{
"featureType": "poi",
"elementType": "labels",
"stylers": [
{ "visibility": "off" }
]
}
]
You can use that JSON (really a JavaScript object literal) using code similar to the examples in the Styled Maps developer's guide. Also see the MapTypeStyle reference for a complete list of map styles.
This example demonstrates the use of click event listeners on POIs (points of interest). It listens for the click event on a POI icon and then uses the placeId from the event data with a directionsService.route request to calculate and display a route to the clicked place. It also uses the placeId to get more details of the place.
Read the google documentation.
<!DOCTYPE html>
<html>
<head>
<title>POI Click Events</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<style>
/* Always set the map height explicitly to define the size of the div
* element that contains the map. */
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.title {
font-weight: bold;
}
#infowindow-content {
display: none;
}
#map #infowindow-content {
display: inline;
}
</style>
</head>
<body>
<div id="map"></div>
<div id="infowindow-content">
<img id="place-icon" src="" height="16" width="16">
<span id="place-name" class="title"></span><br>
Place ID <span id="place-id"></span><br>
<span id="place-address"></span>
</div>
<script>
function initMap() {
var origin = {lat: -33.871, lng: 151.197};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 18,
center: origin
});
var clickHandler = new ClickEventHandler(map, origin);
}
/**
* #constructor
*/
var ClickEventHandler = function(map, origin) {
this.origin = origin;
this.map = map;
this.directionsService = new google.maps.DirectionsService;
this.directionsDisplay = new google.maps.DirectionsRenderer;
this.directionsDisplay.setMap(map);
this.placesService = new google.maps.places.PlacesService(map);
this.infowindow = new google.maps.InfoWindow;
this.infowindowContent = document.getElementById('infowindow-content');
this.infowindow.setContent(this.infowindowContent);
// Listen for clicks on the map.
this.map.addListener('click', this.handleClick.bind(this));
};
ClickEventHandler.prototype.handleClick = function(event) {
console.log('You clicked on: ' + event.latLng);
// If the event has a placeId, use it.
if (event.placeId) {
console.log('You clicked on place:' + event.placeId);
// Calling e.stop() on the event prevents the default info window from
// showing.
// If you call stop here when there is no placeId you will prevent some
// other map click event handlers from receiving the event.
event.stop();
this.calculateAndDisplayRoute(event.placeId);
this.getPlaceInformation(event.placeId);
}
};
ClickEventHandler.prototype.calculateAndDisplayRoute = function(placeId) {
var me = this;
this.directionsService.route({
origin: this.origin,
destination: {placeId: placeId},
travelMode: 'WALKING'
}, function(response, status) {
if (status === 'OK') {
me.directionsDisplay.setDirections(response);
} else {
window.alert('Directions request failed due to ' + status);
}
});
};
ClickEventHandler.prototype.getPlaceInformation = function(placeId) {
var me = this;
this.placesService.getDetails({placeId: placeId}, function(place, status) {
if (status === 'OK') {
me.infowindow.close();
me.infowindow.setPosition(place.geometry.location);
me.infowindowContent.children['place-icon'].src = place.icon;
me.infowindowContent.children['place-name'].textContent = place.name;
me.infowindowContent.children['place-id'].textContent = place.place_id;
me.infowindowContent.children['place-address'].textContent =
place.formatted_address;
me.infowindow.open(me.map);
}
});
};
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places&callback=initMap"
async defer></script>
</body>
</html>
If you are using npm load-google-maps-api with webpack this worked for me:
const loadGoogleMapApi = require("load-google-maps-api");
loadGoogleMapApi({ key: process.env.GOOGLE_MAP_API_KEY }).then(map => {
let mapCreated = new map.Map(mapElem, {
center: { lat: lat, lng: long },
zoom: 7
});
mapCreated.addListener('click', function(e) {
console.log(e.latLng.lat()); // this gives you access to the latitude value of the click
console.log(e.latLng.lng()); // gives you access to the latitude value of the click
var marker = new map.Marker({
position: e.latLng,
map: mapCreated
});
mapCreated.panTo(e.latLng); // finally this adds red marker to the map on click.
});
});
Next if you are integrating openweatherMap in your app you can use the value of e.latLng.lat() and e.latLng.lng() which I console logged above in your api request. This way:
http://api.openweathermap.org/data/2.5/weather?lat=${e.latLng.lat()}&lon=${e.latLng.lng()}&APPID=${YOUR_API_KEY}
I hope this helps someone as it helped me.
Cheers!

How to save map drawing state (Polygon, Polyline, Markers)

I want to enable drawing on Google Maps like (see this example)
When user finish with drawings he will click on save button to save his drawings in Database or KML file, anything :) .. I do not know how to the save part? Could anyone help me
Here, http://jsfiddle.net/X66L4/1/ try drawing some circles, click on SAVE, then edit the circles by switching to the hand cursor and SAVE again to see the changes.
I show an example to save circles' data, the main idea is to keep a global array for each drawing type (line, polygon, marker, circle), and use a listener on the drawing manager to detect each type being drawn (complete).
var circles = [];
google.maps.event.addDomListener(drawingManager, 'circlecomplete',
function(circle) {
circles.push(circle);
});
The reason to save the entire reference to the drawn object is to continue tracking changes. So you will need an array and listener for each type of drawing.
Then, when you want to save the data (you may wish to do so at every edit), iterate through the arrays and extract the minimum information to rebuild it (center, radius, path, latLng, and so on.)
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
html, body, #map_canvas { margin: 0; padding: 0; height: 100% }
</style>
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=drawing"></script>
<script type="text/javascript">
var myOptions = {
center: new google.maps.LatLng(-25,177.5),
zoom: 3,
mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map;
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var drawingManager = new google.maps.drawing.DrawingManager({
drawingMode: google.maps.drawing.OverlayType.CIRCLE,
drawingControl: true,
drawingControlOptions: {
position: google.maps.ControlPosition.TOP_CENTER,
drawingModes: [google.maps.drawing.OverlayType.CIRCLE]
},
circleOptions: {
editable: true
}
});
drawingManager.setMap(map);
var circles = [];
google.maps.event.addDomListener(drawingManager, 'circlecomplete', function(circle) {
circles.push(circle);
});
google.maps.event.addDomListener(savebutton, 'click', function() {
document.getElementById("savedata").value = "";
for (var i = 0; i < circles.length; i++) {
var circleCenter = circles[i].getCenter();
var circleRadius = circles[i].getRadius();
document.getElementById("savedata").value += "circle((";
document.getElementById("savedata").value +=
circleCenter.lat().toFixed(3) + "," + circleCenter.lng().toFixed(3);
document.getElementById("savedata").value += "), ";
document.getElementById("savedata").value += circleRadius.toFixed(3) + ")\n";
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<button id="savebutton">SAVE</button>
<textarea id="savedata" rows="8" cols="40"></textarea>
<div id="map_canvas"></div>
</body>
</html>
In my experience, it's easier to use map's dataLayer then the drawing manager.
Try out this fiddle.
FiddleLink
Showing the controls:
map.data.setControls(['Polygon']);
map.data.setStyle({
editable: true,
draggable: true
});
in this function you can see the Create, Read (localStorage) and Remove (not in that order):
function loadPolygons(map) {
var data = JSON.parse(localStorage.getItem('geoData'));
map.data.forEach(function (f) {
map.data.remove(f);
});
console.log(data);
map.data.addGeoJson(data)
}

Resources