1

I have a Google Map that displays service stations across mainland Europe and can calculate routes between two locations. However, because there are a lot of stations, the map can look quite busy. I therefore want to only show markers that follow the route my google directions have given.

I thought about tracing the directions with a polyline and perhaps using an intercept, but I can't think of how to talk to the database. My current example shows the directions with an red polyline but with all the markers showing.

The code for the javascript is:

//<![CDATA[

var customIcons = {
  as24: {
    icon: 'images/as24.png'
  },
  pearson: {
    icon: 'images/p.png'
  }
};

var rendererOptions = {
draggable: true
};
var directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions);
var directionsService = new google.maps.DirectionsService();
var map, trafficLayer;
var europe = new google.maps.LatLng(-25.274398, 133.775136);

function initialize() {

var mapOptions = {
zoom: 6,
center: europe
};

map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);

directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directionsPanel'));

google.maps.event.addListener(directionsDisplay, 'directions_changed', function() {
computeTotalDistance(directionsDisplay.getDirections());
});

trafficLayer = new google.maps.TrafficLayer();
    trafficLayer.setMap(map);

    var control = document.getElementById('traffic-wpr');
    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control);

    google.maps.event.addDomListener(control, 'click', function() {
      trafficLayer.setMap(trafficLayer.getMap() ? null : map);
    });

 calcRoute();
 }



function calcRoute() {
var start = document.getElementById('start').value;
var end = document.getElementById('end').value;
var request = {
  origin:start,
  destination:end,
  //waypoints:[{location: 'London, England'}, {location: 'Paris, France'}],
  travelMode: google.maps.TravelMode.DRIVING
 };
 directionsService.route(request, function(response, status) {
 if (status == google.maps.DirectionsStatus.OK) {
  directionsDisplay.setDirections(response);
 }
var polyline = new google.maps.Polyline({
 path: [],
 strokeColor: "#FF0000",
        strokeOpacity: 0.2,
        strokeWeight: 30,
        fillColor: "#FF0000",
        fillOpacity: 0.35
});
var bounds = new google.maps.LatLngBounds();


var legs = response.routes[0].legs;
for (i=0;i<legs.length;i++) {
var steps = legs[i].steps;
for (j=0;j<steps.length;j++) {
var nextSegment = steps[j].path;
for (k=0;k<nextSegment.length;k++) {
  polyline.getPath().push(nextSegment[k]);
  bounds.extend(nextSegment[k]);


 }
 }
}



polyline.setMap(map);
map.fitBounds(bounds);

 });
}



function computeTotalDistance(result) {
var total = 0;
var myroute = result.routes[0];
for (var i = 0; i < myroute.legs.length; i++) {
total += myroute.legs[i].distance.value;
}
total = total / 1000.0;
document.getElementById('total').innerHTML = total + ' km';
}
google.maps.event.addDomListener(window, 'load', initialize);


function load() {

  var infoWindow = new google.maps.InfoWindow;

  // Change this depending on the name of your PHP file
  downloadUrl("as24_genxml.php", function(data) {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
      var name = markers[i].getAttribute("name");
      var address = markers[i].getAttribute("address");
      var price = markers[i].getAttribute("price");
      var type = markers[i].getAttribute("type");
      var point = new google.maps.LatLng(
          parseFloat(markers[i].getAttribute("lat")),
          parseFloat(markers[i].getAttribute("lng")));
      var html = "<b>" + name + " " + price + "</b> <br/>" + address;
      var icon = customIcons[type] || {}; 
      var marker = new google.maps.Marker({
        map: map,
        position: point,
        icon: icon.icon
      });
      map.getBounds().contains(marker.getPosition())
      bindInfoWindow(marker, map, infoWindow, html);
    }
  });
}

function bindInfoWindow(marker, map, infoWindow, html) {
  google.maps.event.addListener(marker, 'click', function() {
    infoWindow.setContent(html);
    infoWindow.open(map, marker);
  });
}

function downloadUrl(url, callback) {
  var request = window.ActiveXObject ?
      new ActiveXObject('Microsoft.XMLHTTP') :
      new XMLHttpRequest;

  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      request.onreadystatechange = doNothing;
      callback(request, request.status);
    }
  };

  request.open('GET', url, true);
  request.send(null);
}




function doNothing() {}

//]]>

The code for the markers (as24_genxml.php) is:

<?php include ('php/config.php');

function parseToXML($htmlStr) 
{ 
$xmlStr=str_replace('<','&lt;',$htmlStr); 
$xmlStr=str_replace('>','&gt;',$xmlStr); 
$xmlStr=str_replace('"','&quot;',$xmlStr); 
$xmlStr=str_replace("'",'&#39;',$xmlStr); 
$xmlStr=str_replace("&",'&amp;',$xmlStr); 
return $xmlStr; 
} 

