0

Is it possible to select only a section of a polyline in a Google Map? I have markers which are added by the user and a polyline is drawn between the markers. The polyline between two markers represents the route between the two places.I want the user to be able to click on the polyline, that section changes colour and then insert another point. I'd also like to get the marker ID's (which are set when the marker is added), of the markers which the polyline connects.

This is the google sample code which my code is based off, since my code is quite messy, i'm posting this instead.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Complex Polylines</title>
<style>
    html, body
    {
        height: 100%;
        margin: 0;
        padding: 0;
    }
    #map
    {
        height: 100%;
    }
</style>
</head>
<body>
<div id="map">
</div>
   <script>
       var poly;
       var map;

    function initMap() {
        map = new google.maps.Map(document.getElementById('map'), {
            zoom: 7,
            center: { lat: 41.879, lng: -87.624}  // Center the map on Chicago, USA.
        });

        poly = new google.maps.Polyline({
            strokeColor: '#000000',
            strokeOpacity: 1.0,
            strokeWeight: 3
        });
        poly.setMap(map);

        // Add a listener for the click event
        map.addListener('click', addLatLng);
    }

    // Handles click events on a map, and adds a new point to the Polyline.
    function addLatLng(event) {
        var path = poly.getPath();

        // Because path is an MVCArray, we can simply append a new coordinate
        // and it will automatically appear.
        path.push(event.latLng);

        // Add a new marker at the new plotted point on the polyline.
        var marker = new google.maps.Marker({
            position: event.latLng,
            title: '#' + path.getLength(),
            map: map
        });
    }

 </script>
 <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&signed_in=true&callback=initMap"></script>
</body>
</html>

So far, i've only managed to add a click event listener to the entire polyline:

 google.maps.event.addListener(poly, 'click', function() {
   poly.setOptions({strokeColor: '#76EE00'});
 });
shu
  • 1,938
  • 10
  • 19
  • I think [SO-6170176](http://stackoverflow.com/questions/6170176/google-maps-polyline-click-on-section-of-polyline-and-return-id) might be helpful. – gerardnimo Feb 09 '16 at 14:24
  • @gerardnimo Thanks, I did look at that question but I still don't know how to apply it to my question. –  Feb 09 '16 at 14:43

1 Answers1

0

To get closest polyline i use triangle dependencies, so for each couple of markers i compute distance between points (d^ = (x2-x1)^ + (y2-y1)^) next get area of triangle from Heron's formula, than from p=(a*h)/2 got hight of triangle which is our point to polyline distance. I also devide hight distance throught distance to closes mark point to get closest section - it's not perfect but works preety good.

When we got our section have to restore full path, change markers order and its done.

So when you click on poly line it should highlight, if you click again new marker will appear and highlight will be removed, and main path can be continuing from last marker.

Here is working JSFiddle

var poly, map, 
markers = {}, // here we handle all markers
tmp_path = null, // temporary path for select sections
id_i = 1, // initial value for marker id
MD = []; // selection section markers id

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    zoom: 7,
    center: { lat: 41.879, lng: -87.624}  // Center the map on Chicago, USA.
  });

  poly = new google.maps.Polyline({
    strokeColor: '#000000',
    strokeOpacity: 1.0,
    strokeWeight: 3
  });
  poly.setMap(map);

  // Add a listener for the click event
  map.addListener('click', addLatLng);
  poly.addListener('click', polyOnClick);

}



function polyOnClick(event) {
    if(tmp_path !== null) tmp_path.setMap(null);
    tmp_path = null;

    var
    p_x = event.latLng.lat(),
    p_y = event.latLng.lng(),
    min_dist = 999999;


    $.each(markers, function(k, v) {
      if(typeof markers[(v.id+1)] == 'undefined') return false;

      var 
      m_x = v.x,
      m_y = v.y,
      m2_x = markers[(v.id+1)].x,
      m2_y = markers[(v.id+1)].y;


      var
      a = getDist(m_x, m2_x, m_y, m2_y), 
            b = getDist(m_x, p_x, m_y, p_y),
      c = getDist(p_x, m2_x, p_y, m2_y);
      var h = getHgh(a, b, c);

      var min_mark_dist = (c > b)? b : c;

      console.info(h/min_mark_dist);

      if((h/min_mark_dist) < min_dist) {
        min_dist = (h/min_mark_dist);
        MD = [v.id, markers[(v.id+1)].id];
      }

    });


    // append temporary path to haighlight section
    tmp_path = new google.maps.Polyline({
      path: [{lat: markers[MD[0]].x, lng: markers[MD[0]].y},{lat: markers[MD[1]].x, lng: markers[MD[1]].y}],
      geodesic: true,
      strokeColor: '#76EE00',
      strokeOpacity: 1,
      strokeWeight: 6
    });

    tmp_path.addListener('click', tmp_pathOnClick);
    tmp_path.setMap(map);
}

function tmp_pathOnClick(event) {
    tmp_path.setMap(null);
    tmp_path = null;

    /* restore markers order and path */
   var tmp_markers = {}, 
   ctx_marker_id = 0; // here we handle pushed marker id
   var full_path = [], flag = false;
   id_i = 1; 

    $.each(markers, function(k, v) {
      if(MD[0] < v.id && !flag) {
        flag = true;
        full_path.push(event.latLng);
        ctx_marker_id = id_i;
        tmp_markers[id_i] = {id: id_i, x: event.latLng.lat(), y: event.latLng.lng()};
        id_i++;
      }

      full_path.push({lat: v.x, lng: v.y});
      tmp_markers[id_i] = {id: id_i, x: v.x, y: v.y, marker: v.marker};
      v.marker.setTitle('#'+id_i);
      id_i++;
    });

    markers = tmp_markers;

    // create new marker
    var marker = new google.maps.Marker({
      position: event.latLng,
      title: '#' + ctx_marker_id,
      map: map,
      id: ctx_marker_id
    });

    markers[ctx_marker_id].marker = marker;


    /* restore main path */
    poly.setMap(null); // clear view
    poly = null; // delete object

    poly = new google.maps.Polyline({
      strokeColor: '#000000',
      strokeOpacity: 1.0,
      strokeWeight: 3,
      path: full_path
    });
    poly.setMap(map); 

    poly.addListener('click', polyOnClick);
    MD = []; // clear selected section markers id
}

// get distance between two points
function getDist(x1, x2, y1, y2) {
    return Math.sqrt(Math.pow((x2 - x1), 2) + Math.pow((y2 - y1), 2));
}

// get hight from abc triangle 
function getHgh(a, b, c) {
    var p = (a+b+c)/2;
  var F = Math.sqrt((p * (p-a) * (p-b) * (p-c)), 2);
  return 2*F/a; 
}



// Handles click events on a map, and adds a new point to the Polyline.
function addLatLng(event) {
    console.log('addLatLng');

  if(MD.length) return false;
  if(tmp_path !== null) tmp_path.setMap(null);
  tmp_path = null;

  var path = poly.getPath();

  // Because path is an MVCArray, we can simply append a new coordinate
  // and it will automatically appear.
  path.push(event.latLng);


  // Add a new marker at the new plotted point on the polyline.
  var marker = new google.maps.Marker({
    position:  event.latLng,
    title: '#' + path.getLength(),
    map: map,
    id: id_i
  });

  markers[id_i++] = {id: marker.id, x: marker.position.lat(), y: marker.position.lng(), marker: marker};
}
Sojtin
  • 2,714
  • 2
  • 18
  • 32
  • perfect!! This is exactly what I was looking for. Your method is very interesting! Thank you for your answer :) –  Feb 14 '16 at 16:03