Google Maps API - 在定义的点中沿着折线保持可拖动标记 [英] Google Maps API - Keep Draggable Marker Along Polyline in the defined points

查看:63
本文介绍了Google Maps API - 在定义的点中沿着折线保持可拖动标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图将标记点保留在预定义的点(纬度/经度)中,在示例中的数组polypath中,因此标记沿着折线移动到最近的存在点,所以我可以使用选定的点到另一个计算。

I tried to keep the point of marker in pre-defined points (latitudes/longitudes) which in the array "polypath" in the example, so the marker goes to nearest existed point along polyline, so I can use the selected point to another calculation.

下面的代码显示了用户可以在折线中将标记保存在任何位置的当前行为:

This code below shows the current behavior where user can keep the marker wherever he want in the polyline:

var gmap;
var  currentMarker = new google.maps.Marker({
            position: new google.maps.LatLng(54.13512, -117.0114),
            draggable: true
        });
var snapToRoute = null;
var polypath = new Array(
        new google.maps.LatLng(54.13512, -117.0114),
        new google.maps.LatLng(54.13353, -117.01141),
        new google.maps.LatLng(54.1332, -117.01159),
        new google.maps.LatLng(54.13241, -117.01157),
        new google.maps.LatLng(54.13217, -117.01142),
        new google.maps.LatLng(54.12725, -117.01143),
        new google.maps.LatLng(54.12185, -117.00125),
        new google.maps.LatLng(54.1188, -116.9955),
        new google.maps.LatLng(54.11603, -116.99473),
        new google.maps.LatLng(54.11517, -116.99281),
        new google.maps.LatLng(54.10235, -116.97771),
        new google.maps.LatLng(54.10244, -116.96093),
        new google.maps.LatLng(54.10197, -116.96067),
        new google.maps.LatLng(54.10158, -116.96075),
        new google.maps.LatLng(54.09808, -116.95913),
        new google.maps.LatLng(54.09725, -116.95668),
        new google.maps.LatLng(54.09669, -116.95598),
        new google.maps.LatLng(54.08378, -116.9471),
        new google.maps.LatLng(54.08218, -116.94696),
        new google.maps.LatLng(54.07374, -116.93832),
        new google.maps.LatLng(54.07319, -116.93571),
        new google.maps.LatLng(54.07185, -116.93527));
        
    var polyline = new google.maps.Polyline({
				path: polypath,
				strokeColor: "red",
				strokeWeight: 2,
				strokeOpacity: 1
			});

function initialize() {
    gmap = new google.maps.Map(
    document.getElementById("map_canvas"), {
        center: new google.maps.LatLng(54.10244, -116.96093),
        zoom: 12
    });
    
    
     currentMarker.setMap(gmap);
    polyline.setMap(gmap);
   
    
   snapToRoute = new SnapToRoute(gmap, currentMarker, polyline);
}

google.maps.event.addDomListener(window, "load", initialize);

function SnapToRoute(map, marker, polyline) {
    this.routePixels_ = [];
    this.normalProj_ = map.getProjection();
    this.map_ = map;
    this.marker_ = marker;
    this.polyline_ = polyline;

    this.init_();
}

SnapToRoute.prototype.init_ = function () {
    this.loadLineData_();
    this.loadMapListener_();
};

SnapToRoute.prototype.updateTargets = function (marker, polyline) {
    this.marker_ = marker || this.marker_;
    this.polyline_ = polyline || this.polyline_;
    this.loadLineData_();
};

SnapToRoute.prototype.loadMapListener_ = function () {
    var me = this;

    google.maps.event.addListener(me.marker_, "dragend", function (evt) {
        me.updateMarkerLocation_(evt.latLng);
    });

    google.maps.event.addListener(me.marker_, "drag", function (evt) {
        me.updateMarkerLocation_(evt.latLng);
    });

    google.maps.event.addListener(me.map_, "zoomend", function (evt) {
        me.loadLineData_();
    });
};

