Программное редактирование пути полилинии оставляет призрачную линию - PullRequest
0 голосов
/ 02 января 2019

У меня есть линии на карте, которые пользователь может редактировать, перетаскивая их вершины. Когда это происходит, я проверяю, находится ли вершина, которую переместил пользователь, рядом с любым другим объектом, в этом случае необходимо присоединить линию к этому объекту.

Более конкретно, когда пользователь перемещает линию, вызывается событие "set_at", и в функции, вызываемой слушателем, строка программно редактируется для присоединения к ближайшему объекту (если таковой имеется). В случае, если объект существует, линия присоединяется к объекту без каких-либо проблем (это означает, что линия правильно присоединена и она работает). Однако на карте линия, сгенерированная пользователем путем перемещения оригинала, все еще видна, но она полупрозрачна. И эта строка в конце концов исчезает, когда на карте выполняется другая операция.

Я попытался очистить путь (path.clear()), создать новый путь, удалить его с карты (setMap(null)) и поместить его снова (setMap(LocationPicker.map.map)). Но, похоже, ничего не работает.

google.maps.event.addListener(marker.getPath(), 'set_at', function(vertex, eventC) {
    LocationPicker.controlVertexMovement(marker,vertex, eventC);
});

controlVertexMovement: function(marker, vertex, eventC) {
    var path = marker.getPath();
    var closest = LocationPicker.searchClosestObject(path.j[vertex].lat(), path.j[vertex].lng());
    if(closest!=null){
        path.j[vertex] = closest.latlng;
        LocationPicker.map.overlays[overlayNum].setPath(path);
    }
}

Фактический результат: https://cdn.pbrd.co/images/HUCyWwu.png Ожидаемый результат: https://cdn.pbrd.co/images/HUCxBfJ.png

пример скрипки

фрагмент кода:

function initialize() {
  var mapOptions = {
    zoom: 3,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: 'terrain'
  };

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

  var flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];
  var flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    editable: true,
    strokeColor: '#FF0000',
    strokeOpacity: 1.0,
    strokeWeight: 2,
    map: map
  });

  var deleteMenu = new DeleteMenu();

  google.maps.event.addListener(flightPath, 'rightclick', function(e) {
    // Check if click was on a vertex control point
    if (e.vertex == undefined) {
      return;
    }
    deleteMenu.open(map, flightPath.getPath(), e.vertex);
  });

  google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) {
    var path = flightPath.getPath();
    path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);
    //marker.setMap(null);
    flightPath.setPath(path);
    //marker.setMap(LocationPicker.map.map);
  });

}

/**
 * A menu that lets a user delete a selected vertex of a path.
 * @constructor
 */
function DeleteMenu() {
  this.div_ = document.createElement('div');
  this.div_.className = 'delete-menu';
  this.div_.innerHTML = 'Delete';

  var menu = this;
  google.maps.event.addDomListener(this.div_, 'click', function() {
    menu.removeVertex();
  });
}
DeleteMenu.prototype = new google.maps.OverlayView();

DeleteMenu.prototype.onAdd = function() {
  var deleteMenu = this;
  var map = this.getMap();
  this.getPanes().floatPane.appendChild(this.div_);

  // mousedown anywhere on the map except on the menu div will close the
  // menu.
  this.divListener_ = google.maps.event.addDomListener(map.getDiv(), 'mousedown', function(e) {
    if (e.target != deleteMenu.div_) {
      deleteMenu.close();
    }
  }, true);
};

DeleteMenu.prototype.onRemove = function() {
  google.maps.event.removeListener(this.divListener_);
  this.div_.parentNode.removeChild(this.div_);

  // clean up
  this.set('position');
  this.set('path');
  this.set('vertex');
};

DeleteMenu.prototype.close = function() {
  this.setMap(null);
};

DeleteMenu.prototype.draw = function() {
  var position = this.get('position');
  var projection = this.getProjection();

  if (!position || !projection) {
    return;
  }

  var point = projection.fromLatLngToDivPixel(position);
  this.div_.style.top = point.y + 'px';
  this.div_.style.left = point.x + 'px';
};

/**
 * Opens the menu at a vertex of a given path.
 */
DeleteMenu.prototype.open = function(map, path, vertex) {
  this.set('position', path.getAt(vertex));
  this.set('path', path);
  this.set('vertex', vertex);
  this.setMap(map);
  this.draw();
};

/**
 * Deletes the vertex from the path.
 */
DeleteMenu.prototype.removeVertex = function() {
  var path = this.get('path');
  var vertex = this.get('vertex');

  if (!path || vertex == undefined) {
    this.close();
    return;
  }

  path.removeAt(vertex);
  this.close();
};

google.maps.event.addDomListener(window, 'load', initialize);
/* Always set the map height explicitly to define the size of the div
 * element that contains the map. */

#map {
  height: 100%;
}


/* Optional: Makes the sample page fill the window. */

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

.delete-menu {
  position: absolute;
  background: white;
  padding: 3px;
  color: #666;
  font-weight: bold;
  border: 1px solid #999;
  font-family: sans-serif;
  font-size: 12px;
  box-shadow: 1px 3px 3px rgba(0, 0, 0, .3);
  margin-top: -10px;
  margin-left: 10px;
  cursor: pointer;
}

.delete-menu:hover {
  background: #eee;
}
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>

