Javascript 谷歌地图v3-删除多边形上的顶点

Javascript 谷歌地图v3-删除多边形上的顶点,javascript,google-maps,drawing,polygon,Javascript,Google Maps,Drawing,Polygon,谷歌地图有绘图库来绘制多段线、多边形和其他东西 此功能的示例如下: 在绘制和编辑多边形时,我希望能够删除路径上的一个点/顶点。API文档似乎没有任何暗示。这是目前一个未完成的功能请求(谷歌已确认) 这是我的解决方案:。它使用一个函数,将删除按钮添加到传入的多边形(位于“撤消”按钮下方) 或者,有人提出了这种方法:,它工作得很好,但在UI技巧方面有所欠缺。我基于链接中的代码来检查单击是否在节点内部(或在节点的1像素范围内)-在JSBin中 编辑:如前所述-此方法目前已被打破,因为事件需要附加到多

谷歌地图有绘图库来绘制多段线、多边形和其他东西

此功能的示例如下:


在绘制和编辑多边形时,我希望能够删除路径上的一个点/顶点。API文档似乎没有任何暗示。

这是目前一个未完成的功能请求(谷歌已确认)

这是我的解决方案:。它使用一个函数,将删除按钮添加到传入的多边形(位于“撤消”按钮下方)


或者,有人提出了这种方法:,它工作得很好,但在UI技巧方面有所欠缺。我基于链接中的代码来检查单击是否在节点内部(或在节点的1像素范围内)-在JSBin中


编辑:如前所述-此方法目前已被打破,因为事件需要附加到多边形。

谷歌地图现在为从多边形或多段线触发的事件提供了一个“”回调对象

要在其他答案的基础上构建一个包含右键单击的解决方案,您只需在V3 API的最新版本中执行以下操作:

// this assumes `my_poly` is an normal google.maps.Polygon or Polyline
var deleteNode = function(mev) {
  if (mev.vertex != null) {
    my_poly.getPath().removeAt(mev.vertex);
  }
}
google.maps.event.addListener(my_poly, 'rightclick', deleteNode);
你会注意到,不再需要任何关于我们是否接近点的复杂计算,因为谷歌地图API现在告诉我们点击了哪个顶点

注意:这仅在多段线/多边形处于编辑模式时有效。(此时可能要删除的顶点可见。)


作为最后一个想法,你可以考虑使用点击或双击事件来代替。“点击”足够聪明,不会在拖动时触发,尽管使用一次点击触发可能仍然会让一些用户感到惊讶。

我发现肖恩的代码非常简单,而且非常有用。我刚刚添加了一个限制器,在用户只剩下3个节点时停止删除。如果没有它,用户只能访问一个节点,并且无法再编辑:

my_poly.addListener('rightclick', function(mev){
    if (mev.vertex != null && this.getPath().getLength() > 3) {
        this.getPath().removeAt(mev.vertex);
    }
});

我想我会有所贡献,因为我也在寻找解决方案,以下是我的实现:

if (m_event.hasOwnProperty('edge') && m_event.edge >= 0 &&
GeofenceService.polygon.getPath().getLength() > 3) {
    GeofenceService.polygon.getPath().removeAt(m_event.edge);
    return;
}

if (m_event.hasOwnProperty('vertex') && m_event.vertex >= 0 &&
GeofenceService.polygon.getPath().getLength() > 3) {
    GeofenceService.polygon.getPath().removeAt(m_event.vertex);
    return;
}

这允许处理顶点节点和边节点的删除,并通过检查路径长度>3始终保持三角形形成多边形的最小值。

我遇到需要从包含多条路径的多边形中删除节点的情况。下面是对肖恩和邪恶的代码的修改:

shape.addListener('rightclick', function(event){
  if(event.path != null && event.vertex != null){
    var path = this.getPaths().getAt(event.path);
    if(path.getLength() > 3){
      path.removeAt(event.vertex);
    }
  }
});

2020年更新

谷歌在他们的文档中提供了一个工作演示,演示了如何通过右键单击顶点来显示“删除”菜单来删除顶点或线上的点

退房

完整性代码(见其附录)


您的演示页面在FF、IE和Chrome中对我有效,但在Opera中无效,Opera似乎覆盖了右键单击事件。但是Thx.Right-Opera在默认情况下允许脚本执行的操作可能有点吝啬。这有帮助吗:不要听起来像专家的改变或任何东西,但如果有帮助的话+1我!:)我使用“右键单击删除”方法已经有一段时间了,效果很好。然而,谷歌地图最近的一次更新似乎已经停止了这一功能。我最初以为这是我的代码,但你的两个例子都停止工作太…讨厌!我在这里发布了关于这个问题的帖子(),幸运的是,我收到了回复。看起来编辑控制柄现在会生成附着到多边形本身的单击事件。因此,要修改答案中的两个示例,请将多边形的clickable属性更改为true,并将右键单击事件侦听器附加到多边形,而不是贴图。您可以在回调中切换
my_poly
,以查看
this
。我用
点击
并用
确认
对话框进行保护。。。我不认为用户会猜测右键单击(上下文菜单)或双击(缩放),但单击是自然的。谢谢这对于具有多条路径的多边形(例如甜甜圈)不起作用。请参阅我的答案,以了解正确处理多个路径的代码。保留两个节点仍然可以,因为它们之间有一个褪色的节点,可以创建一个新的节点。但是谢谢你的提示,我用了它。优雅的解决方案!需要一个改变。多边形在路径中有+1个顶点,因为它们需要一个额外的点来闭合多边形。所以把3改成4。那对我有用。谢谢!这是一个救星(:链接不再工作。
function initialize() {
  const mapOptions = {
    zoom: 3,
    center: new google.maps.LatLng(0, -180),
    mapTypeId: "terrain",
  };
  const map = new google.maps.Map(document.getElementById("map"), mapOptions);
  const 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),
  ];
  const flightPath = new google.maps.Polyline({
    path: flightPlanCoordinates,
    editable: true,
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 2,
    map: map,
  });

  /**
   * A menu that lets a user delete a selected vertex of a path.
   */
  class DeleteMenu extends google.maps.OverlayView {
    constructor() {
      super();
      this.div_ = document.createElement("div");
      this.div_.className = "delete-menu";
      this.div_.innerHTML = "Delete";
      const menu = this;
      google.maps.event.addDomListener(this.div_, "click", () => {
        menu.removeVertex();
      });
    }
    onAdd() {
      const deleteMenu = this;
      const 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",
        (e) => {
          if (e.target != deleteMenu.div_) {
            deleteMenu.close();
          }
        },
        true
      );
    }
    onRemove() {
      if (this.divListener_) {
        google.maps.event.removeListener(this.divListener_);
      }
      this.div_.parentNode.removeChild(this.div_);
      // clean up
      this.set("position", null);
      this.set("path", null);
      this.set("vertex", null);
    }
    close() {
      this.setMap(null);
    }
    draw() {
      const position = this.get("position");
      const projection = this.getProjection();

      if (!position || !projection) {
        return;
      }
      const 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.
     */
    open(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.
     */
    removeVertex() {
      const path = this.get("path");
      const vertex = this.get("vertex");

      if (!path || vertex == undefined) {
        this.close();
        return;
      }
      path.removeAt(vertex);
      this.close();
    }
  }
  const deleteMenu = new DeleteMenu();
  google.maps.event.addListener(flightPath, "rightclick", (e) => {
    // Check if click was on a vertex control point
    if (e.vertex == undefined) {
      return;
    }
    deleteMenu.open(map, flightPath.getPath(), e.vertex);
  });
}