SnapToRoute.prototype.loadLineData_ = function () {
    var zoom = this.map_.getZoom();
    this.routePixels_ = [];
    var path = this.polyline_.getPath();
    for (var i = 0; i < path.getLength(); i++) {
        var Px = this.normalProj_.fromLatLngToPoint(path.getAt(i));
        this.routePixels_.push(Px);
    }
};

SnapToRoute.prototype.updateMarkerLocation_ = function (mouseLatLng) {
    var markerLatLng = this.getClosestLatLng(mouseLatLng);
    this.marker_.setPosition(markerLatLng);
};

SnapToRoute.prototype.getClosestLatLng = function (latlng) {
    var r = this.distanceToLines_(latlng);
    return this.normalProj_.fromPointToLatLng(new google.maps.Point(r.x, r.y));
};

SnapToRoute.prototype.getDistAlongRoute = function (latlng) {
    if (typeof (opt_latlng) === 'undefined') {
        latlng = this.marker_.getLatLng();
    }
    var r = this.distanceToLines_(latlng);
    return this.getDistToLine_(r.i, r.to);
};

SnapToRoute.prototype.distanceToLines_ = function (mouseLatLng) {
    var zoom = this.map_.getZoom();
    var mousePx = this.normalProj_.fromLatLngToPoint(mouseLatLng);
    var routePixels_ = this.routePixels_;
    return this.getClosestPointOnLines_(mousePx, routePixels_);
};

SnapToRoute.prototype.getDistToLine_ = function (line, to) {
    var routeOverlay = this.polyline_;
    var d = 0;
    for (var n = 1; n < line; n++) {
        d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(n - 1), routeOverlay.getAt(n));
    }
    d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(line - 1), routeOverlay.getAt(line)) * to;
    return d;
};

SnapToRoute.prototype.getClosestPointOnLines_ = function (pXy, aXys) {
    var minDist;
    var to;
    var from;
    var x;
    var y;
    var i;
    var dist;

    if (aXys.length > 1) {
        for (var n = 1; n < aXys.length; n++) {
            if (aXys[n].x !== aXys[n - 1].x) {
                var a = (aXys[n].y - aXys[n - 1].y) / (aXys[n].x - aXys[n - 1].x);
                var b = aXys[n].y - a * aXys[n].x;
                dist = Math.abs(a * pXy.x + b - pXy.y) / Math.sqrt(a * a + 1);
            } else {
                dist = Math.abs(pXy.x - aXys[n].x);
            }

            var rl2 = Math.pow(aXys[n].y - aXys[n - 1].y, 2) + Math.pow(aXys[n].x - aXys[n - 1].x, 2);
            var ln2 = Math.pow(aXys[n].y - pXy.y, 2) + Math.pow(aXys[n].x - pXy.x, 2);
            var lnm12 = Math.pow(aXys[n - 1].y - pXy.y, 2) + Math.pow(aXys[n - 1].x - pXy.x, 2);
            var dist2 = Math.pow(dist, 2);
            var calcrl2 = ln2 - dist2 + lnm12 - dist2;
            if (calcrl2 > rl2) {
                dist = Math.sqrt(Math.min(ln2, lnm12));
            }

            if ((minDist == null) || (minDist > dist)) {
                to = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
                from = Math.sqrt(ln2 - dist2) / Math.sqrt(rl2);
                minDist = dist;
                i = n;
            }
        }
        if (to > 1) {
            to = 1;
        }
        if (from > 1) {
            to = 0;
            from = 1;
        }
        var dx = aXys[i - 1].x - aXys[i].x;
        var dy = aXys[i - 1].y - aXys[i].y;

        x = aXys[i - 1].x - (dx * to);
        y = aXys[i - 1].y - (dy * to);
    }
    return {
        'x': x,
            'y': y,
            'i': i,
            'to': to,
            'from': from
    };
};

html, body, #map_canvas {
    height: 100%;
    width: 100%;
    margin: 0px;
    padding: 0px
}

