My code to make markers:
for (var marker in markers) {
var posMarker = new google.maps.Marker({
position: new google.maps.LatLng(markers[marker].lat, markers[marker].lng),
map: map,
visible: markers[marker].visible
});
};
My markers object:
var markers = {
"London": {"lat": -83.68088192646843, "lng": -125.270751953125, "type": "town", "visible": false},
"Paris": {"lat": -58.1548020417031, "lng": -21.318115234375, "type": "town", "visible": false},
};
I'm trying to be able to toggle the markers with a checkbox like so:
$('#toggle').change(function() {
for (var marker in markers) {
posMarker.setVisible(true);
};
});
But only the last marker in the array is shown, how do I make all of them appear?
Thanks.
Well, I see posMarker being used as a temporary variable that places a Google Maps marker, and as the for loop progresses, the posMarker reference "updates" to the latest marker placed. That's why only the last marker is being shown.
You need to keep track of all references to Google Maps markers being placed, including those that have been "consumed". My approach uses an object, much like your markers object but holding references to Google Maps markers. You could also use a plain indexed array (posMarkers[]). It's up to you.
See the Demo, note the LatLngs have been modified for simplicity (looks like you have a custom coordinate system).
Also, I didn't make this change, but I just noticed that it may make more sense to call marker in markers, city in markers because the way your object is written. It would be more readable, but won't affect the execution.
Finally, semicolons at the end of for loops blocks are unneeded, and be careful with the trailing comma after the Paris object (I'm guessing you just erased the rest of the list). In this case it didn't matter, but other times these trailing commas can be a source of hard-to-find bugs.
function initialize() {
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
var markers = {
"London": { "lat": 0, "lng": 0, "type": "town", "visible": false },
"Paris": { "lat": 10, "lng": 10, "type": "town", "visible": false }
};
var posMarkers = {};
for (var marker in markers) {
posMarkers[marker] = new google.maps.Marker({
position: new google.maps.LatLng(markers[marker].lat, markers[marker].lng),
map: map,
visible: markers[marker].visible
});
}
$('#toggle').change(function () {
for (var marker in markers) {
if (posMarkers[marker].getVisible()) {
posMarkers[marker].setVisible(false);
}
else {
posMarkers[marker].setVisible(true);
}
}
});
}
Related
GIS data and python are old hat to me but I am very new to web development and geospatial web applications.
I have followed a tutorial and a class that I am taking to get to the below script but I cannot get the resulting geojson object (the polygon layer) to display within leaflet. I can however, log all of the features of the polygon layer to the console. Furthermore, within the console I can clearly see the correct type, properties, and coordinate arrays of the geojson object. I can also clearly see all of the features within the leaflet map object within the console.
Any input would be greatly appreciated. If needed I will be happy to post the getData.php code. I just don't think that is the problem.
var map,
fieldsin = ["campus_nam", "status", "schnumber", "type"],
autocomplete = [];
$(document).ready(initialize);
function initialize(){
map = L.map("mapdiv", {
center: [36.10, -80.25],
zoom: 12
});
var backgroundLayer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png').addTo(map);
//adding postgresql layers to map with getData.php
getData(fieldsin);
};
function getData(fieldsin){
$.ajax({
url: "php/getData.php",
data: { table: "public.school_campus", fields: fieldsin },
success: function(data){
mapData(data);
}
})
};
function mapData(data){
//remove existing map layers
map.eachLayer(function(layer){
//if not the tile layer
if (typeof layer._url === "undefined"){
map.removeLayer(layer);
}
})
//create geojson container object
var geojson = {
"type": "FeatureCollection",
"features": []
};
//split data into features
var dataArray = data.split(", ;");
//pop off the last value of the array because it is an empty string.
dataArray.pop();
//build geojson features
dataArray.forEach(function(d){
d = d.split(", "); //split the comma seperated data string up into individual attribute values
var test = d[fieldsin.length].concat("}");
//feature object container
var feature = {
"type": "Feature",
"properties": {}, //properties object container
//"geometry": JSON.parse(d[fieldsin.length]) //parse geometry
"geometry": JSON.parse(d[fieldsin.length]) //parse geometry
};
//bulding properties for properties container above
for (var i=0; i<fieldsin.length; i++){
feature.properties[fieldsin[i]] = d[i];
};
//add feature names to autocomplete list
if ($.inArray(feature.properties.campus_nam, autocomplete) == -1){
autocomplete.push(feature.properties.campus_nam);
};
//console.log(feature.geometry)
geojson.features.push(feature);
//var campusLayer = L.geoJSON(geojson).addTo(map);
var campusLayer = L.geoJSON(geojson, {
style: {
fillColor: "#CC9900",
color: "#66ffff",
weight: 1
},
onEachFeature: function (feature, layer) {
var html = "";
for (prop in feature.properties){
html += prop+": "+feature.properties[prop]+"<br>";
};
layer.bindPopup(html);
}
}).addTo(map);
});
};
Adding a sample of your resulting GeoJSON object would have surely helped in understanding your situation.
However I highly suspect that you have simply inverted the coordinates:
Leaflet expects [latitude, longitude] order
GeoJSON expects [longitude, latitude] order
See also https://macwright.org/lonlat/
Therefore there is a very high chance your Leaflet GeoJSON Layer Group is actually added onto your map, but you would have to zoom out to see your features on a completely different place and distorded.
Looks like you also have not specified the appropriate CRS to your Leaflet map instance, or you need to convert the coordinates from your backend to the Leaflet's default EPSG:3857.
Note that the GeoJSON spec requests WGS84 CRS, which is the same input for EPSG:3857.
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 have a Google Maps script in this format:
function initMap()
{
var mapDiv = document.getElementById('map');
var map = new google.maps.Map(mapDiv, {center: {lat: 45.9, lng: 25.0}, zoom:7,
mapTypeId: google.maps.MapTypeId.ROADMAP, disableDoubleClickZoom:true, scrollwheel:false, ...});
var marker = new google.maps.Marker({position: {lat:46.1, lng:25.4}, map:map, icon:'../images/Marker.png});
}
I'd like to know how the var marker part of the script must look like if there were more than one points to be displayed. Note: I have seen JavaScript examples on StackExchange which use arrays etc. - one of the best is here: Google Maps Script - but I want my script to use the format above, which is very simple.
The google.maps.Marker class can only create a marker for a single point at at time, so you'll need some way to repeat that for all your points.
I'd say have an array of objects, each of which has the latitude and longitude values as separate properties. And any other properties you might want to associate with all your points, such as titles and icons. e.g.
var places = [
{
latitude: 46.1,
longitude: 25.4
title: "Place 1",
icon: "blue.png"
},
{
latitude: 54.1,
longitude: 0.0
title: "Place 2"
icon: "red.png"
},
// etc
];
Then when you want to create the markers, just loop over the array:
for (var i = 0; i < places.length; i++) {
marker = new google.maps.Marker({
position: {lat:places[i].latitude, lng: places[i].longitude},
title: places[i].title,
map: map,
icon: '../images/' + places[i].icon
});
}
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.