1 Ответ

0 голосов
/ 03 января 2019

path.j не является документированным свойством.Не используйте недокументированные свойства, они могут (и будут) меняться с каждым выпуском API.Используйте только документированные свойства / методы.

Не использовать:

path.j[vertex] = new google.maps.LatLng(-34.397, 150.644);

Можно использовать один вариант:

path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));

Например:

google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

function processSetAt(vertex, eventC) {
  // turn off editing
  flightPath.setEditable(false);
  // update the path
  var path = flightPath.getPath();
  path.setAt(vertex,new google.maps.LatLng(-34.397, 150.644));
  flightPath.setPath(path);
  // turn editing back on
  flightPath.setEditable(true);
  google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
} 

подтверждение концепции скрипта

Обратите внимание, что ваша проблема связана с изменением пути полилинии, пока она "редактируема".Единственный способ найти «призрачный» путь - отключить редактирование, изменить ломаную линию, а затем снова включить редактирование.

Другой вариант (из комментария ОП):

Используйте флаг, чтобы избежать бесконечного цикла в событии set at.Вот так:

google.maps.event.addListener(flightPath.getPath(), 'set_at', function(vertex, eventC) { 
  if(!changingPath){ 
    var path = flightPath.getPath(); 
    changingPath = true; 
    path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644)); 
    changingPath = false; 
  } 
}); 

скрипка

фрагмент кода:

function initialize() {
  var mapOptions = {
    zoom: 3,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: 'terrain'
  };

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

  var flightPlanCoordinates = [
    new google.maps.LatLng(37.772323, -122.214897),
    new google.maps.LatLng(21.291982, -157.821856),
    new google.maps.LatLng(-18.142599, 178.431),
    new google.maps.LatLng(-27.46758, 153.027892)
  ];
  var flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    editable: true,
    strokeColor: '#FF0000',
    strokeOpacity: 1.0,
    strokeWeight: 2,
    map: map
  });

  var deleteMenu = new DeleteMenu();

  google.maps.event.addListener(flightPath, 'rightclick', function(e) {
    // Check if click was on a vertex control point
    if (e.vertex == undefined) {
      return;
    }
    deleteMenu.open(map, flightPath.getPath(), e.vertex);
  });

  google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);

  function processSetAt(vertex, eventC) {
    // turn off editing
    flightPath.setEditable(false);
    // update the path
    var path = flightPath.getPath();
    path.setAt(vertex, new google.maps.LatLng(-34.397, 150.644));
    flightPath.setPath(path);
    // turn editing back on
    flightPath.setEditable(true);
    google.maps.event.addListenerOnce(flightPath.getPath(), 'set_at', processSetAt);
  }
}

/**
 * A menu that lets a user delete a selected vertex of a path.
 * @constructor
 */
function DeleteMenu() {
  this.div_ = document.createElement('div');
  this.div_.className = 'delete-menu';
  this.div_.innerHTML = 'Delete';

  var menu = this;
  google.maps.event.addDomListener(this.div_, 'click', function() {
    menu.removeVertex();
  });
}
DeleteMenu.prototype = new google.maps.OverlayView();

DeleteMenu.prototype.onAdd = function() {
  var deleteMenu = this;
  var map = this.getMap();
  this.getPanes().floatPane.appendChild(this.div_);

  // mousedown anywhere on the map except on the menu div will close the
  // menu.
  this.divListener_ = google.maps.event.addDomListener(map.getDiv(), 'mousedown', function(e) {
    if (e.target != deleteMenu.div_) {
      deleteMenu.close();
    }
  }, true);
};

DeleteMenu.prototype.onRemove = function() {
  google.maps.event.removeListener(this.divListener_);
  this.div_.parentNode.removeChild(this.div_);

  // clean up
  this.set('position');
  this.set('path');
  this.set('vertex');
};

DeleteMenu.prototype.close = function() {
  this.setMap(null);
};

DeleteMenu.prototype.draw = function() {
  var position = this.get('position');
  var projection = this.getProjection();

  if (!position || !projection) {
    return;
  }

  var point = projection.fromLatLngToDivPixel(position);
  this.div_.style.top = point.y + 'px';
  this.div_.style.left = point.x + 'px';
};

/**
 * Opens the menu at a vertex of a given path.
 */
DeleteMenu.prototype.open = function(map, path, vertex) {
  this.set('position', path.getAt(vertex));
  this.set('path', path);
  this.set('vertex', vertex);
  this.setMap(map);
  this.draw();
};

/**
 * Deletes the vertex from the path.
 */
DeleteMenu.prototype.removeVertex = function() {
  var path = this.get('path');
  var vertex = this.get('vertex');

  if (!path || vertex == undefined) {
    this.close();
    return;
  }

  path.removeAt(vertex);
  this.close();
};

google.maps.event.addDomListener(window, 'load', initialize);
#map {
  height: 100%;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

.delete-menu {
  position: absolute;
  background: white;
  padding: 3px;
  color: #666;
  font-weight: bold;
  border: 1px solid #999;
  font-family: sans-serif;
  font-size: 12px;
  box-shadow: 1px 3px 3px rgba(0, 0, 0, .3);
  margin-top: -10px;
  margin-left: 10px;
  cursor: pointer;
}

.delete-menu:hover {
  background: #eee;
}
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
...