-2

I'm doing an application with google maps API that have a JSON with the marker's coordinates. Then I draw polylines between the markers. I also implemented a function with a onclick event that creates a new marker inside the polyline. This marker has to show information of the previous marker in the polyline (the one taked of the JSON, not a clicked one). But I don't know how to take the previous vertex(marker) of a selected polyline.

enter image description here

Code:

(function() {

window.onload = function() {

var options = {
zoom: 3,
center: new google.maps.LatLng(37.09, -95.71),
mapTypeId: google.maps.MapTypeId.HYBRID,
noClear: true,
panControl: true,
scaleControl: false,
streetViewControl:false,
overviewMapControl:false,
rotateControl:false,
mapTypeControl: true,
zoomControl: false,
}; 
var map = new google.maps.Map(document.getElementById('map'), options);

// JSON
$.getJSON("loc.js", function(json) {
    console.log(json);
});

//Marker type
var markers = [];
var arr = []; 
var pinColor = "FE7569";
var pinImage = new google.maps.MarkerImage("http://labs.google.com/ridefinder/images/mm_20_red.png" + pinColor,
    new google.maps.Size(21, 34),
    new google.maps.Point(0,0),
    new google.maps.Point(10, 34));

// JSON loop
for (var i = 0, length = json.length; i < length; i++) {
    var data = json[i],
    latLng = new google.maps.LatLng(data.lat, data.lng);
    arr.push(latLng);

    // Create markers
    var marker = new google.maps.Marker({
        position: latLng,
        map: map,
        icon: pinImage,
    });
    infoBox(map, marker, data);   

    //Polylines
    var flightPath = new google.maps.Polyline({
        path: json,
        geodesic: true,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2,
        map:map
    });
      infoPoly(map, flightPath, data);

    //Calculate polylines distance
    google.maps.LatLng.prototype.kmTo = function(a){ 
        var e = Math, ra = e.PI/180; 
        var b = this.lat() * ra, c = a.lat() * ra, d = b - c; 
        var g = this.lng() * ra - a.lng() * ra; 
        var f = 2 * e.asin(e.sqrt(e.pow(e.sin(d/2), 2) + e.cos(b) * e.cos 
        (c) * e.pow(e.sin(g/2), 2))); 
        return f * 6378.137; 
    }
    google.maps.Polyline.prototype.inKm = function(n){ 
        var a = this.getPath(n), len = a.getLength(), dist = 0; 
        for (var i=0; i < len-1; i++) { 
           dist += a.getAt(i).kmTo(a.getAt(i+1)); 
        }
        return dist; 
    }
}

function infoBox(map, marker, data) {
    var infoWindow = new google.maps.InfoWindow();
    google.maps.event.addListener(marker, "click", function(e) {
        salta(data.tm);
    });

    (function(marker, data) {
      google.maps.event.addListener(marker, "click", function(e) {
        salta(data.tm);
      });
    })(marker, data);
}
//Create onclick marker on the polyline
function  infoPoly(map, flightPath, data){
google.maps.event.addListener(flightPath, 'click', function(event) {
      mk = new google.maps.Marker({
        map: map,
        position: event.latLng,

      });
      markers.push(mk);
      map.setZoom(17);
      map.setCenter(mk.getPosition());
    });
    }

    function drawPath() {
       var coords = [];
       for (var i = 0; i < markers.length; i++) {
        coords.push(markers[i].getPosition());
       }
       flightPath.setPath(coords);
    }  

//  Fit these bounds to the map
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < arr.length; i++) {
    bounds.extend(arr[i]);
}

map.fitBounds(bounds);
//dist polylines
distpoly = flightPath.inKm();
distpolyround = Math.round(distpoly);
};
})();

If I click in the blue arrow, I create a marker on that point of the polyline. I that marker it takes the values of the previous one.

geocodezip
  • 158,664
  • 13
  • 220
  • 245
