Google Directions API - Route is blurred after a new request - javascript

here is a picture with the problem.
I am using Vue.js to consume a REST API that send data about upcoming bus transfers. In the picture above each list item represents a transfer and when clicked, the map should show the route. When switching from smaller to bigger is okay, but then when I switch to a shorter route, the blue line indicating it appears blurred and bigger than normal. The problem disappears when I zoom in/out, it's just the initial display.
I've tried the setZoom(int) function on the map object after every new request, but that didn't work.
Here's the relevant code from the Vue instance:
methods: {
...
calcRoute() {
const request = {
origin: this.start,
destination: this.end
}
this.directionsService.route(request, (result, status) => {
if (status == 'OK') {
this.directionsRenderer.setDirections(result);
//this.map.setZoom(12);
}
})
}
},
watch: {
start: () => {
if (this.end && this.start) {
this.calcRoute();
}
},
...
}
EDIT: as suggested, I've provided a running code snippet. Click the CHANGE DIRECTIONS button to see the problem.
EDIT 2: I've implemented it in pure JS for simplicity
EDIT 3: Provide your API KEY
const transfers = [{
"id": 29,
"date": "2020-02-12T08:00:00.000Z",
"pick_up": "Sofia Airport, Terminal 1",
"drop_off": "Stara Zagora",
"driver": "СТ",
"vehicle": 6264,
},
{
"id": 43,
"date": "2020-02-13T08:30:00.000Z",
"pick_up": "Sofia Terminal 1",
"drop_off": "Boutique One Hotel Sofia",
"driver": "СТ",
"vehicle": 6264,
}];
let map, directionsService, directionsRenderer;
let selectedTrans = 0;
window.addEventListener('load', function() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: 7,
center: {
lat: 42.698334,
lng: 23.319941
}
});
directionsService = new google.maps.DirectionsService();
directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
calcRoute();
});
function calcRoute() {
const start = transfers[selectedTrans].pick_up;
const end= transfers[selectedTrans].drop_off;
const request = {
origin: start,
destination: end,
travelMode: 'DRIVING'
};
directionsService.route(request, (result, status) => {
if (status == 'OK') {
directionsRenderer.setDirections(result);
}
})
}
document.getElementById('changeDirectionsBtn').addEventListener('click', () => {
selectedTrans = selectedTrans == 0 ? 1 : 0;
calcRoute();
});
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<button id="changeDirectionsBtn"> Change Directions </button>
<div id="map">
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY" defer></script>

I'd need to investigate this a bit further when I have some time...
The documentation mentions that
Because the renderer is an MVCObject, it will automatically detect any changes to its properties and update the map when its associated directions have changed.
and I am not sure about what that exactly means.
That said, simply calling directionsRenderer.setMap(null); before calculating the new route and directionsRenderer.setMap(map); in the callback fixes the issue. See the snippet below.
const transfers = [{
"id": 29,
"date": "2020-02-12T08:00:00.000Z",
"pick_up": "Sofia Airport, Terminal 1",
"drop_off": "Stara Zagora",
"driver": "СТ",
"vehicle": 6264,
},
{
"id": 43,
"date": "2020-02-13T08:30:00.000Z",
"pick_up": "Sofia Terminal 1",
"drop_off": "Boutique One Hotel Sofia",
"driver": "СТ",
"vehicle": 6264,
}];
let map, directionsService, directionsRenderer;
let selectedTrans = 0;
window.addEventListener('load', function() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: 7,
center: {
lat: 42.698334,
lng: 23.319941
}
});
directionsService = new google.maps.DirectionsService();
directionsRenderer = new google.maps.DirectionsRenderer();
calcRoute();
});
function calcRoute() {
directionsRenderer.setMap(null);
const start = transfers[selectedTrans].pick_up;
const end= transfers[selectedTrans].drop_off;
const request = {
origin: start,
destination: end,
travelMode: 'DRIVING'
};
directionsService.route(request, (result, status) => {
if (status == 'OK') {
directionsRenderer.setDirections(result);
directionsRenderer.setMap(map);
}
})
}
document.getElementById('changeDirectionsBtn').addEventListener('click', () => {
selectedTrans = selectedTrans == 0 ? 1 : 0;
calcRoute();
});
#map {
height: 100%;
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
<button id="changeDirectionsBtn"> Change Directions </button>
<div id="map">
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk" defer></script>

Related

Is there a way to open a popup input text after a polygon is created in leaflet?