<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script>
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>

推荐答案

删除将点插值到顶点之间的最近点的代码。

Remove the code that interpolates the point to the nearest point on the line between the vertices.

var dx = aXys[i - 1].x - aXys[i].x;
var dy = aXys[i - 1].y - aXys[i].y;

x = aXys[i - 1].x - (dx * to);
y = aXys[i - 1].y - (dy * to);

更改返回其中一个顶点(i是下一个顶点,i-1是前一个vertex):

change that to return one of the vertices (i is the next vertex, i-1 is the previous vertex):

x = aXys[i].x; 
y = aXys[i].y; 

概念证明小提琴

代码段

var gmap;
var currentMarker = new google.maps.Marker({
  position: new google.maps.LatLng(54.13512, -117.0114),
  draggable: true
});
var snapToRoute = null;
var polypath = new Array(
  new google.maps.LatLng(54.13512, -117.0114),
  new google.maps.LatLng(54.13353, -117.01141),
  new google.maps.LatLng(54.1332, -117.01159),
  new google.maps.LatLng(54.13241, -117.01157),
  new google.maps.LatLng(54.13217, -117.01142),
  new google.maps.LatLng(54.12725, -117.01143),
  new google.maps.LatLng(54.12185, -117.00125),
  new google.maps.LatLng(54.1188, -116.9955),
  new google.maps.LatLng(54.11603, -116.99473),
  new google.maps.LatLng(54.11517, -116.99281),
  new google.maps.LatLng(54.10235, -116.97771),
  new google.maps.LatLng(54.10244, -116.96093),
  new google.maps.LatLng(54.10197, -116.96067),
  new google.maps.LatLng(54.10158, -116.96075),
  new google.maps.LatLng(54.09808, -116.95913),
  new google.maps.LatLng(54.09725, -116.95668),
  new google.maps.LatLng(54.09669, -116.95598),
  new google.maps.LatLng(54.08378, -116.9471),
  new google.maps.LatLng(54.08218, -116.94696),
  new google.maps.LatLng(54.07374, -116.93832),
  new google.maps.LatLng(54.07319, -116.93571),
  new google.maps.LatLng(54.07185, -116.93527));

var polyline = new google.maps.Polyline({
  path: polypath,
  strokeColor: "red",
  strokeWeight: 2,
  strokeOpacity: 1
});

function initialize() {
  gmap = new google.maps.Map(
    document.getElementById("map_canvas"), {
      center: new google.maps.LatLng(54.10244, -116.96093),
      zoom: 12
    });


  currentMarker.setMap(gmap);
  polyline.setMap(gmap);


  snapToRoute = new SnapToRoute(gmap, currentMarker, polyline);
}

google.maps.event.addDomListener(window, "load", initialize);

function SnapToRoute(map, marker, polyline) {
  this.routePixels_ = [];
  this.normalProj_ = map.getProjection();
  this.map_ = map;
  this.marker_ = marker;
  this.polyline_ = polyline;

  this.init_();
}

SnapToRoute.prototype.init_ = function() {
  this.loadLineData_();
  this.loadMapListener_();
};

SnapToRoute.prototype.updateTargets = function(marker, polyline) {
  this.marker_ = marker || this.marker_;
  this.polyline_ = polyline || this.polyline_;
  this.loadLineData_();
};

SnapToRoute.prototype.loadMapListener_ = function() {
  var me = this;

  google.maps.event.addListener(me.marker_, "dragend", function(evt) {
    me.updateMarkerLocation_(evt.latLng);
  });

  google.maps.event.addListener(me.marker_, "drag", function(evt) {
    me.updateMarkerLocation_(evt.latLng);
  });

  google.maps.event.addListener(me.map_, "zoomend", function(evt) {
    me.loadLineData_();
  });
};

SnapToRoute.prototype.loadLineData_ = function() {
  var zoom = this.map_.getZoom();
  this.routePixels_ = [];
  var path = this.polyline_.getPath();
  for (var i = 0; i < path.getLength(); i++) {
    var Px = this.normalProj_.fromLatLngToPoint(path.getAt(i));
    this.routePixels_.push(Px);
  }
};