Andrew
  • 31
  • 7
  • 1
    It's a bit hard to understand the concept. Could you provide some screenshots and maybe post more of your code?! Things I don't get are - you create polyline between 2 markers - one is at the position of the click. Where is the 2nd one? And also - what this means? - _the one taked of the JSON_. Apart from that - you should just create a global variable, that keeps track of the last one. You just save last one's reference in that. – Mike B Apr 24 '16 at 19:34
  • If you gave more code, I could explain how to do it – Mike B Apr 24 '16 at 19:36
  • Edited: The code now, it's complete. I try to explain better my problem. I have a JSON with the latLng coodinates. With these coordinates I create markers, and between them polylines. Then I create a new marker (onclick) in some point inside the polyline (between the 2 markers that contain the coordinates and other data). And the problem: I need this new marker(onclick marker), takes the contained information of the previous marker. This is because I don't have enought waypoints in the map. – Andrew Apr 24 '16 at 20:02
  • How do you determine what is _previous marker_? I guess the polyline is some kind of way/road from A to B through some points. And _previous_ is the one "on the road" at the start of that line-part (between those 2 markers) closer to the start? – Mike B Apr 24 '16 at 20:16
  • All markers have a time stamp, but I don't use it for create the polyline. – Andrew Apr 24 '16 at 20:28
  • But are the polyline points the exact same lat/lng as markers? – Mike B Apr 24 '16 at 20:50
  • Yes! The separation between the markers and the polyline seen in the picture, it's because I chnaged the type of the markers. With the normal one's does not happen. – Andrew Apr 24 '16 at 20:55
  • while I am writing your answer, you can check something like **offset** for the marker. I am using that for openLayers. Don't know if there is one for google. – Mike B Apr 24 '16 at 20:57
  • I get a javascript error with the posted code `Uncaught ReferenceError: salta is not defined`; changing the marker to the default icon (commenting out `icon: pinImage`) solves the offset of the markers from the polyline (or remove the `MarkerImage` constructor and replace it with: `var pinImage = "http://labs.google.com/ridefinder/images/mm_20_red.png";`). – geocodezip Apr 24 '16 at 21:04
  • Yes, this function it's in another js file. Don't worry about this one. I try this offset option, but it's only "cosmetic". – Andrew Apr 24 '16 at 21:12
  • Your blue arrow is between two markers. Which of those is the "previous one"? – geocodezip Apr 24 '16 at 21:16

2 Answers2

1

You can use the geometry library .poly namespace isLocationOnEdge method to determine which segment of the polyline the clicked point (new marker) is on.