I'm trying to make a web app that uses leaflet to display a map, users should be able to draw and edit polygons over the map and they should have the ability to name each polygon they create.
I want to open a popup when a polygon is created that asks for a name and then set it to a property in a geojson feature.
I tried to follow this example Leaflet popup form but I couldn't get it to work with the leaflet draw created event.
Here's what I got.
// Map center
var center = [-32.692825, -62.104689];
// Map creation
var map = L.map('map').setView(center, 14);
// Map tile layer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// Initialise the FeatureGroup to store editable layers
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
// Draw plugin options
var drawPluginOptions = {
position: 'topleft',
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#97009c'
}
},
// disable toolbar item by setting it to false
polyline: false,
circle: false, // Turns off this drawing tool
rectangle: false,
marker: false,
},
edit: {
featureGroup: editableLayers,
polygon: {
allowIntersection: false
} //REQUIRED!!
}
};
// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw(drawPluginOptions);
map.addControl(drawControl);
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
// draw created event handler
function polygonCreateHandler(e) {
var type = e.layerType;
var layer = e.layer;
if (type != 'polygon') {
alert("ESTO NO ES UN POLIGONO");
return;
}
editableLayers.addLayer(layer);
}
// draw created event
map.on('draw:created', function(e) {
polygonCreateHandler(e);
});
//Ignore this
/*jshint multistr: true */
var template = '<form id="popup-form">\
<label for="input-speed">New speed:</label>\
<input id="input-speed" class="popup-input" type="number" />\
<button id="button-submit" type="button">Save Changes</button>\
</form>';
/*
** fetch geojson example
let geojson_url = "https://raw.githubusercontent.com/delineas/leaflet-flyto-webpack-bulma/master/src/data/arboles_singulares_en_espacios_naturales.geojson"
fetch(
geojson_url
).then(
res => res.json()
).then(
data => {
let geojsonlayer = L.geoJson(data, {
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties['arbol_nombre'])
layer.setIcon(treeMarker)
}
}).addTo(map)
map.fitBounds(geojsonlayer.getBounds())
}
)
** layer polygon example
var geojson_msjz_polygon = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { "name": "Test Distrito electoral"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-62.103266716003425,
-32.687209099455636
],
[
-62.13047504425048,
-32.68211618935444
],
[
-62.133564949035645,
-32.693746380985395
],
[
-62.106142044067376,
-32.698838627713116
],
[
-62.103266716003425,
-32.687209099455636
]
]
]
}
}
]
};
let geojsonlayer = L.geoJson(geojson_msjz_polygon, {
onEachFeature: function(feature, layer) {
let text = L.tooltip({
permanent: true,
direction: 'center',
className: 'text'
})
.setContent(feature.properties.name)
.setLatLng(layer.getBounds().getCenter());
text.addTo(map);
}
}).addTo(map);
map.fitBounds(geojsonlayer.getBounds())
*/
#map {
height: 98vh;
width: 100hw;
}
body {
margin: 0;
}
html,
body,
#leaflet {
height: 100%;
}
.popup-table {
width: 100%;
}
.popup-table-row {
background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css" rel="stylesheet" />
<div id="map"></div>
Just bind a popup on the created layer and open it once it is created
function polygonCreateHandler(e) {
var type = e.layerType;
var layer = e.layer;
if (type != 'polygon') {
alert("ESTO NO ES UN POLIGONO");
return;
}
editableLayers.addLayer(layer);
layer.bindPopup(template).openPopup(); // here create and open the popup with your form
}
// Map center
var center = [-32.692825, -62.104689];
// Map creation
var map = L.map('map').setView(center, 14);
// Map tile layer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// Initialise the FeatureGroup to store editable layers
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
// Draw plugin options
var drawPluginOptions = {
position: 'topleft',
draw: {
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: '#e1e100', // Color the shape will turn when intersects
message: '<strong>Oh snap!<strong> you can\'t draw that!' // Message that will show when intersect
},
shapeOptions: {
color: '#97009c'
}
},
// disable toolbar item by setting it to false
polyline: false,
circle: false, // Turns off this drawing tool
rectangle: false,
marker: false,
},
edit: {
featureGroup: editableLayers,
polygon: {
allowIntersection: false
} //REQUIRED!!
}
};
// Initialise the draw control and pass it the FeatureGroup of editable layers
var drawControl = new L.Control.Draw(drawPluginOptions);
map.addControl(drawControl);
var editableLayers = new L.FeatureGroup();
map.addLayer(editableLayers);
var template = '<form id="popup-form">\
<label for="input-speed">New speed:</label>\
<input id="input-speed" class="popup-input" type="number" />\
<button id="button-submit" type="button">Save Changes</button>\
</form>';
var createdPolygonTemplate = '<form id="popup-form">\
<label for="input-speed">Name:</label>\
<input id="name" type="text" />\
</form>';
// draw created event handler
function polygonCreateHandler(e) {
var type = e.layerType;
var layer = e.layer;
if (type != 'polygon') {
alert("ESTO NO ES UN POLIGONO");
return;
}
editableLayers.addLayer(layer);
layer.bindPopup(createdPolygonTemplate).openPopup()
}
// draw created event
map.on('draw:created', function(e) {
polygonCreateHandler(e);
});
//Ignore this
/*jshint multistr: true */
/*
** fetch geojson example
let geojson_url = "https://raw.githubusercontent.com/delineas/leaflet-flyto-webpack-bulma/master/src/data/arboles_singulares_en_espacios_naturales.geojson"
fetch(
geojson_url
).then(
res => res.json()
).then(
data => {
let geojsonlayer = L.geoJson(data, {
onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties['arbol_nombre'])
layer.setIcon(treeMarker)
}
}).addTo(map)
map.fitBounds(geojsonlayer.getBounds())
}
)
** layer polygon example
var geojson_msjz_polygon = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": { "name": "Test Distrito electoral"},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-62.103266716003425,
-32.687209099455636
],
[
-62.13047504425048,
-32.68211618935444
],
[
-62.133564949035645,
-32.693746380985395
],
[
-62.106142044067376,
-32.698838627713116
],
[
-62.103266716003425,
-32.687209099455636
]
]
]
}
}
]
};
let geojsonlayer = L.geoJson(geojson_msjz_polygon, {
onEachFeature: function(feature, layer) {
let text = L.tooltip({
permanent: true,
direction: 'center',
className: 'text'
})
.setContent(feature.properties.name)
.setLatLng(layer.getBounds().getCenter());
text.addTo(map);
}
}).addTo(map);
map.fitBounds(geojsonlayer.getBounds())
*/
#map {
height: 98vh;
width: 100hw;
}
body {
margin: 0;
}
html,
body,
#leaflet {
height: 100%;
}
.popup-table {
width: 100%;
}
.popup-table-row {
background-color: grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.0.0-beta.2.rc.2/leaflet.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.2.3/leaflet.draw.css" rel="stylesheet" />
<div id="map"></div>
Yes, the next is a code example:
<div id="map" style="width: 100%; height: 500px;"></div>
<script>
var map = L.map('map', {
center: [18.9, -71.2],
zoom: 8,
});
const tileURL = 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png'
L.tileLayer(tileURL).addTo(map);
drawnItems = L.featureGroup().addTo(map);
var drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems,
},
});
var getName = function(layer) {
var name = prompt('please, enter the geometry name', 'geometry name');
return name;
};
map.addControl(drawControl);
map.on(L.Draw.Event.CREATED, function(e) {
var layer = e.layer;
var name = getName(layer);
if (name == 'geometry name') {
layer.bindPopup('-- no name provided --');
} else if (name == '') {
layer.bindPopup('-- no name provided --');
} else {
layer.bindTooltip(name, {permanent:true, direction:'top'})
};
drawnItems.addLayer(layer);
});
</script>
And this is the result:
enter image description here
Do not forget the cdn's:
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw-src.css" integrity="sha512-vJfMKRRm4c4UupyPwGUZI8U651mSzbmmPgR3sdE3LcwBPsdGeARvUM5EcSTg34DK8YIRiIo+oJwNfZPMKEQyug==" crossorigin="anonymous" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous"></script>

