How do I redraw a google maps marker on click? - google-maps-api-3

I have a google map with a set of map markers. I chose to draw the map markers with a function called pinSymbol() - instead of using the default image.
I want to change the color of the pin when it is clicked, but I can't get it to update. With the current code I can change the property of the icon, I can see this with console.log(marker), however it won't update the color on the map.
Question: How do I redraw the icon on click?
This is my code.
// Go through all restaurants and get facebook info,
// then create a marker for each one.
restaurants.forEach(function(restaurant){
getFacebookInfo(restaurant);
}); // end forEach loop
// Get data from Facebook Graph API and create a marker
function getFacebookInfo(restaurant){
$.ajax({
url : '/restaurants/' + restaurant.id,
type : 'GET',
dataType:'json',
success : function(data) {
restaurant.about = data.about;
createMarker(restaurant);
},
error : function(request, error) {
console.log(error);
alert("We're having some trouble getting a restaurant's info from Facebook. " +
"Please check your internet connection and try refreshing the page.")
}
});
}
// Create a marker on the map for a location
function createMarker(restaurant){
var position = restaurant.location;
var infowindow = new google.maps.InfoWindow({
maxWidth: 200
});
restaurant.marker = new google.maps.Marker({
position: position,
map: map,
icon: pinSymbol('#CD212A', '#CD212A'),
name: restaurant.name,
id: restaurant.id,
about: restaurant.about,
animation: google.maps.Animation.DROP
});
// Push the marker to array of markers
markers.push(restaurant.marker);
// Call populateInfoWindow function
populateInfoWindow(restaurant.marker, infowindow);
// Add infowindow as a property to restaurant
// this makes it available for use outside this function.
restaurant.infowindow = infowindow;
This is where I'm stuck:
// Open infowindow when marker is clicked and change color
restaurant.marker.addListener('click', function(){
this.icon = pinSymbol('#EED4D9', '#EED4D9');
console.log(restaurant.marker);
infowindow.open(map, this);
});
}
pinSymbol Function
// Create pin for google map marker
function pinSymbol(color, strokeColor) {
return {
path: 'M 0,0 C -2,-20 -10,-22 -10,-30 A 10,10 0 1,1 10,-30 C 10,-22 2,-20 0,0 z',
fillColor: color,
fillOpacity: 1,
strokeColor: strokeColor,
strokeWeight: 1,
scale: 1,
labelOrigin: new google.maps.Point(0,-29)
};
}