//Create onclick marker on the polyline
function infoPoly(map, flightPath, data) {
  google.maps.event.addListener(flightPath, 'click', function(event) {
    mk = new google.maps.Marker({
      map: map,
      position: event.latLng,

    });
    markers.push(mk);
    map.setZoom(17);
    map.setCenter(mk.getPosition());

    // find line segment.  Iterate through the polyline checking each line segment.
    // isLocationOnEdge takes a google.maps.Polyline as the second argument, so make one,
    // then use it for the test.  The default value of 10e-9 for the tolerance didn't work,
    // a tolerance of 10e-6 seems to work.
    var betweenStr = "result no found";
    var betweenStr = "result no found";
    for (var i=0; i<flightPath.getPath().getLength()-1; i++) {
       var tempPoly = new google.maps.Polyline({
         path: [flightPath.getPath().getAt(i), flightPath.getPath().getAt(i+1)]
       })
       if (google.maps.geometry.poly.isLocationOnEdge(mk.getPosition(), tempPoly, 10e-6)) {
          betweenStr = "between "+i+ " and "+(i+1);
       }
    }

    (function(mk, betweenStr) {
      google.maps.event.addListener(mk, "click", function(e) {
        infowindow.setContent(betweenStr+"<br>loc:" + this.getPosition().toUrlValue(6));
        infowindow.open(map, mk);
        // salta(data.tm);
      });
    })(mk, betweenStr);

    google.maps.event.trigger(mk,'click');
  });

proof of concept fiddle

code snippet:

var infowindow = new google.maps.InfoWindow();
(function() {

  window.onload = function() {

    var options = {
      zoom: 3,
      center: new google.maps.LatLng(37.09, -95.71),
      mapTypeId: google.maps.MapTypeId.HYBRID,
    };
    var map = new google.maps.Map(document.getElementById('map'), options);

    //Marker type
    var markers = [];
    var arr = [];
    var pinColor = "FE7569";
    var pinImage = "http://labs.google.com/ridefinder/images/mm_20_red.png";

    // JSON loop
    for (var i = 0, length = json.length; i < length; i++) {
      var data = json[i],
        latLng = new google.maps.LatLng(data.lat, data.lng);
      arr.push(latLng);

      // Create markers
      var marker = new google.maps.Marker({
        position: latLng,
        map: map,
        icon: pinImage,
      });
      infoBox(map, marker, data);

      //Polylines
      var flightPath = new google.maps.Polyline({
        path: json,
        geodesic: true,
        strokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2,
        map: map
      });
      infoPoly(map, flightPath, data);
    }

    function infoBox(map, marker, data) {
        var infoWindow = new google.maps.InfoWindow();
        google.maps.event.addListener(marker, "click", function(e) {
          infowindow.setContent("tm:" + data.tm + "<br>loc:" + this.getPosition().toUrlValue(6));
          infowindow.open(map, marker);
          // salta(data.tm);
        });

        (function(marker, data) {
          google.maps.event.addListener(marker, "click", function(e) {
            infowindow.setContent("tm:" + data.tm + "<br>loc:" + this.getPosition().toUrlValue(6));
            infowindow.open(map, marker);
            // salta(data.tm);
          });
        })(marker, data);
      }
      //Create onclick marker on the polyline

    function infoPoly(map, flightPath, data) {
      google.maps.event.addListener(flightPath, 'click', function(event) {
        mk = new google.maps.Marker({
          map: map,
          position: event.latLng,

        });
        markers.push(mk);
        map.setZoom(17);
        map.setCenter(mk.getPosition());

        // find line segment.  Iterate through the polyline checking each line segment.
        // isLocationOnEdge takes a google.maps.Polyline as the second argument, so make one,
        // then use it for the test.  The default value of 10e-9 for the tolerance didn't work,
        // a tolerance of 10e-6 seems to work.
        var betweenStr = "result no found";
        for (var i = 0; i < flightPath.getPath().getLength() - 1; i++) {
          var tempPoly = new google.maps.Polyline({
            path: [flightPath.getPath().getAt(i), flightPath.getPath().getAt(i + 1)]
          })
          if (google.maps.geometry.poly.isLocationOnEdge(mk.getPosition(), tempPoly, 10e-6)) {
            betweenStr = "between " + i + " and " + (i + 1);
          }
        }

        (function(mk, betweenStr) {
          google.maps.event.addListener(mk, "click", function(e) {
            infowindow.setContent(betweenStr + "<br>loc:" + this.getPosition().toUrlValue(6));
            infowindow.open(map, mk);
            // salta(data.tm);
          });
        })(mk, betweenStr);

        google.maps.event.trigger(mk, 'click');
      });
    }

    function drawPath() {
      var coords = [];
      for (var i = 0; i < markers.length; i++) {
        coords.push(markers[i].getPosition());
      }
      flightPath.setPath(coords);
    }

    //  Fit these bounds to the map
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < arr.length; i++) {
      bounds.extend(arr[i]);
    }

    map.fitBounds(bounds);
    //dist polylines
    distpoly = flightPath.inKm();
    distpolyround = Math.round(distpoly);
  };
})();

var json = [{
  lat: 38.931808,
  lng: -74.906606,
  tm: 0
}, {
  lat: 38.932442,
  lng: -74.905147,
  tm: 1
}, {
  lat: 38.93311,
  lng: -74.903473,
  tm: 2
}, {
  lat: 38.933777,
  lng: -74.901671,
  tm: 3
}, {
  lat: 38.930739,
  lng: -74.912528,
  tm: 1000
}];
html,
body,
#map {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?libraries=geometry"></script>
<div id="map"></div>
geocodezip
  • 158,664
  • 13
  • 220
  • 245
0

INITIALIZING
When you are creating those markers in the for loop, add them to a map [Data structure] that you define (empty) before the loop. In the map markers will be stored. Their keys - concatenated lat/lng.

  • var initial_markers = {}; //before for loop
  • initial_markers[data.lat+"-"+data.lng] = marker; //after each marker initialization
  • Count them, so you know how many there are initial_marker_count, because you cannot get length of size of a map[data structure]

DETECTION
When you have clicked on a polyline, I don't think you can get exactly the part of polyline that is clicked, so you need to get it yourself. The steps are:

  • Get the coordinate of click event
  • Loop through the markers
  • Take their coordinates
  • Check if the clicked point on the map is on the line between those two points
  • If is, take the first of those two points

DETECTION PSEUDOCODE

var prev_marker;
for (var i=initial_markers; i<initial_marker_count-2; i++) {
    if( isPointOnLine(initial_markers[i], initial_markers[i+1], clicked_point) {
        prev_marker = initial_markers[i];
        break;
    }
}

The only reason I am saying that this is pseudocode, is because I don't know hor to find if point is on the line between two points in Google maps. And you should write that isPointOnLine() functions. Apart from that - the idea is given. Hope You appreciate it.

Mike B
  • 2,756
  • 2
  • 16
  • 28