I'm trying to use JavaScript and the Google Maps API to plot a number of markers on a map; I have a large array of objects containing key-value pairs as follows:
xyz: [ { name: 'abc', loc: { lat: 0.000000, lng: 0.000000 } }, ... , ... ]
I have a For-Loop that iterates through this array and plots a marker at xyz.loc for each object in the array (see below). Now, I'm trying to change the icon used for each marker based on the xyz.name property.
I've defined two different custom marker icons and their associated shape (xyzMarkerIcon1, xyzMarkerIcon2 and xyzMarkerShape) and I'm trying to switch which one is used using an If-Else statement as follows:
var xyzMarkerIcon = {};
for (i in xyz) {
if (xyz[i].name = 'abc') {
xyzMarkerIcon = xyzMarkerIcon1
}
else {
xyzMarkerIcon = xyzMarkerIcon2
}
xyzMarkerArray[i] = new google.maps.Marker({
map: map,
position: xyz[i].loc,
icon: xyzMarkerIcon,
shape: xyzMarkerShape,
});
}
The For-loop works fine, but the If-Else statement seems to be overlooked after the first iteration; all of the objects in the array are plotted successfully but all using the first instance of xyzMarkerIcon.
I feel like this should be a simple enough problem, but I just can't figure it out! Thanks for your help!
You forgot the == 'abc'
var xyzMarkerIcon = {};
for (i in xyz) {
if (xyz[i].name == 'abc') {
xyzMarkerIcon = xyzMarkerIcon1
}
else {
xyzMarkerIcon = xyzMarkerIcon2
}
xyzMarkerArray[i] = new google.maps.Marker({
map: map,
position: xyz[i].loc,
icon: xyzMarkerIcon,
shape: xyzMarkerShape,
});
}
Related
I want to find and remove marker based on it's coordinates. Or remove all the markers in the given geometry. There are few solutions I'm aware of. First is to store all the markers in a map or array, and the second is to remove whole level with markers and add another one (updated) - both of this solutions are not performance friendly if we talking about thousands of markers. And I didn't found a way to get a marker by it's coordinates natively.
I'd be glad if someone had any ideas about it. Thank you for the attention!
I've finished with a structure like this for adding and removing markers:
let markerSet = {}
const saveMarker = (coords, marker) => {
const [ key1, key2 ] = coords
markerSet = {
...markerSet,
[key1]: {
...markerSet[key1],
[key2]: marker
}
}
}
const removePointer = (coords) => {
const [ key1, key2 ] = coords
const marker = markerSet[key1][key2]
if (!marker)
return
markers.removeLayer(marker)
delete markerSet[key1][key2]
}
coords is latlng array
I hope for a bit support about my following javascript code:
// Initialize Firebase
var config = {
apiKey : "AIzaSyBRC2kza6jhghEFNr5dteVpw2kB9mxqrU8",
authDomain : "formulaire-7fba1.firebaseapp.com",
databaseURL : "https://formulaire-7fba1.firebaseio.com",
projectId : "formulaire-7fba1",
storageBucket : "formulaire-7fba1.appspot.com",
messagingSenderId: "548100244430"
};
firebase.initializeApp(config);
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 0, lng: 0},
zoom: 3,
styles: [{
featureType: 'poi',
stylers: [{ visibility: 'off' }] // Turn off points of interest.
}, {
featureType: 'transit.station',
stylers: [{ visibility: 'off' }] // Turn off bus stations, train stations, etc.
}],
disableDoubleClickZoom: true
});
}
// Loop through users in order with the forEach() method. The callback
// provided to forEach() will be called synchronously with a DataSnapshot
// for each child:
var query = firebase.database().ref("client").orderByKey();
query.once("value").then(function(snapshot) {
var position = [];
snapshot.forEach(function(childSnapshot) {
// key will be "ada" the first time and "alan" the second time
var key = childSnapshot.key;
// childData will be the actual contents of the child
var childData = childSnapshot.val();
position.push(childData.lat + " " + childData.lng);
console.log(position);
});
});
I'm trying to get the array, that's filled with GPS position as a strings, into the google map, as markers. Tried several methods but none works. Can anyone can give me a tip or an direction?
Thanks!
If position is the array that will hold your coordinates. You need to make sure the array elements inside follow a latLng object or what the marker.position property would recognize. Usually it would follow this format:
var latLngObj = {lat: -25.363, lng: 131.044};
You can use your forEach loop to already add a marker per iteration. Before/Aftter pushing the coordinates to the position array do something like:
var marker = new google.maps.Marker({
position: {lat: childData.lat, lng:childData.lng},
map: map
});
I'm not sure how childData actually looks like, as you didn't give that info, but assuming it's a double like -25.363 and not a string, then it will be fine.
You might also want to define your map variable globally so that your functions can recognize it at the part of map: map as you're only defining the map variable inside your initMap function.
Here's the documentation that may guide you on how to add a marker to the map. Just use an iteration (e.g. for loop) to add multiple markers. You'll also see how to delete them in the same documentation.
Also found a relevant stackoverflow post on properly looping to create your markers.
Hope that helps!
I'm doing a dynamic map using the Google Maps API that uses the markers to mark a list of predefined locations, such as:
self.locations = [{
name: 'Foxtrot',
lat: 38.713905,
lng: -9.1518868,
type: 'Bar'
}
It also has a Search field that allows you to filter by the name of the locations (filteredNav). It should also filter the markers, but...that is the problem.
The recommendation that I have is the following:
Try writing console.log(self.location_array());.Because location and
marker data modal is separate, you'll have to loop through
self.location_array() to process and find which one to show, which one
to hide by calling setVisible (or setMap) on the marker object.
This is my code:
// Create observable array
self.nav = ko.observableArray(self.locations);
// Create empty observable string
self.filter = ko.observable('');
// Show nav and filter
self.filteredNav = ko.computed(function() {
var filter = self.filter().toLowerCase();
if (!filter) {
return self.nav();
}
return self.nav().filter(function(i) {
// Check for proper casing or lowercase
return i.name.toLowerCase().indexOf(filter) > -1 || i.name.indexOf(filter) > -1;
});
//THIS IS THE PROBLEM!
for (var i = 0; i < location_array()[i].length; i++) {
//??????
location_array()[i].setVisible(true);
}//?????
}
note: observable array implementation: vm.location_array()[i]
Link to the project
So...the question is...how can I do the loop? I've no idea how to do it....
First of all, the code you have presented has some 'mysterious' parts. For example, what is self, what is ko, what is observableArray etc. One can only guess what each of these are.
So I will simply describe to you the general logic of how to achieve what you want.
The logic is pretty straightforward.
The same way you filter the places in the sidebar, when you type, you should filter the array of markers to call setVisible with true or false
This means, that when you create the markers, you should store them to a separate array.
Also, when you create a marker, e.g.
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(latitude, longitude)
})
Add a name property, or something similar, to it, like so
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(latitude, longitude),
name: 'Foxtrot`
})
so that your created marker has a name property, which you can use to filter your array of markers.
Thus, in order to filter your markers array, you should simply iterate over the array and check the .name property of each marker object, and if the name does not match the search input, simply setVisible(false) on the marker, otherwise do setVisible(true)
Hope this helps.
having a very strange problem.
A: One method of my map works fine. User sets start point and end point and map is created and the fitBounds.extend(bounds) sets zoom level appropriately to encompass the start/end markers on the map.
B: The second method is if the user sets a start point but not and end point, but based on other user interests I get retrieve and end point for them and plot it on the map using the same functions as method A. However, upon fitBounds.extend(bounds) it sets the zoom level way out at 4 (country level). Then I have to force set the zoom.
It doesn't matter when at any point the user does method A (before or after method B)...when its method A, the zoom level is correct. When its method B its always to zoom level 4.
...but all using the same functions.
Both methods accurately put the markers on the map and accurately draw the route between the markers. Just on method A, the auto zoom is correct and on method B the zoom is always set to 4.
If user does A, its right...then B happens, its zooms out...does B again it stays zoomed out...does A again it goes back to proper zoom.
Driving me nuts here!
My map object is "setMap", it is a global var
function setMapBounds(start,end) {
mapBounds = new google.maps.LatLngBounds();
mapBounds.extend(start.position);
mapBounds.extend(end.position) ;
setMap.fitBounds(mapBounds) ;
}
function addMarkers(newMarkers) { // an array of map points.
var tempMarkers = [] ;
for (var x=0;x<newMarkers.length;x++) {
var tempLatlon = new google.maps.LatLng(newMarkers[x].lat,newMarkers[x].lon) ;
var tempMarker = createMarker(tempLatlon,newMarkers[x].img,newMarkers[x].title) ;
tempMarkers.push(tempMarker) ;
}
return tempMarkers ;
}
function createMarker(latlon,img,title) {
var marker = new google.maps.Marker({
map:setMap,
position:latlon,
icon: img,
title:title
}) ;
return marker ;
}
// This is Method A - it ALWAYS sets the zoom properly
function setDropoff(dropoffLoc) { //called from: index.js/setPickup(), tab-map.html
geoCoder.geocode({'address': dropoffLoc}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
if (results[0]) {
endLocation = dropoffLoc ;
endLat = results[0].geometry.location.lat() ;
endLon = results[0].geometry.location.lng() ;
// first clear any existing END Markers only.
while(markersArray.length) {
markersArray.pop().setMap(null);
}
endPointSet = 1 ;
endLatlon = new google.maps.LatLng(endLat,endLon) ;
var endMarker = createMarker(endLatlon,'img/red-pin.png','Drop off') ;
markersArray.push(endMarker) ;
setMapBounds(userMarker,endMarker) ;
if (startPointSet == 1) {
drawRoute("DRIVING",startLocation,endLocation) ;
}
}
} else {
error = "Address not found."
}
});
}
// This is method B, it ALWAYS pushees the zoom out to 4. It is pulled out of another function that tests to see if the user manually set and end point...if so, then add wayPoints between user set start/end points. If not, then set map to user start point to a single end point of interest
if (endPointSet == 1) { // draw Pickup to START to wayPoints to END
var markers = [
{lat:interests[0].shub_lat,lon:interests[0].shub_lon,img:interests[0].img,title:"Pickup"},
{lat:interests[1].ehub_lat,lon:interests[1].ehub_lon,img:interests[1].img,title:"Dropoff"}
] ;
var points = [interests.shub_address,interests.ehub_address] ;
extraMarkers = addMarkers(markers) ;
drawRoute("BICYCLING",startLocation,endLocation,points) ;
} else {
var markers = [
{lat:interests[0].shub_lat,lon:interests[0].shub_lon,img:interests[0].img,title:"Dropoff"}
] ;
extraMarkers = addMarkers(markers) ;
setMapBounds(userMarker,extraMarkers[0]) ;
drawRoute("WALKING",startLocation,interests[0].shub_address) ;
}
}
Here is are the objects passed into setMapBounds from the else within Method B. Start point is set by User...but no end point is set, I am picking one for them. The first Object is start, the second object is end.
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 563, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.49799999999999
k: 27.873196
...
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 602, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.47631678090198
k: 27.9374560148825
...
And here are the objects passed into setMapBounds from Method A where the user is setting both the same start and end points. you can see the start point is the same for both Method A and B.
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 563, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.49799999999999
k: 27.873196
...
Lh {__gm: Object, gm_accessors_: Object, map: Qk, closure_uid_909815000: 703, gm_bindings_: Object…}
Lf: Object
...
position: pf
D: -82.45717760000002
k: 27.950575
...
I am making a similar application, and the code that I am using is:
var start;
var end;
function updateMap(name, obj){ //obj is a form input i.e. <input type="text">
var marker = (name==='start')?start:end;
geocoder.geocode({address:obj.value}, function(results, status){
//get coords/check if is valid place
if(status === google.maps.GeocoderStatus.OK){
//get info, store in new marker
marker.setPosition(results[0].geometry.location);
marker.setTitle(obj.value);
//if both markers present
if(start.getPosition() && end.getPosition()){
map.fitBounds(new google.maps.LatLngBounds(start.getPosition(), end.getPosition()));
}else{
//otherwise, if one marker
map.setCenter(marker.getPosition());
map.setZoom(15);
}
marker.setMap(map);
}else if(status === google.maps.GeocoderStatus.ZERO_RESULTS){
alert('There is an issue with address. Please refer to the "Help" link.');
}else{
setTimeout(function(){
updateMap(marker, obj);
}, 200);
}
});
}
What this does is take an argument from a text input, geocode it, and place a marker on the map. The function is triggered by an onchange event on the form element. This can be easily adapted for your own usage. If there was only one point, I just settled for a default zoom value (usually pretty close to the street, though you can adjust this however you want).
As for your question of why it is not working, I can formulate a better guess with the entire code. For now, I would think it has something to do with region-biasing, or that it is simply a bug. It is probably just best to work around it.
I'm developing an app with Google maps that should display several categories on a map. Now I would like to have the possibility to add markers from several categories and delete them as well if necessary.
I've managed to figure out the whole thing. At least, almost... I'm having troubles with the removal of the markers of a category. I've created a live demo on jsfiddle to make this clear.
So here's how I attempt to do this:
CODE
First I initialize the map, etc. (but that is not relevant here). Then I add the markers on the map:
for(i in markers){
var marker = new google.maps.Marker({
map: map,
draggable: false,
position: new google.maps.LatLng(markers[i].latitude, markers[i].longitude),
visible: true,
data: category
});
newMarkers.push(marker);
}
As you can see I have 'data: category' in the object. This is something that's not google maps api, but it gives me no errors and gives me the possibility to search the array when I want to remove the markers. Here the removeMarker function:
function removeMarkers(category)
{
for(i in newMarkers) {
if(newMarkers[i]['data'] == category){
count ++;
newMarkers[i].setMap(null);
newMarkers.splice(i, 1);
}
}
}
It does remove markers, but not all of them...
Does anyone have solution to my problem?
LIVE DEMO
Thanks in advance,
Helena S.
Seems like the problem is that you are iterating the newMarkers array and at the same time removing elements from it.
Try this instead. It only sets the removed marker values in the array to null then, after the loop, filters those null values:
for(i in newMarkers) {
if(newMarkers[i]['data'] == category){
count ++
newMarkers[i].setMap(null);
newMarkers[i] = null;
}
}
newMarkers = newMarkers.filter(function(val){ return !!val; });
http://jsfiddle.net/GJUcy/