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!
Related
I am getting data from Algolia and have a map showing the results using Leaflet when a user searches the results update, the map does too but the markers are not removed and therefore more markers are added to the page.
I assumed that markers.forEach(marker => marker.remove()); would remove my markers but that is not the case.
search.addWidget(
instantsearch.widgets.hits({
container: '#hits',
images: {
},
templates: {
item: document.getElementById('hit-template').innerHTML,
empty: "We didn't find any results for the search <em>\"{{query}}\"</em>"
},
transformItems: function(items) {
renderMap(items);
return items.slice(0, curentResultsPerPage);
},
})
);
const map = L.map(
'mapid', {
renderer: L.canvas(),
zoom: 18,
keepInView: true,
dragging: !L.Browser.mobile,
}
).setMaxZoom(18).setMinZoom(2);
L.mapboxGL({
attribution: '© MapTiler © OpenStreetMap contributors',
accessToken: 'not-needed',
style: 'https://maps.tilehosting.com/c/acad0958-1cbc-46ac-a497-681525e8ca19/styles/streets/style.json?key=iVyYurApGpcJs6fpSZIZ',
}).addTo(map);
let markers = [];
function renderMap(items) {
// remove current markers
markers.forEach(marker => marker.remove());
// clear the markers
markers = [];
// create cluster group
var clusters = L.markerClusterGroup({
chunkedLoading: true,
showCoverageOnHover: false,
});
// iterate through search results
for (var i = 0; i < items.length; i++) {
// get result
var item = items[i];
var geo = item._geoloc;
// create marker
var marker = L.marker([geo.lat, geo.lng], {icon: myIcon});
// create marker popup
marker.bindPopup(item.title);
// add the marker to the markers array
markers.push(marker);
// add the marker to the cluster group
clusters.addLayer(marker);
}
// add the cluster group to the map
map.addLayer(clusters);
if (markers.length) {
map.fitBounds(L.featureGroup(markers).getBounds());
}
}
search.start();
The issue is that the Leaflet Markers in your markers array are actually managed by your clusters Marker Cluster Group. The latter handles the addition and removal of your Markers on its own. Therefore clustered Markers are already removed from your map, and your marker.remove() will do nothing, or temporarily remove the Marker from the map until clusters adds it back.
If markers has the sams list of Markers as in clusters, then simply use the latter instead:
clusters.clearLayers() to get rid of all Markers.
clusters.getBounds() to fit your map to the extent of your Markers.
var cityMarkers = [
{
id: "bliss",
name: "Principality of Bliss",
icon: cityIcon,
coords: [-90.19, -76.90]
},
{
id: "cantonia",
name: "Grand City of Cantonia",
icon: cityIcon,
coords: [-39.513421, -69.09375]
},
{
id: "mithril",
name: "Grand City of Mithril ",
icon: cityIcon,
coords: [42, -102.5]
}];
I have the above in a separate file for referencing from my app.js file.
cityMarkers.forEach(function(item) {
var marker = L.marker(item.coords, {icon : item.icon});
marker.bindTooltip("<b>" + item.name + "<b>", {permanent: true, offset:
[60, 0]});
This will make the markers and the other properties, but it won't put them on the map. An array handles placing them on the map, so this doesn't help me much with what I am really trying to do.
This is a map based on the leaflet library. I am trying to assign a variable to each city with the id. Then, after the markers are made and attached to their variables, I want to make an array out of those names to function as the data layer. I admit that I am out of my depth, here. Any guidance would be most appreciated. I linked the documentation below in case anyone wants it.
https://leafletjs.com/reference-1.3.4.html
I did research the question, but I was unable to find any results that answered what I think I am asking. I would highly prefer a nudge over a flat answer. I don't understand how to instantiate the variables and bind them to the markers. Thank you for your time.
Instead of adding the markers directly to the map, add them to a L.layerGroup. You can add the layerGroup to the map and remove it again at will.
var lg = new L.layerGroup();
cityMarkers.forEach(function(item) {
var marker = L.marker(item.coords, {icon : item.icon});
marker.bindTooltip("<b>" + item.name + "<b>", {permanent: true, offset:
[60, 0]})
.addTo(lg)});
lg.addTo(map); // Add the layerGroup the map
lg.removeFrom(map); // Remove the layerGroup from the map
I think you can try adding .addTo(map)
cityMarkers.forEach(function(item) {
var marker = L.marker(item.coords, {icon : item.icon});
marker
.bindTooltip("<b>" + item.name + "<b>", {permanent: true, offset: [60, 0]})
.addTo(map);
Demo for adding multiple markers to leaflet.
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.
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,
});
}
I have a basic markerclusterer example which works very well.
var center = new google.maps.LatLng(37.4419, -122.1419);
var options = {
'zoom': 13,
'center': center,
'mapTypeId': google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map"), options);
var markers = [];
for (var i = 0; i < 100; i++) {
var latLng = new google.maps.LatLng(data.photos[i].latitude,
data.photos[i].longitude);
var marker = new google.maps.Marker({'position': latLng});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
What I would like to do is cluster the markers by country and then once you click on it they are still clustered until on3 further click. Currently they are clustered until you are down to one result. I have thousands of markers and would like them visible after one country click and then one more click.
I looked for a solution online and found this http://google-maps-utility-library-v3.googlecode.com/svn/tags/markermanager/1.0/examples/google_northamerica_offices.html
which is produced using this
var officeLayer = [
{
"zoom": [0, 3],
"places": [
{ "name": "US Offices", "icon": ["us", "flag-shadow"], "posn": [40, -97] },
{ "name": "Canadian Offices", "icon": ["ca", "flag-shadow"], "posn": [58, -101] }
]
},
...
};
function setupOfficeMarkers() {
allmarkers.length = 0;
for (var i in officeLayer) {
if (officeLayer.hasOwnProperty(i)) {
var layer = officeLayer[i];
var markers = [];
for (var j in layer["places"]) {
if (layer["places"].hasOwnProperty(j)) {
var place = layer["places"][j];
var icon = getIcon(place["icon"]);
var title = place["name"];
var posn = new google.maps.LatLng(place["posn"][0], place["posn"][1]);
var marker = createMarker(posn, title, getIcon(place["icon"]));
markers.push(marker);
allmarkers.push(marker);
}
}
mgr.addMarkers(markers, layer["zoom"][0], layer["zoom"][1]);
}
}
mgr.refresh();
updateStatus(mgr.getMarkerCount(map.getZoom()));
}
I'm not sure how to implement this into what I've currently got and if i need to include any other scripts/ libraries also.
You are looking at two totally different libraries, there. Your question is about the MarkerClusterer library, but your example solution is about the MarkerManager library.
The MarkerClusterer library automatically clumps markers together based on an algorithm that tries to decide when too markers would be so close together that you can't visibly distinguish one from another. You don't really have a lot of control over when and how it decides to merge markers together this way, so this library is idea when it doesn't matter to you how they get merged, as long as merging happens. Since you want to merge markers together by political boundaries (countries) and not by proximity to each other, this is not the library for you.
The MarkerManager library does not automatically merge markers together at all. What it does do is to selectively hide and reveal markers based on the zoom level of the current map viewport. What you would need to do is do your own merging, and then add to the MarkerManager all of the merged markers, as well as the detail markers, and the zoom levels where you want each marker to be visible. Doing your own merging means you will need an alternate way of determining which country each marker point falls within. Hopefully, you already know (or can get) that information, because it's not automatically provided by any of these libraries.
tl;dr - use the MarkerManager library and not the MarkerClusterer library for grouping by countries, and it's up to you to identify the location for each country and which marker goes with which one.