Google Maps API searching for places based on city using dropdown (select option) not working

hello I want to ask about google maps API. Previously, I was a beginner in using Google Maps API. I want to make a search for places by city using select option.
I've tried reading documentation and a few videos on youtube, other posts on stackoverflow, but none of them fit what I want.
I want to make maps like below. when I search by select option, the selected city will appear. And when i click on the marker, i will see place descriptions such as photos, place names, and descriptions.
Is it possible for me to make a feature like that? I really stuck with what I make, I've made some code like the one below. please help me, i really need your help.
let map;
let places;
let infoWindow;
let markers = [];
let autocomplete;
const countryRestrict = {
country: "tangerang"
};
const MARKER_PATH = "https://developers.google.com/maps/documentation/javascript/images/marker_green";
const hostnameRegexp = new RegExp("^https?://.+?/");
const cities = {
jakarta: {
center: {
lat: -6.186286,
lng: 106.822746
},
zoom: 12
},
tangerang: {
center: {
lat: -6.336135,
lng: 106.676924
},
zoom: 11
}
};
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
zoom: cities["tangerang"].zoom,
center: cities["tangerang"].center,
mapTypeControl: false,
panControl: false,
zoomControl: false,
streetViewControl: false,
fullscreenControl: false,
});
infoWindow = new google.maps.InfoWindow({
content: document.getElementById("info-content")
});
autocomplete = new google.maps.places.Autocomplete(
document.getElementById("autocomplete"), {
types: ["(cities)"],
componentRestrictions: countryRestrict
}
);
places = new google.maps.places.PlacesService(map);
autocomplete.addListener("place_changed", onPlaceChanged);
document.getElementById("country").addEventListener("change", setAutocompleteCountry);
}
function setAutocompleteCountry() {
const country = document.getElementById("country").value;
if (country == "all") {
autocomplete.setComponentRestrictions({
country: []
});
map.setCenter({
lat: 15,
lng: 0
});
map.setZoom(2);
} else {
autocomplete.setComponentRestrictions({
country: country
});
map.setCenter(cities[country].center);
map.setZoom(cities[country].zoom);
}
}
#mapsContent {
position: relative;
}
#mapsContent #controls {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
position: absolute;
left: 50%;
top: 5%;
-webkit-transform: translate(-50%, -5%);
transform: translate(-50%, -5%);
background-color: #fff;
padding: 10px 30px;
border-radius: 10px;
z-index: 9;
}
#mapsContent #controls .city {
padding-right: 30px;
border-right: 1px solid #acacac;
margin-right: 20px;
}
#contactContent #mapsContent #controls h4 {
color: #16215C;
font-size: 13px;
margin: 0;
}
#contactContent #mapsContent #controls #country {
border: none;
cursor: pointer;
}
#map {
position: relative;
width: 100%;
height: 900px;
background-color: #CACACA;
border-radius: 10px;
z-index: 0;
}
<div class="container-fluid">
<div class="row" id="mapsContent">
<div id="controls">
<div class="city">
<h4>Kota</h4>
</div>
<select id="country">
<option value="all">All</option>
<option value="jakarta">DKI Jakarta</option>
<option value="tangerang" selected>Tangerang</option>
</select>
</div>
<div id="map"></div>
</div>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=places&v=weekly" async defer></script>
In order to get achieve your desired results, you will have to make use of Place Details and Place photo requests. As indicated, after selecting a city, your known corporate places will show markers and infowindows that shows the details and initial photo of the place.
The places of each city are in a JSON object, however, it will only have each unique place ids. When you modify the JSON object, you can make use of the place id finder inputting your company address to get the place's unique place_id. It is alright to cache the place ID as indicated in the service specific terms of google
To also minimize costs further, you will see that I indicated the fields parameter to only get the data that you need. You can check all the available fields here.
Here is the JSFiddle sample for your reference: https://jsfiddle.net/pintsik999/0vjbep7h/
You can also see the code below:
"use strict";
let map;
let cities;
let markers = [];
var citiesObj = {
"cities": [{
"key": "DKI Jakarta",
"value": {
"city": "jakarta",
"center": {
"lat": -6.186286,
"lng": 106.822746
},
"zoom": 12,
//Since you know at least the address of the places, you can go here to get the unique place ID: https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder
"places": [{
"place_id": "ChIJB9Y8liH0aS4RemVuMOm5PFA"
},
{
"place_id": "ChIJA7dLFoL2aS4Rbu2LGxzIbAA"
}
]
}
}, {
"key": "Tangerang",
"value": {
"city": "tangerang",
"center": {
"lat": -6.336135,
"lng": 106.676924
},
"zoom": 11,
"places": [{
"place_id": "ChIJS3fhJPzkaS4RF8UTWV8LnLY"
}]
}
}]
}
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: -6.336135,
lng: 106.676924,
},
zoom: 10,
mapTypeControl: false,
panControl: false,
zoomControl: false,
streetViewControl: false,
fullscreenControl: false,
});
cities = document.getElementById("city");
cities.options.add(new Option('Select City', ''))
//value of cities are JSON objects to customize center and zoom of the map upon selection
for (var i = 0; i < citiesObj.cities.length; i++) {
cities.options.add(new Option(citiesObj.cities[i].key, JSON.stringify(citiesObj.cities[i].value)))
}
}
//add markers and infowindows on the places in the selected city
function cityChanged() {
//Hide/reset markers when city selection has changed.
deleteMarkers();
var selectedCity = JSON.parse(cities.value);
map.setCenter(new google.maps.LatLng(selectedCity.center));
//instantiate placedetail service
const service = new google.maps.places.PlacesService(map);
for (var i = 0; i < selectedCity.places.length; i++) {
const request = {
placeId: selectedCity.places[i].place_id,
//adding the fields parameter will allow you to specify the details that you only need so that you wont be billed unnecessarily for extra data that you don't use. Check all the available fields here: https://developers.google.com/maps/documentation/javascript/place-data-fields
fields: ["name", "formatted_address", "place_id", "geometry", "photos"],
};
service.getDetails(request, (place, status) => {
if (status === google.maps.places.PlacesServiceStatus.OK) {
addMarker(place);
}
});
}
}
function addMarker(place) {
var marker = new google.maps.Marker({
position: place.geometry.location,
map: map
});
addInfoWindow(marker, place);
markers.push(marker);
}
function addInfoWindow(marker, place) {
const infowindow = new google.maps.InfoWindow();
google.maps.event.addListener(marker, "click", function() {
infowindow.setContent(
"<img src='" + place.photos[0].getUrl() + " width='300' height='400'>" +
"<div><strong>" +
place.name +
"</strong><br>" +
"Place ID: " +
place.place_id +
"<br>" +
place.formatted_address +
"</div>"
);
infowindow.open(map, this);
});
}
function deleteMarkers() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
}
/* 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;
}
<!DOCTYPE html>
<html>
<head>
<title>Simple Map</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<!-- REPLACE API KEY PLACEHOLDER -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=places&v=weekly" defer></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div>
City:
<select id="city" onchange="cityChanged()">
</select>
</div>
<div id="map"></div>
</body>
</html>

google maps loadGeoJson change marker icon on click

I am loading the markers from a json file with loadGeoJson.
I can SET the marker icon/img on load, but I don't know how to CHANGE it on click.
how to target the clicked marker and do a setIcon or similar?
javascript:
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 6,
center: new google.maps.LatLng(2.8,-187.3),
mapTypeId: 'terrain'
});
map.data.loadGeoJson('geoJson2.json');
map.data.setStyle(function(feature) {
return {icon:feature.getProperty('icon')};
});
map.data.addListener("click", event => {
console.log(event.feature.getProperty("hicon"));
//CHANGE MARKER ICON -> event.feature.getProperty("hicon")
});
}
json:
{
"type":"FeatureCollection",
"features":[
{
"type":"Feature",
"properties":{
"name":"nameOne",
"icon":"marker1.png",
"hicon":"marker1HOVER.png",
"id":1
},
"geometry":{
"type":"Point",
"coordinates":[
-59.58984374999999,
-37.97884504049711
]
}
}
]
}
See the example of dynamic styling in the documentation.
map.data.setStyle(function(feature) {
var icon=feature.getProperty('icon');
if (feature.getProperty("isHighlighted"))
icon=feature.getProperty('hicon');
return {
icon: icon
};
});
map.data.addListener("click", event => {
if (!event.feature.getProperty("isHighlighted"))
event.feature.setProperty("isHighlighted", true);
else
event.feature.setProperty("isHighlighted", false);
console.log(event.feature.getProperty("hicon"));
//CHANGE MARKER ICON -> event.feature.getProperty("hicon")
});
proof of concept fiddle
code snippet:
"use strict";
let map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 6,
center: new google.maps.LatLng(-37.9788, -59.58984375),
mapTypeId: 'terrain'
});
map.data.addGeoJson(geoJson);
map.data.setStyle(function(feature) {
var icon = feature.getProperty('icon');
if (feature.getProperty("isHighlighted"))
icon = feature.getProperty('hicon');
return {
icon: icon
};
});
map.data.addListener("click", event => {
if (!event.feature.getProperty("isHighlighted"))
event.feature.setProperty("isHighlighted", true);
else
event.feature.setProperty("isHighlighted", false);
console.log(event.feature.getProperty("hicon"));
//CHANGE MARKER ICON -> event.feature.getProperty("hicon")
});
}
var geoJson = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"name": "nameOne",
"icon": "https://maps.google.com/mapfiles/ms/micons/blue.png",
"hicon": "https://maps.google.com/mapfiles/ms/micons/yellow.png",
"id": 1
},
"geometry": {
"type": "Point",
"coordinates": [-59.58984374999999, -37.97884504049711]
}
}]
};
/* 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;
}
<!DOCTYPE html>
<html>
<head>
<title>Data Layer: Styling</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=&v=weekly" defer></script>
<!-- jsFiddle will insert css and js -->
</head>
<body>
<div id="map"></div>
</body>
</html>

Showing map markers by location in list outside map

I have a number of markers and I want to show the markers in a list outside of the map. How can this be achieved using javascript? I am new to Javascript so help is appreciated. Code I have currently below, this is all working as expected apart from listing the map marker information.
I idea is that a list will appear depending on the option chosen in the dropdown for counties.
//List of Counties
var counties = [{
name: "Armagh",
code: "am",
zoom : 8,
center: {
lat: 54.274911,
lng: -6.626583
}
}, {
name: "Cork",
code: "c",
zoom : 8,
center: {
lat: 51.904246,
lng: -8.474038
}
}];
//List of Practices
var practice = [{
name: "Cross Veterinary Clinic",
position: {
lat: 54.07531,
lng: -6.60590
},
code: "am",
address: "8 Dundalk Road, Crossmaglen, Co. Armagh",
vet: "Carol Peterson",
programme: ['bvd', 'jd']
}, {
name: "Keltic Veterinary",
position: {
lat: 52.35386,
lng: -8.68204
},
code: "c",
address: "Charleville Town Centre, Bakers Road, Charleville, Co. Cork",
vet: "Gerald Gonzales",
programme: ['cck', 'bvd']
}];
var countyselect = document.getElementById('county')
countyselect.addEventListener("change", onCountySelect);
//render map
function initialize() {
var options = {
center: {
lat: 53.2734,
lng: -7.77832031
},
zoom: 6.5
};
map = new google.maps.Map(document.getElementById('map'), options);
marker = renderMarker();
}
function renderMarker() {
for (var i = 0; i < practice.length; i++) {
var marker = new google.maps.Marker({
position: practice[i].position,
title: practice[i].name,
map: map,
});
inforwindow(marker, map);
}
}
function inforwindow(marker, map) {
var infowindow = new google.maps.InfoWindow(); {
google.maps.event.addListener(marker, 'click', function(renderMarker) {
infowindow.setContent(marker.getTitle());
infowindow.open(map, marker);
});
}
}
function onCountySelect() {
let countySelect = document.getElementById("county");
let selectedCounty = countySelect.options[countySelect.selectedIndex];
let countyFound = (counties.find(({ name }) => name === selectedCounty.value));
if (selectedCounty.value === "all") {
map.setCenter({ lat: 53.2734, lng: -7.77832031 });
map.setZoom(6.5);
} else {
map.setCenter(countyFound.center);
map.setZoom(countyFound.zoom);
}
}
function resultsList() {
if (selectedCounty.value === "all") {
let countySelect = document.write(`<h3>${practice.name}</h3><p>${practice.address}</p><p>${practice.vet}</p>`);
}
}
I'm not sure at all from your code what your plan is with markers, or whether you intend to make items in the list clickable so that they highlight a specific marker on the map. But in any case, here's code to do what you asked - to create a list of relevant practices when a county is selected. I've dropped in some hacky test HTML just as it's easier to test.
Hopefully this will get you on the right path.
A couple of notes - you have used the backtick, ie using ` and ${variable} approach to rendering some content - this may not work on older browsers directly.
Also, please excuse the mix of single and double quotes - that's a matter of taste but I didn't see the point in going back and changing everything you had done. Good luck!
<!doctype html>
<html>
<head>
<title>Map Thing</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style type="text/css">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
font-family: Helvetica;
min-height: 100vh;
display: flex;
flex-direction: column;
}
#container {
flex: 1;
display: flex;
}
#options {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#results {
margin-top: 40px;
padding: 40px;
}
.result {
padding: 30px;
border: 1px solid #ddd;
}
#map {
flex: 3;
}
</style>
</head>
<body>
<div id="container">
<div id="options">
<select id="county" name="county" value="">
<option value="">Please choose</option>
<option value="am">Armagh</option>
<option value="c">Cork</option>
</select>
<div id="results"><!-- will be populated --></div>
</div>
<div id="map"></div>
</div>
<script>
//List of Counties
var counties = [{
name: "Armagh",
code: "am",
zoom : 8,
center: {
lat: 54.274911,
lng: -6.626583
}
}, {
name: "Cork",
code: "c",
zoom : 8,
center: {
lat: 51.904246,
lng: -8.474038
}
}];
//List of Practices
var practices = [{
name: "Cross Veterinary Clinic",
position: {
lat: 54.07531,
lng: -6.60590
},
code: "am",
address: "8 Dundalk Road, Crossmaglen, Co. Armagh",
vet: "Carol Peterson",
programme: ['bvd', 'jd']
}, {
name: "Keltic Veterinary",
position: {
lat: 52.35386,
lng: -8.68204
},
code: "c",
address: "Charleville Town Centre, Bakers Road, Charleville, Co. Cork",
vet: "Gerald Gonzales",
programme: ['cck', 'bvd']
}];
function initialize() {
var options = {
center: {
lat: 53.2734,
lng: -7.77832031
},
zoom: 6.5
};
map = new google.maps.Map(document.getElementById('map'), options);
var countyselect = document.getElementById('county');
countyselect.addEventListener('change', onCountySelect);
renderMarkers();
}
function renderMarkers() {
for (var i = 0; i < practices.length; i++) {
var marker = new google.maps.Marker({
position: practices[i].position,
title: practices[i].name,
map: map,
});
}
}
function showInfoWindow(marker, map) {
var infowindow = new google.maps.InfoWindow();
google.maps.event.addListener(marker, 'click', function() {
infowindow.setContent(marker.getTitle());
infowindow.open(map, marker);
});
}
function onCountySelect() {
var countySelect = document.getElementById("county");
var countiesByCode = counties.map(function(c){
return c.code;
});
var index = countiesByCode.indexOf(countySelect.value)
if (index > -1) {
var selectedCounty = counties[index];
map.setCenter(selectedCounty.center);
map.setZoom(selectedCounty.zoom);
renderResultsList(selectedCounty);
} else {
map.setCenter({ lat: 53.2734, lng: -7.77832031 });
map.setZoom(6.5);
clearResultsList();
}
}
function renderResultsList(selectedCounty) {
var relevantPractices = practices.filter(function(p){
return p.code === selectedCounty.code;
});
var resultsArea = document.getElementById("results");
resultsArea.innerHTML = "";
for(var i = 0; i < relevantPractices.length; i++) {
var practice = relevantPractices[i];
var div = document.createElement("div");
div.className = "result";
div.innerHTML = `<h3>${practice.name}</h3><p>${practice.address}</p><p>${practice.vet}</p>`;
resultsArea.appendChild(div);
}
}
function clearResultsList() {
document.getElementById("results").innerHTML = "";
}
</script>
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_KEY_HERE&callback=initialize"
async defer></script>
</body>
</html>

GoogleMaps MarkerClusterer InfoWindow Position

I have a problem with the position of the markercluster's infoWindow. It doesn't show up at the marker position. Instead it is positioned on the upper left corner of the map. Here is my code:
<script type="text/javascript">
function initialize(cities) {
var mapOptions = {
center: new google.maps.LatLng(48.220, 15.199),
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP,
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var markers=[];
var markerCluster = new MarkerClusterer(map, markers, {zoomOnClick: false});
//markerCluster should be always above the geocoder-->
geocoder = new google.maps.Geocoder();
for (var i = 0; i < cities.length; i++) {
var city = cities[i];
geocoder.geocode({'address': city.city+" Niederösterreich"}, function(results, status){
if (status == google.maps.GeocoderStatus.OK) {
position=results[0].geometry.location;
var marker = new google.maps.Marker({
map: map,
position: position,
title: "Ort: "+city.city + "\nBeitrag: " + city.title +"\nRed.: "+ city.reporter +"\nDatum: "+ city.storydate,
});
// below code alway lies inside the loop
markers.push(marker);
markerCluster.addMarker(marker);
}
});
};
// Listen for a cluster to be clicked
google.maps.event.addListener(markerCluster, 'clusterclick', function(cluster) {
var markers = markerCluster.getMarkers();
var content = '';
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
content += marker.title;
content += ("<br>");
};
// Convert lat/long from cluster object to a usable MVCObject
var info = new google.maps.MVCObject;
var infowindow = new google.maps.InfoWindow();
// infowindow.setPosition(this.markerCluster.getCenter());
// infowindow.setPosition(latLng);
infowindow.close();
infowindow.setContent(content);
infowindow.open(map, info);
google.maps.event.addListener(map, 'zoom_changed', function() { infowindow.close() });
});
}
</script>
Your MVCObject doesn't have any properties. According to the documentation, if you pass the optional anchor argument into the function .open, it must expose a LatLng position property, yours doesn't (as it doesn't have any properties, it can't expose any).
open(map?:Map|StreetViewPanorama, anchor?:MVCObject)
Return Value: None
Opens this InfoWindow on the given map. Optionally, an InfoWindow can be associated with an anchor. In the core API, the only anchor is the Marker class. However, an anchor can be any MVCObject that exposes a LatLng position property and optionally a Point anchorPoint property for calculating the pixelOffset (see InfoWindowOptions). The anchorPoint is the offset from the anchor's position to the tip of the InfoWindow.
The simplest solution is to not use the anchor argument, set the position of the infowindow directly.
google.maps.event.addListener(markerCluster, 'clusterclick', function (cluster) {
var markers = cluster.getMarkers();
var content = '';
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
content += marker.title;
content += ("<br>");
}
var infowindow = new google.maps.InfoWindow();
infowindow.setPosition(cluster.getCenter());
infowindow.setContent(content);
infowindow.open(map);
google.maps.event.addListener(map, 'zoom_changed', function () {
infowindow.close();
});
});
proof of concept fiddle
code snippet:
var geocoder;
var markers = [];
function initialize(cities) {
var mapOptions = {
center: new google.maps.LatLng(48.220, 15.199),
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
var markerCluster = new MarkerClusterer(map, markers, {
zoomOnClick: false,
imagePath: 'https://cdn.jsdelivr.net/gh/googlemaps/v3-utility-library#07f15d84/markerclustererplus/images/m'
});
//markerCluster should be always above the geocoder-->
geocoder = new google.maps.Geocoder();
for (var i = 0; i < cities.length; i++) {
var city = cities[i];
geocodeCity(city, markerCluster);
}
// Listen for a cluster to be clicked
google.maps.event.addListener(markerCluster, 'clusterclick', function(cluster) {
var markers = cluster.getMarkers();
var content = '';
for (var i = 0; i < markers.length; i++) {
var marker = markers[i];
content += marker.title;
content += ("<br>");
}
var infowindow = new google.maps.InfoWindow();
infowindow.setPosition(cluster.getCenter());
infowindow.close();
infowindow.setContent(content);
infowindow.open(map);
google.maps.event.addListener(map, 'zoom_changed', function() {
infowindow.close();
});
});
}
function geocodeCity(city, markerCluster) {
geocoder.geocode({
'address': city.city + " Niederösterreich"
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
position = results[0].geometry.location;
var marker = new google.maps.Marker({
map: map,
position: position,
title: "Ort: " + city.city + "\nBeitrag: " + city.title + "\nRed.: " + city.reporter + "\nDatum: " + city.storydate
});
// below code alway lies inside the loop
markers.push(marker);
markerCluster.addMarker(marker);
} else {
document.getElementById('info').innerHTML += city.city + " status=" + status + "<br>";
}
});
}
google.maps.event.addDomListener(window, "load", function() {
initialize(cities);
});
var cities = [{
city: "Sankt Polten",
title: "title 0",
reporter: "reporter 0",
storydate: "November 25,2015 00:00:00"
}, {
city: "Wiener Neustadt",
title: "title 1",
reporter: "reporter 1",
storydate: "November 25, 2015 01:01:01"
}, {
city: "Baden",
title: "title 2",
reporter: "reporter 2",
storydate: "November 25,2015 02:02:02"
}, {
city: "Klosterneuburg",
title: "title 3",
reporter: "reporter 3",
storydate: "November 25, 2015 03:03:03"
}, {
city: "Krems",
title: "title 4",
reporter: "reporter 4",
storydate: "November 25,2015 04:04:04"
}, {
city: "Amstetten",
title: "title 5",
reporter: "reporter 5",
storydate: "November 25, 2015 05:05:05"
}, {
city: "Modling",
title: "title 6",
reporter: "reporter 6",
storydate: "November 25,2015 06:06:06"
}, {
city: "Traiskirchen",
title: "title 7",
reporter: "reporter 7",
storydate: "November 25, 2015 07:07:07"
}, {
city: "Schwechat",
title: "title 8",
reporter: "reporter 8",
storydate: "November 25,2015 08:08:08"
}, {
city: "Ternitz",
title: "title 9",
reporter: "reporter 9",
storydate: "November 25, 2015 09:09:09"
}, {
city: "Stockerau",
title: "title 10",
reporter: "reporter 10",
storydate: "November 25,2015 10:10:10"
}];
html,
body,
#map {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<script src="https://cdn.jsdelivr.net/gh/googlemaps/v3-utility-library#07f15d84/markerclustererplus/src/markerclusterer.js"></script>
<div id="info"></div>
<div id="map"></div>

Categories