// Opens a connection to a MySQL server
$connection=mysql_connect (localhost, $mysql_user, $mysql_pass);
if (!$connection) {
die('Not connected : ' . mysql_error());
}

// Set the active MySQL database
$db_selected = mysql_select_db($mysql_db, $connection);
if (!$db_selected) {
  die ('Can\'t use db : ' . mysql_error());
}

// Select all the rows in the markers table
$query = "SELECT * FROM as24 WHERE 1";
$result = mysql_query($query);
if (!$result) {
  die('Invalid query: ' . mysql_error());
}

header("Content-type: text/xml");

// Start XML file, echo parent node
echo '<markers>';

// Iterate through the rows, printing XML nodes for each
while ($row = @mysql_fetch_assoc($result)){
  // ADD TO XML DOCUMENT NODE
  echo '<marker ';
  echo 'name="' . parseToXML($row['name']) . '" ';
  echo 'address="' . parseToXML($row['address']) . '" ';
  echo 'price="' . parseToXML($row['price']) . '" ';
  echo 'lat="' . $row['lat'] . '" ';
  echo 'lng="' . $row['lng'] . '" ';
  echo 'type="' . $row['type'] . '" ';
  echo '/>';
}

// End XML file
echo '</markers>';

?>

I can't seem to find anyone else that has a similar problem. I may be overcomplicating things by using the polyline?

tomantford
  • 182
  • 22
  • 2
    The Directions Service provides you with a Route object that contains all the waypoints. https://developers.google.com/maps/documentation/javascript/directions Then you will need to define "Along the route" and probably show markers that are within a specific range around your waypoints. For this, you can check my answer here: http://stackoverflow.com/a/21043061/1238965 – MrUpsidown Jan 23 '14 at 10:32
  • Would never have thought of that query, well played. I've previously always queried for items BETWEEN coordinates from a maps bounds object and then narrowed by radius in the front end. – ChrisSwires Jan 23 '14 at 10:34
  • Well, that might be an ok solultion, or maybe not. For example, what will happen if you select all markers within a 10km range and that 2 waypoints are separated by 50km? This would need to be tested. – MrUpsidown Jan 23 '14 at 10:50
  • Thanks for the comments @MrUpsidown and Swires. This might better show the dilemma: http://thoford.co.uk/pp/stations_map.php?from=eindhoven&to=berlin – tomantford Jan 23 '14 at 10:53
  • How do we toggle the markers? – MrUpsidown Jan 23 '14 at 11:06
  • @MRUpsidown There is no way to toggle the markers, instead each time the calcRoute() is called, I want the markers that are within the bounds of the directions/polygon to show. – tomantford Jan 23 '14 at 11:09
  • Oh well, you stated in your question that the map looks busy so I thought I would see that happening... Now what do you want us to help you with? Did you check the Route object as suggested? – MrUpsidown Jan 23 '14 at 11:13
  • Yes I looked at the weypoints section, but that seems to work in a way that forces the directions to change. I don't want the route to have to pass through a particular waypoint, I just want the markers to only show if they appear along the route. – tomantford Jan 23 '14 at 11:18
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/45918/discussion-between-tomantford-and-mrupsidown) – tomantford Jan 23 '14 at 13:25
  • 1
    possible duplicate of [How to to Get Places (e.g Gas Stations) along Route Between Origin and Destination in Google Maps API](http://stackoverflow.com/questions/17283826/how-to-to-get-places-e-g-gas-stations-along-route-between-origin-and-destinati) – geocodezip Jan 23 '14 at 14:00
  • @Geocodezip - appreciate the link to your answer. Just the person I've been looking for! Your answer is almost what I need, but I want to load the events from mysql..? – tomantford Jan 23 '14 at 15:57
  • Yup. Replace the places queries with queries to your database. – geocodezip Jan 23 '14 at 15:58
  • Sure, but not in the short term, I don't have your database, and I don't have a lot of time right now. There are other questions on SO about how to query databases for markers inside a bounds. – geocodezip Jan 23 '14 at 16:32

1 Answers1

0

Ok, I'm not sure if I'm over-complicating this to be honest but if you merely want the map to look less cluttered then you don't need to change anything in the back-end (presuming you're having no performance issues, I'm unsure how many points we're talking about here. All you need to do is check the distance between each coordinate on the polyline and each 'service station' marker.

An example of how to achieve this is available in the first part of the answer here. You can even hide the polyline to further reduce clutter, or remove it and use the coordinates within each path segment to achieve the same effect.

This could however be an issue if you have a lot of points to check and long routes. The only way to know for sure will be to try it, but the asymptotic complexity is not great.

Community
  • 1
  • 1
ChrisSwires
  • 2,713
  • 1
  • 15
  • 28