SnapToRoute.prototype.updateMarkerLocation_ = function(mouseLatLng) {
  var markerLatLng = this.getClosestLatLng(mouseLatLng);
  this.marker_.setPosition(markerLatLng);
};

SnapToRoute.prototype.getClosestLatLng = function(latlng) {
  var r = this.distanceToLines_(latlng);
  return this.normalProj_.fromPointToLatLng(new google.maps.Point(r.x, r.y));
};

SnapToRoute.prototype.getDistAlongRoute = function(latlng) {
  if (typeof(opt_latlng) === 'undefined') {
    latlng = this.marker_.getLatLng();
  }
  var r = this.distanceToLines_(latlng);
  return this.getDistToLine_(r.i, r.to);
};

SnapToRoute.prototype.distanceToLines_ = function(mouseLatLng) {
  var zoom = this.map_.getZoom();
  var mousePx = this.normalProj_.fromLatLngToPoint(mouseLatLng);
  var routePixels_ = this.routePixels_;
  return this.getClosestPointOnLines_(mousePx, routePixels_);
};

SnapToRoute.prototype.getDistToLine_ = function(line, to) {
  var routeOverlay = this.polyline_;
  var d = 0;
  for (var n = 1; n < line; n++) {
    d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(n - 1), routeOverlay.getAt(n));
  }
  d += google.maps.geometry.spherical.computeDistanceBetween(routeOverlay.getAt(line - 1), routeOverlay.getAt(line)) * to;
  return d;
};

SnapToRoute.prototype.getClosestPointOnLines_ = function(pXy, aXys) {
  var minDist;
  var to;
  var from;
  var x;
  var y;
  var i;
  var dist;

  if (aXys.length > 1) {
    for (var n = 1; n < aXys.length; n++) {
      if (aXys[n].x !== aXys[n - 1].x) {
        var a = (aXys[n].y - aXys[n - 1].y) / (aXys[n].x - aXys[n - 1].x);
        var b = aXys[n].y - a * aXys[n].x;
        dist = Math.abs(a * pXy.x + b - pXy.y) / Math.sqrt(a * a + 1);
      } else {
        dist = Math.abs(pXy.x - aXys[n].x);
      }

      var rl2 = Math.pow(aXys[n].y - aXys[n - 1].y, 2) + Math.pow(aXys[n].x - aXys[n - 1].x, 2);
      var ln2 = Math.pow(aXys[n].y - pXy.y, 2) + Math.pow(aXys[n].x - pXy.x, 2);
      var lnm12 = Math.pow(aXys[n - 1].y - pXy.y, 2) + Math.pow(aXys[n - 1].x - pXy.x, 2);
      var dist2 = Math.pow(dist, 2);
      var calcrl2 = ln2 - dist2 + lnm12 - dist2;
      if (calcrl2 > rl2) {
        dist = Math.sqrt(Math.min(ln2, lnm12));
      }

      if ((minDist == null) || (minDist > dist)) {
        to = Math.sqrt(lnm12 - dist2) / Math.sqrt(rl2);
        from = Math.sqrt(ln2 - dist2) / Math.sqrt(rl2);
        minDist = dist;
        i = n;
      }
    }
    if (to > 1) {
      to = 1;
    }
    if (from > 1) {
      to = 0;
      from = 1;
    }
    x = aXys[i].x; // aXys[i - 1].x - (dx * to);
    y = aXys[i].y; // aXys[i - 1].y - (dy * to);
  }
  return {
    'x': x,
    'y': y,
    'i': i,
    'to': to,
    'from': from
  };
};

html,
body,
#map_canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}

<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=geometry,places&ext=.js"></script>
<div id="map_canvas" style="border: 2px solid #3872ac;"></div>

这篇关于Google Maps API - 在定义的点中沿着折线保持可拖动标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