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.
Related
To allow users to delete the correct marker among those on the map, I need to associate each marker with its datastore ID, which is a string. I had originally thought I could set the ID as an integer and use the existing zIndex property of markers. That lead to the code below for creating each physical marker. (But, alas, I was unable to access the integer ID value.)
var marker = new google.maps.Marker({ position: point, map: map , title: text, icon: icon, zIndex: ID});
I don't know how to add a property to the prototype of google.maps.Marker that would hold the ID string, and I imagine it is not advisable to alter such prototypes, anyway. So how is this done? Do I have to use the zIndex property as an index for an array that contains the actual ID's as elements which correspond to the zIndex value? That's awkward, too. Surely there is a better way to do this.
Assuming you have an array of locations:
var markers = [];
for(var i in locations){
var loc = locations[i];
var marker = new google.maps.Marker({
position: loc.point
map: map,
title: loc.text,
icon: loc.icon
});
marker.id = loc.id;
markers.push(marker);
}
You can do this because each marker is just a plain old javascript object.
Then you can define a function to hide markers with particular IDs:
function hideMarkersWithIdIn(ids){
var markersToRemove = markers.filter(function(marker){
return ids.indexOf(marker.id) > -1;
});
markersToRemove.forEach(function(marker){
marker.setMap(null);
});
}
That can be used like
hideMarkersWithIdIn([1,5,3])
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/
Edit:
Question = "is there a way to loop through the array and check if each location (long/lat) falls within the current viewport directly" (failing that get all markers within the viewport)
Background:
I have an array of locations (lat, long, id).
I want to:
On a Google Map, use the location array to display markers.
The user can scroll/zoom the map.
Have a button underneath the map, so when the user has decided on an area, he can click the button, and the code will return the ids (from the location array) that are contained within the viewport / map bounds.
There is a .contains for Google, so I guess you could potentially use that with something like
map.getBounds().contains and somehow reference each marker.getPosition()
but I wonder if there's a way to loop through the array and check if each location (long/lat) falls within the current viewport directly
You mean something like this (not tested), map is the google.maps.Map object and needs to be in scope. markersArray is the array of markers.
for (var i=0; i< markersArray.length; i++) {
if (map.getBounds().contains(markersArray[i].getPosition())) {
// the marker is in view
} else {
// the marker is not in view
}
}
http://jsfiddle.net/UA2g2/1/
Thanks geocodezip, you gave me the idea on how to solve it via looping through the array. I don't know if this is the most efficient way, but I put together some code that seems to do what I want - if you check the jsfiddle above and view console you can see that it logs when and which points are in the viewport.
$(document).ready(function(){
var myOptions = {
center: new google.maps.LatLng(51, -2),
zoom: 9,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var storeArray = new Array(["51.38254", "-2.362804", "ID1"], ["51.235249", "-2.297804","ID2"], ["51.086126", "-2.910767","ID3"]);
google.maps.event.addListener(map, 'idle', function() {
for (i = 0; i < storeArray.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(storeArray[i][0], storeArray[i][1]),
map: map
});
}
for (var i=0; i<storeArray.length; i++) {
if (map.getBounds().contains(new google.maps.LatLng(storeArray[i][0], storeArray[i][1]))) {
console.log("marker: " + storeArray[i][2]);
}
}
});
});
I have a map with various markers and i need to be able to draw a rectangle on the map and select the markers which are within the rectangle bounds.
So far i have found some great info here: How to get markers inside an area selected by mouse drag?
I have implemented the keymapzoom plugin ok. like so
$('#dispatcher').gmap3({action:'get'}).enableKeyDragZoom({
boxStyle: {
border: "dashed black",
//backgroundColor: "red",
opacity: 0.5
},
paneStyle: {
backgroundColor: "gray",
opacity: 0.2
}
});
var dz = $('#dispatcher').gmap3({action:'get'}).getDragZoomObject();
google.maps.event.addListener(dz, 'dragend', function (bnds) {
alert(bnds);
});
This gives me the following
((lat,long),(lat,long)) format from the alert(bnds);
I need to know how i can now check if any markers are within this?
I already have an object that is storing the markers for another reason. like:
markers[name] = {};
markers[name].lat = lati;
markers[name].lng = longi;
which might be useful?
I don't understand how to use the GLatLngBounds and containsLatLng(latlng:GLatLng) as suggested.
Your question is tagged with the v3 version of the Maps API, so I'll assume you are using that version (which you should as v2 is deprecated). Note that some classes and methods are named different than in your question.
Bounds are represented with the LatLngBounds class. You can perform the contains method on an instance of that class to determine if a point lies within those bounds.
If you have an object with all your markers, you can loop through them and check each marker, for example:
var bounds = new google.maps.LatLngBounds(sw, ne);
for (var a in markers) {
if (bounds.contains(new google.maps.LatLng(markers[a].lat, markers[a].lng)) {
// marker is within bounds
}
}
On a side note, I would store the LatLng object in the markers object when creating them. That way you don't have to create them wherever you need.
Box/Rectangle Draw Selection in Google Maps
This was my solution..
google.maps.event.addListener(dz, 'dragend', function(e) { //important listener
for(var i = 0; i < markers.length; i++){ // looping through my Markers Collection
if(e.contains(markers[i].position))
console.log("Marker"+ i +" - matched");
}
});
I was trying to follow this example http://code.google.com/p/gmaps-samples/source/browse/trunk/fusiontables/custom_markers.html?spec=svn2515&r=2515, to create custom markers.
I tried to change the example to use my data. The difference is that my data is already geocoded. I had trouble trying to figure why it didnt work when I changed the table id and the columns on the code.
So i printed the 'Address' on the original code and the one with my data.
The original code with the sample fusion-table, outputs the location like this
(37.4471132, -122.1602044)
Because my table is already geocoded I took away most of the function
function codeAddress(row) {
alert(row[1]);
var marker = new google.maps.Marker(
{
map : map,
position : row[1],
//this is where the magic happens!
icon : new google.maps.MarkerImage(icon: new google.maps.MarkerImage("http://www.google.com/images/icons/product/fusion_tables-32.png")
});
}
But the alert only diplays the coordinate a little bit different
<Point><coordinates>-78.423652,-0.203057,0.0</coordinates></Point>
So yeah, that is what I think it is not working
My opinion is that position : has to be followed by a google.maps.LatLng.
It looks like the row data is from KML, you need to extract the first two numbers to create the LatLng.
Mia DiLorenzo is right, the MarkerOption position expects a LatLng object.
Look at this example, which is very similar to yours, but it uses the Coordinates field to create the marker.
The example assumes, that the data in the Coordinates field is comma-separated "lat,lng"
e.g. 47.7672,-3.2022
But if your data happens to be in KML format then you can just extract the lat/lng values. The values are in order: longitude, latitude, and altitude (see the KML reference for details about KML coordinates):
function createLatLngObject(kmlString) {
//remove XML tags from input
var xmlRegEx = /<\/?\w+>/;
var kmlValue = kmlString.replace(xmlRegEx,'');
// now kmlValue contains e.g. -78.423652,-0.203057,0.0
//extract latitude and longitude
var coordinates = kmlValue.split(",");
var lat = coordinates[1];
var lng = coordinates[0];
return new google.maps.LatLng(lat, lng);
}
function createMarker(row) {
var latlng = createLatLngObject(row[1]);
var marker = new google.maps.Marker({
map: map,
position: latlng,
icon: new google.maps.MarkerImage("http://www.google.com/images/icons/product/fusion_tables-32.png")
});
}