There is no (documented) .icon property of a marker. Don't use it. Use the documented .setIcon method:
// Open infowindow when marker is clicked and change color
restaurant.marker.addListener('click', function() {
this.setIcon(pinSymbol('#EED4D9', '#EED4D9'));
console.log(restaurant.marker);
infowindow.open(map, this);
});
proof of concept fiddle
code snippet:
var geocoder;
var map;
var markers = [];
function initialize() {
map = new google.maps.Map(
document.getElementById("map_canvas"), {
center: new google.maps.LatLng(37.4419, -122.1419),
zoom: 13,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
createMarker({
name: "center",
id: 2,
about: "",
location: {
lat: 37.4419,
lng: -122.1419
}
});
}
google.maps.event.addDomListener(window, "load", initialize);
// Create a marker on the map for a location
function createMarker(restaurant) {
var position = restaurant.location;
var infowindow = new google.maps.InfoWindow({
maxWidth: 200
});
restaurant.marker = new google.maps.Marker({
position: position,
map: map,
icon: pinSymbol('#CD212A', '#CD212A'),
name: restaurant.name,
id: restaurant.id,
about: restaurant.about,
animation: google.maps.Animation.DROP
});
// Push the marker to array of markers
markers.push(restaurant.marker);
// Call populateInfoWindow function
populateInfoWindow(restaurant.marker, infowindow);
// Add infowindow as a property to restaurant
// this makes it available for use outside this function.
restaurant.infowindow = infowindow;
// Open infowindow when marker is clicked and change color
restaurant.marker.addListener('click', function() {
if (this.getIcon().fillColor != "#EED4D9") {
this.setIcon(pinSymbol('#EED4D9', '#EED4D9'));
} else {
this.setIcon(pinSymbol('#CD212A', '#CD212A'));
}
console.log(restaurant.marker);
infowindow.open(map, this);
});
}
// Create pin for google map marker
function pinSymbol(color, strokeColor) {
return {
path: 'M 0,0 C -2,-20 -10,-22 -10,-30 A 10,10 0 1,1 10,-30 C 10,-22 2,-20 0,0 z',
fillColor: color,
fillOpacity: 1,
strokeColor: strokeColor,
strokeWeight: 1,
scale: 1,
labelOrigin: new google.maps.Point(0, -29)
};
}
function populateInfoWindow(marker, infowindow) {
infowindow.setContent("content");
};
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map_canvas"></div>

Related

Google maps API getting infowindow on click with geojson file

I am using the google maps API and I am displaying polygons on a map using a GeoJSON file. When the user presses inside the polygon, I would like an InfoWindow to appear and display data that is stored in the properties. Seems easy enough but when I am clicking on the polygons, nothing is popping up. Can anyone explain what I am doing wrong?
Below is what I am currently attempting:
map.data.loadGeoJson('plant_bounds_2011.json');
map.data.setStyle({
fillColor: 'red',
strokeWeight: 1
});
var infowindow = new google.maps.InfoWindow({
content: "hello"
});
map.data.addListener('click', function(event) {
let id = event.feature.getProperty('ID');
let name = event.feature.getProperty('HORZ_ORG');
let html = id + " " + name;
infowindow.setContent(html); // show the html variable in the infowindow
infowindow.setPosition(event.feature.getGeometry().get()); // anchor the infowindow at the marker
infowindow.setOptions({pixelOffset: new google.maps.Size(0,-30)}); // move the infowindow up slightly to the top of the marker icon
infowindow.open(map);
});
There is a javascript error with the posted code: Uncaught TypeError: event.feature.getGeometry(...).get is not a function on the line:
infowindow.setPosition(event.feature.getGeometry().get()); // anchor the infowindow at the marker`
A Data.Polygon geometry doesn't have a .get() method. It has a .getArray() method (which returns an array of LineStrings)
One location to place the InfoWindow at would be the point clicked (which is in the polygon):
infowindow.setPosition(event.latLng);
(if you want to either add an fixed point for the infowindow to the GeoJson or you want to compute a fixed point from the polygon you can do that as well)
proof of concept fiddle
code snippet:
function initialize() {
var map = new google.maps.Map(
document.getElementById("map_canvas"), {
zoom: 4,
center: {
lat: -28,
lng: 137
},
mapTypeId: google.maps.MapTypeId.ROADMAP
});
map.data.loadGeoJson('https://storage.googleapis.com/mapsdevsite/json/google.json');
map.data.setStyle({
fillColor: 'red',
strokeWeight: 1
});
var infowindow = new google.maps.InfoWindow({
content: "hello"
});
map.data.addListener('click', function(event) {
let id = event.feature.getProperty('ID');
let name = event.feature.getProperty('HORZ_ORG');
if (typeof id == "undefined") id = event.feature.getProperty('letter');
if (typeof name == "undefined") name = event.feature.getProperty('color');
let html = id + " " + name;
infowindow.setContent(html); // show the html variable in the infowindow
infowindow.setPosition(event.latLng);
infowindow.setOptions({
pixelOffset: new google.maps.Size(0, 0)
}); // move the infowindow up slightly to the top of the marker icon
infowindow.open(map);
});
}
google.maps.event.addDomListener(window, "load", initialize);
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map_canvas"></div>

svg static image within the area of a polygon

How do I get the svg image is static when I zoom in on the map, which always remains in the same place.
This is my fiddle
If I use png images works , but it is not visually well for me and is not what i'm looking for.
Help is appreciated
Sorry for my english.
new Fiddle
The anchor is expected to be a Point, not a LatLng.
The default-acnchor is the bottom-middle of the icon, as it seems you need to set it to the top-left, so it has to be:
new google.maps.Point(0,0)
When you want to have a scaled icon based on the zoom you must calculate the scale-property and re-assign the icon to the marker.
The formula would be(assuming the scale-factor at zoom 12 is 1):
Math.pow(2,map.getZoom()-12)
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(-32.95041520, -60.66641804),
zoom: 12,
mapTypeId: google.maps.MapTypeId.TERRAIN
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
triangleCoords = [
new google.maps.LatLng(-32.93831432, -60.69379806),
new google.maps.LatLng(-32.96337859, -60.67860603),
new google.maps.LatLng(-32.96352262, -60.66633224),
new google.maps.LatLng(-32.95041520, -60.66641807)
];
var bermudaTriangle = new google.maps.Polygon({
paths: triangleCoords,
IsInactivo: true
});
bermudaTriangle.setMap(map);
var bounds = new google.maps.LatLngBounds();
var i;
for (i = 0; i < triangleCoords.length; i++) {
bounds.extend(triangleCoords[i]);
}
console.log(bounds.getCenter());
centroPolygon = bounds.getCenter();
var inactive = new google.maps.MVCObject();
inactive.set('icon', {
path: 'M27.314 4.686c-3.022-3.022-7.040-4.686-11.314-4.686s-8.292 1.664-11.314 4.686c-3.022 3.022-4.686 7.040-4.686 11.314s1.664 8.292 4.686 11.314c3.022 3.022 7.040 4.686 11.314 4.686s8.292-1.664 11.314-4.686c3.022-3.022 4.686-7.040 4.686-11.314s-1.664-8.292-4.686-11.314zM28 16c0 2.588-0.824 4.987-2.222 6.949l-16.727-16.727c1.962-1.399 4.361-2.222 6.949-2.222 6.617 0 12 5.383 12 12zM4 16c0-2.588 0.824-4.987 2.222-6.949l16.727 16.727c-1.962 1.399-4.361 2.222-6.949 2.222-6.617 0-12-5.383-12-12z',
fillColor: '#FF5858',
fillOpacity: 0.4,
scale: 1,
strokeColor: '#FF5858',
strokeWeight: 1,
//set the anchor to the top left corner of the svg
anchor: new google.maps.Point(0, 0)
});
google.maps.event.addListener(map, 'zoom_changed', function() {
inactive.get('icon').scale = Math.pow(2, this.getZoom() - 12);
//tell the marker that the icon has changed
inactive.notify('icon');
});
google.maps.event.trigger(map, 'zoom_changed');
new google.maps.Marker({
map: map,
position: centroPolygon
}).bindTo('icon', inactive, 'icon');
}
google.maps.event.addDomListener(window, 'load', initialize)
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3&.js"></script>
<div id="map-canvas"></div>

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!

Unable to show the latitude and longitude in the InfoWindow

I have a java script function which I am using to display a marker on the selected position of the map and also show the latitude and longitude at the marker's location in a InfoWindow.
I could display the marker at any location but unable to show a InfoWindow with the coordinates.
This is the function:
function init()
{
var mapoptions=
{
center: new google.maps.LatLng(17.379064211298, 78.478946685791),
zoom: 8,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map=new google.maps.Map(document.getElementById("map_can"), mapoptions);
var marker;
google.maps.event.addListener(map,'click',function(event)
{
marker= new google.maps.Marker({position:event.latLng,map:map});
});
var iwindow= new google.maps.InfoWindow();
google.maps.event.addListener(marker,'click',function(event)
{
iwindow.setContent(event.latLng.lat()+","+event.latLng.lng());
iwindow.open(map,marker);
});
}
Where am I wrong? Suggestions please.
This is because you attach event to an empty marker object (it is unassigned at the moment when you invoke
google.maps.event.addListener(marker,'click',function(event) { ... });
Try attaching click event to the marker after you create it, e.g.:
google.maps.event.addListener(map,'click',function(event)
{
marker= new google.maps.Marker({position:event.latLng,map:map});
google.maps.event.addListener(marker,'click',function(event)
{
iwindow.setContent(event.latLng.lat()+","+event.latLng.lng());
iwindow.open(map,marker);
});
});
You can try this snipped code :
function addMarkerWithTimeout(position, timeout, id) {
window.setTimeout(function () {
markers.push(new google.maps.Marker({
position: position,
map: map,
icon: image1,
title: "whatever!",
draggable: true,
animation: google.maps.Animation.ROUTE
}));
google.maps.event.addListener(map, 'click', function (event)
{
google.maps.event.addListener(markers[id], 'click', function (event)
{
infoWindow.setContent(event.latLng.lat() + "," + event.latLng.lng());
infoWindow.open(map, markers[id]);
});
});
}, timeout);
}

The correct way to hide a polyline?

I´ve a function that show a polyline on a map, this part is working, now I want to implement a function that hides the polyline, but I can´t find my mistake, thanks in advance.
function cargaMapaCYL(mapa, varControl){
var limite = null;
limite = [
new google.maps.LatLng(42.49956716,-7.019005501),
new google.maps.LatLng(42.49947126,-7.029286373),
new google.maps.LatLng(42.50904062,-7.049299123),
new google.maps.LatLng(42.50722622,-7.069103626),
new google.maps.LatLng(42.50452387,-7.000150672),
new google.maps.LatLng(42.49348015,-6.983058917),
new google.maps.LatLng(42.49843269,-6.971666546),
new google.maps.LatLng(42.51765791,-6.956909023),
new google.maps.LatLng(42.52010069,-6.927429186),
new google.maps.LatLng(42.50992238,-6.914231493),
new google.maps.LatLng(42.50096695,-6.879679821),
new google.maps.LatLng(42.48775868,-6.857775832),
new google.maps.LatLng(43.23907504,-3.293216584)], "#000000", 5);
var contorno= new google.maps.Polyline({
path: limite,
strokeColor: "#000000",
strokeOpacity: 1.0,
strokeWeight: 2
});
if(varControl==true){
contorno.setMap(mapa);
}
if(varControl==false){
contorno.setMap(null);
}
}
You only need to create the Polyline once. Put it into a global var contorno = ... Then you can create a toggle function using the setVisible(boolean) method.
if(contorno.getVisible()){
contorno.setVisible(false);
else{
contorno.setVisible(true);
}
// or
contorno.getVisible() ? contorno.setVisible(false) : contorno.setVisible(true);
Blow is an example which hides the path after 3 seconds.
/* 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;
}
<div id="map"></div>
<script>
// This example creates a 2-pixel-wide red polyline showing the path of William
// Kingsford Smith's first trans-Pacific flight between Oakland, CA, and
// Brisbane, Australia.
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 3,
center: {lat: 0, lng: -180},
mapTypeId: 'terrain'
});
var flightPlanCoordinates = [
{lat: 37.772, lng: -122.214},
{lat: 21.291, lng: -157.821},
{lat: -18.142, lng: 178.431},
{lat: -27.467, lng: 153.027}
];
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinates,
geodesic: true,
strokeColor: '#FF0000',
strokeOpacity: 1.0,
strokeWeight: 2
});
flightPath.setMap(map);
setTimeout(function() {
alert('hide path');
flightPath.setVisible(false);
}, 3000);
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>
Everytime your function is called, it creates a new polyline. Which is either added to the map or not.
Persumably you want be able to call the function once with true to add the line, then again with false to remove it. At the moment, when you call it a second time, its creates a new line and doesn't add it to the map. It does not touch the original line, already added to the map.
One way is too keep the line in a global variable. Then you can refer to the exact same object between calls.
var contorno = null;
function cargaMapaCYL(mapa, varControl){
if (!contorno) {
var limite = [...], "#000000", 5);
contorno= new google.maps.Polyline({...});
}
if(varControl){
contorno.setMap(mapa);
} else {
contorno.setMap(null);
}
}

Resources