I have the a situation where I want to limit the search results from a database that presents Google map markers on a map. Currently there are no criteria to limit this, however there could be sitautions where there are many markers and I want to contain this. I receive my markers in JSON - what would be the best practice to filter these to say 2km of the users current location?
My hunch is to do this with the actual JSON data on generation - but an idea of best practice here would be greatly appreciated as there isn't much in terms of guidance on SO.
Thanks!
Code presented below:
function showMarkers(str) {
if (str == "") {
document.getElementById("products").innerHTML = "";
return;
}
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//$('#mapMarkerPositions').html(this.responseText);
let data = JSON.parse(this.responseText);
merchantMarkers = [];
for (let i = 0; i < data.length; i++) {
merchantMarkers[i] = data[i];
}
resetMarker();
reloadMarkers();
}
}
xmlhttp.open("GET", "filterMarkers.php?s=" + str, true);
xmlhttp.send();
}
Then for the actual map:
<div id="merchantLocations">
<script>
var map;
var markers = [];
var merchantMarkers = [];
</script>
</div>
(additional code between this)
setMarkers(merchantMarkers);
var infowindow = new google.maps.InfoWindow({})
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
map.setCenter(initialLocation);
});
}
}
function setMarkers(locations) {
var infowindow = new google.maps.InfoWindow({});
for (var i = 0; i < locations.length; i++) {
var merchant = locations[i];
var myLatLng = new google.maps.LatLng(merchant[1], merchant[2]);
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
icon: icons.icon,
label: merchant[4]
});
/* ****************** */
map.panTo(myLatLng);
/* ****************** */
google.maps.event.addListener(
marker,
'click',
(function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker)
}
})(marker, i));
markers.push(marker);
}
}
function resetMarker() {
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(null);
}
markers = [];
}
function reloadMarkers() {
setMarkers(merchantMarkers);
}
Since you already have a set of markers with their locations (lat/lng) as well as the device's location using Geolocation, and you only want to put markers within a certain radius from the device origin, then what you can do is to compare the distance between the markers and the device location. You can use Distance Matrix API for this. The DM API can take in X no. of origin and destination in the form of address, latitude/longitude coordinates, or a place ID. So for example you have 1 origin (device's location) and multiple destinations (markers). This will provide you the distance results between your origin and each of your destinations. For example:
https://maps.googleapis.com/maps/api/distancematrix/json?origins=40.6655101,-73.89188969999998&destinations=40.6905615%2C-73.9976592%7C40.6905615%2C-73.9976592%7C40.6905615%2C-73.9976592%7C40.6905615%2C-73.9976592%7C40.6905615%2C-73.9976592%7C40.6905615%2C-73.9976592%7C40.659569%2C-73.933783%7C40.729029%2C-73.851524%7C40.6860072%2C-73.6334271%7C40.598566%2C-73.7527626%7C40.659569%2C-73.933783%7C40.729029%2C-73.851524%7C40.6860072%2C-73.6334271%7C40.598566%2C-73.7527626&key=YOUR_API_KEY
After getting the distance between them, you can then just add a simple if statement:
let result = JSON.parse(this.responseText);
//iterate through all the markers
for(i = 0 ; i <= no_of_markers ; i++ ){
//only show markers that are <= to 2km
if (result.rows[0].elements[i].distance.value <= 20000){
//Show Marker
}
}
Here is where you can learn more about Distance Matrix API. Note that you may also be billed for using this only if you went over the $200 free credit given per month. Here is the pricing sheet for your reference.
Related
I have a function that loads my map to keep my map static.
<script>
var delArray = new Array();
var gm;
var map;
var iw;
var oms;
window.onload = function(){
gm = google.maps;
map = new gm.Map(document.getElementById('map_canvas'), {
mapTypeId: gm.MapTypeId.TERRAIN,
center: new gm.LatLng(-29.335205, 24.793563),
scrollwheel: false,
zoom: 6
});
iw = new gm.InfoWindow();
oms = new OverlappingMarkerSpiderfier(map,
{markersWontMove: true, markersWontHide: true});
}
</script>
I then use another function to construct my spiderfier data.
<script>
function spider(mapData){
var usualColor = 'eebb22';
var spiderfiedColor = 'ffee22';
var iconWithColor = function(color) {
return 'http://chart.googleapis.com/chart?chst=d_map_xpin_letter&chld=pin|+|' +
color + '|000000|ffff00';
}
var shadow = new gm.MarkerImage(
'https://www.google.com/intl/en_ALL/mapfiles/shadow50.png',
new gm.Size(37, 34), // size - for sprite clipping
new gm.Point(0, 0), // origin - ditto
new gm.Point(10, 34) // anchor - where to meet map location
);
oms.addListener('click', function(marker) {
iw.setContent(marker.desc);
iw.open(map, marker);
});
oms.addListener('spiderfy', function(markers) {
for(var i = 0; i < markers.length; i ++) {
markers[i].setIcon(iconWithColor(spiderfiedColor));
markers[i].setShadow(null);
}
iw.close();
});
oms.addListener('unspiderfy', function(markers) {
for(var i = 0; i < markers.length; i ++) {
markers[i].setIcon(iconWithColor(usualColor));
markers[i].setShadow(shadow);
}
});
var bounds = new gm.LatLngBounds();
for (var i = 0; i < mapData.length; i ++) {
var datum = mapData[i];
var loc = new gm.LatLng(datum[0], datum[1]);
bounds.extend(loc);
var marker = new gm.Marker({
position: loc,
title: datum[2],
animation: google.maps.Animation.DROP,
map: map,
icon: iconWithColor(usualColor),
shadow: shadow
});
marker.desc = datum[3];
oms.addMarker(marker);
delArray.push(marker);
}
map.fitBounds(bounds);
// for debugging/exploratory use in console
window.map = map;
window.oms = oms;
}
</script>
And Another to remove markers from the map:
<script>
function delMe(){
if(delArray){
for(i =0; i <= delArray.length; i++){
delArray[i].setMap(null);
}
this.delArray = new Array();
}
}
</script>
My map data (mapData) comes from a php script and passed on via Jason. And that's also where I call my delete function right before I call my spider (map) function. This I do to clear the map before I pass the new data.
$( document ).ready(function() {
delMe();
var pdata = $js_array;
spider(pdata);
});
Now, my problem is that all data is displaying perfectly but after calling the delMe() function it clears the markers 100% but then my map become unresponsive it's not loading new data when calling the spider() function with new data.
I can overcome this problem by reloading/creating the map again, but I want to avoid that and only use a static map. And if I don't delete markers it just fill the map with 100's of markers mixing the old and new.
I am a bit of a noob when it comes to javascript/jquery, any help will be much appreciated!.
It looks like you're missing an OMS removeMarker call in your delMe function, which should go something like this:
function delMe(){
if (delArray){
for (i =0; i <= delArray.length; i++){
oms.removeMarker(delArray[i]);
delArray[i].setMap(null);
}
this.delArray = [];
}
}
(It's possible you have other problems too, but here's a start).
It's not clear from what you write, but are you using the JS developer console? Google '[your browser] developer console' for more info — it lets you see if errors are causing your map to become unresponsive.
Hey guys, the function of this code is described below.
there are some predefined functions below i.e getMapOption and others
function initialize(){
var divCalcDis = $('divCalcDis');
var pdist = $('pdist');
var pTimeTaken = $('pTimeTaken');
var txtLatLon = $('divLatLon');
var lblDistance = $('lblDistance');
var mapOption = mapHandler.getMapOption(that.LonLatCoordinates[0], 15, "Default");
map = mapHandler.getMap('map_canvas', mapOption);
var renderOption = { draggable: true };
directionsDisplay = new google.maps.DirectionsRenderer(renderOption);
directionsDisplay.setMap(map);
google.maps.event.addListener(directionsDisplay, 'directions_changed', function () { for (i = 0; i < directionsDisplay.directions.routes.length; i++) {
//getting latlon
txtLatLon.innerHTML = "";
console.log(directionsDisplay.directions.routes[i].overview_path.length);
var latLng = directionsDisplay.directions.routes[i].overview_path[k];
var latLng = directionsDisplay.directions.routes[i].overview_path[directionsDisplay.directions.routes[i].overview_path.length - 1].toString();
latLng = latLng.split('(')[1];
latLng = latLng.split(')')[0];
latLng = latLng.split(' ');
latLng = latLng[0] + latLng[1];
txtLatLon.innerHTML += latLng;
}
});
startMap();
}
function startMap() {
var i=0;
google.maps.event.addListener(map, 'click', function (event) {
i++;
if(i === 1){
mapHandler.setMarker(event.latLng, map, "http://www.google.com/intl/en_us/mapfiles/ms/micons/green-dot.png", null, null, null, that.permanentMarkers, false);
that.origin = event.latLng; //comma seperated values of lat,lon
}
else if(i > 1){
mapHandler.setMarker(event.latLng, map, "http://www.google.com/intl/en_us/mapfiles/ms/micons/green-dot.png", null, null, null, that.permanentMarkers, false);
if (i === 2) {
that.dest = event.latLng; //comma seperated values of lat,lon
}
else if (i > 2) {
that.wayPTs.push({
location: that.dest,
stopover: true
});
that.dest = event.latLng;
}
that.calcRoute();
}});
};
function calcRoute() {
var divCalcDis = stringHandler._id('divCalcDis');
var pdist = stringHandler._id('pdist');
var pTimeTaken = stringHandler._id('pTimeTaken');
var txtLatLon = stringHandler._id('divLatLon');
txtLatLon.innerHTML = "";
if (!that.wayPTs.length > 1) {
this.wayPTs = null;
}
var request = this.directionsRequest(this.origin,this.dest,google.maps.DirectionsTravelMode.DRIVING,this.wayPTs,false,true,true,google.maps.DirectionsUnitSystem.METRIC);
that.directionsResponse.route(request, function (response, status) {
//console.log(response);
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
};
**
I am making a project using Google Maps API V3 Directions library in which i am creating a route when a user click some place on the map
Here is a screenshot**
Now when i drag the direction drawn line it works smoothly and giving me the latitude and longitude correctly.
Here is a screenshot
But the Problem is when i click on anyother place on the map(after dragging) the waypoint refreshes and i get the old without drag route with the next stop as you can see below
Here is a Screenshot
How to save the latLon of the waypoint so they are available after creation of new points Thx
You need to push the coordinates into the route array so they will always be available. So push when you drag and push when you click. May be this can be of assistance to you. Best of luck.
I know that similar questions have been asked before but the provided answers don't solve my problem. I have a loop in which I iterate through places, create markers and add eventlisteners. When I click on any of the markers afterwards they all show the same information.
var geocoder;
var map;
function initialize() {
// Load places from xml file
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("GET","person_city_clause.xml",false);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
var text =
xmlDoc.getElementsByTagName("text");
var places = [];
var descriptions = [];
for (var i=3; i<text.length; i++)
{
places.push(text[i].childNodes[0].nodeValue); // place
descriptions[places[i]] = descriptions.push(text[i-2].childNodes[0].nodeValue); // person
i=i+3;
}
// Create inital Google Map
var latlng = new google.maps.LatLng(-34.397, 150.644);
var myOptions = {
zoom: 2,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// fill map with place markers
geocoder = new google.maps.Geocoder();
var infowindow = new google.maps.InfoWindow();
var marker = [];
for (var i=0; i<places.length; i++)
{
geocoder.geocode( { 'address': places[i]}, function(results, status)
{
if (status == google.maps.GeocoderStatus.OK)
{
marker[i] = new google.maps.Marker({
map: map,
position: results[0].geometry.location});
listenMarker(marker[i], results[0].formatted_address );
}
})
}
function listenMarker(marker, place)
{
google.maps.event.addListener(marker, 'click', function(){
infowindow.setContent("" + place);
infowindow.open(map, this);});
}
}
edit: when I do alert(i) after geocoder.geocode I always get 32 (the size of the places array).
You need an array for the infowindows aswell, if you do not do this the infowindow variable gets overridden by the next marker..
The content is the same for all of them..
EDIT: Just make another global array:
var locations = [];
..code blabla
if(status == google.maps.GeocoderStatus.OK)
{
for(int k = 0; k<results.length;k++{
locations.push = results[k].geometry.location;
}
}
You can loop through this array using this:
for(int i=0; i<locations.length;i++)
{
}
Try setting a local var in the context of the function, that creates the event function:
...
var index = i;
if (status == google.maps.GeocoderStatus.OK) {
...
infowindow.setContent("" + index);
Here is my problem. I want to set different image to standard markers given by fusion tables. I extract data from the column that contains my points "(coord,coord)" BUT when I associate this coordinates to a marker, this one is not showed! I think that the solution is soooo easy but I can't get it :(. Please read in the section "HERE IS THE PROBLEM" in the middle of this code to have a clear idea. Thanks!!!!
function initialize() {
geocoder = new google.maps.Geocoder();
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: new google.maps.LatLng(46.06454, 13.23561), //the center lat and long
zoom: 9, //zoom
mapTypeId: google.maps.MapTypeId.ROADMAP //the map style
});
//make gviz request
setData();
}
/* GVIZ - get data from Fusion Tables */
function setData() {
//create a viz query to send to Fusion Tables
var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + encodeURIComponent("SELECT dove FROM 781907"));
//set the callback function that will be called when the query returns
query.send(getData);
}
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
for (i = 0; i < numRows; i++) {
var row = response.getDataTable().getValue(i,0);
codeAddress(row);
}
}
var geocoder;
function codeAddress(latlng) {
// HERE IS THE PROBLEM!!!!
// Test show correctly "(lat,lng)" BUT no marker showed on the map!
document.getElementById("test").innerHTML = latlng;
geocoder.geocode( { 'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
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")
});
}
});
}
UPDATE: Based on #Trott's answer, maybe something like this? But still not running. Any advice?
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
//create an array of row values
for (i = 0; i < numRows; i++) {
rowtext = response.getDataTable().getValue(i,0);
var strArr[] = rowtext.split(",");
document.getElementById("via").innerHTML = rowtext;
row = new google.maps.LatLng(strArr[0],strArr[1]);
codeAddress(row);
}
}
geocoder.geocode() requires a LatLng object. Your variable latlng is simply text. You'll need to find a way to convert it to a LatLng object. Most obvious way is probably to parse it with a regex or some other way and pass the lat and lng to new google.maps.LatLng(). There may be a more elegant solution, but that will work.
If it helps, here's some quick hacking I did to your code to confirm what I wrote above. I just hardcoded your first pair of coordinates. You'll still need to write something to parse the data.
function codeAddress(latlng) {
//Whoops, latlng is a string. We need it to be an object. Let's just hardcode one for demo purposes.
latlng=new google.maps.LatLng(46.0724339, 13.249490000000037);
geocoder.geocode( { 'latLng': latlng}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
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")
});
}
});
}
UPDATE: If you (#Massimo) want to do it the way you have it in your update, then you need to remove the parentheses and possibly white space. Try something more like this:
function getData(response) {
numRows = response.getDataTable().getNumberOfRows();
//create an array of row values
for (i = 0; i < numRows; i++) {
var rowtext = response.getDataTable().getValue(i,0);
var sanitizedText = rowtext.replace(/[\(\)\s]/g, "");
var strArr = sanitizedText.split(",");
document.getElementById("via").innerHTML = rowtext;
row = new google.maps.LatLng(strArr[0],strArr[1]);
codeAddress(row);
}
}
I've got this problem when removing a Marker from an array. I click on the map and place markers where i have clicked, the markers are then saved in an array. When removing them it only works in the order i have placed them but backwards, that means i place 1 2 3 but have to remove them like 3 2 1.
If i try to remove the markers in random order, the first one is removed, but then the others just stop working, the listener still works, but it seems like the forloop doesnt find the other markers in the array.
Any ideas? I'm completely lost.
Here is the code:
var map;
var tempLatLng;
var zoomLevel;
var markers = [];
var zoomLevels = [];
var count = -1;
var nullLatlng = new google.maps.LatLng(84.52,45.16);
var nullMarker = new google.maps.Marker({
position: nullLatLng,
});
function initialize() {
var myLatlng = new google.maps.LatLng(55.605629745598904,13.000441789627075);
var myOptions = {
zoom: 17,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel:false
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
//Puts a listener on the map, when clicking on the map, it places a marker.
google.maps.event.addListener(map, 'click', function(event) {
zoomLevel = map.getZoom();
document.getElementById("zoom").value = zoomLevel;
tempLatLng = event.latLng;
setTimeout("placeMarker(tempLatLng)", 800); //placeMarker is called with a duration so that //doubleclicking doesn't bother the placement.
});
}
//Function to place markers.
function placeMarker(location) {
if(zoomLevel == map.getZoom()){
if(true){
var marker1 = new google.maps.Marker({
position: location,
map: map,
draggable:true
});
count = count + 1;
markers[count] = marker1;
document.getElementById("count").value = count;
google.maps.event.addListener(marker1,'rightclick', function(event){
document.getElementById("test2").value = "funkar";
for(var i = 0 ;i < markers.length ;i++){
if(markers[i].getTitle() == marker1.getTitle()){
marker1.setMap(null);
document.getElementById("markerpos").value = markers[i].getTitle();
document.getElementById("test1").value = markers[i].getTitle();
count = count - 1;
document.getElementById("count").value = count;
markers[i] = nullMarker;
}
}
});
marker1.setTitle(location.toString());
}
map.setCenter(location);
}
}
Here is the JSFiddle Demo:
Basically, you were using var count to keep track of the number of markers. You can do markers.length for that. Instead of using markers[count] you can use native array's push method to add element into the array. To remove use splice(i, 1); where i is the element's position and remove 1 element from that position. Also, to check if two markers are equal or the "same" instead using getTitle() use === which does:
is exactly equal to (value and type)
The problem is if you create two or more markers on the same position it would remove both markers but in reality you only remove one of the two "clones" and thus leaving a marker un-removable. This is caused by using getTitle which returns lat lng and if you have two markers w/ same lat lng you have an issue. Also, i changed, within your onclick function, marker1 to this which are referring to the same object for readability.
//Function to place markers.
function placeMarker(location) {
if (zoomLevel == map.getZoom()) {
if (true) {
var marker1 = new google.maps.Marker({
position: location,
map: map,
draggable: true
});
count = count + 1;
markers.push(marker1);
document.getElementById("count").value = markers.length;
google.maps.event.addListener(marker1, 'rightclick', function(event) {
document.getElementById("test2").value = "funkar";
for (var i = 0; i < markers.length; i++) {
if (markers[i] === this) {
this.setMap(null);
document.getElementById("markerpos").value = markers[i].getTitle();
document.getElementById("test1").value = markers[i].getTitle();
markers.splice(i, 1);
document.getElementById("count").value = markers.length;
}
}
});
marker1.setTitle(location.toString());
}
map.setCenter(location);
}
}