禁用Google地图上的拖动Javascript自定义控件

时间:2017-07-04 16:26:42

标签: javascript api google-maps-api-3 custom-controls

我想使用Javascript API创建Google地图自定义控件。

该控件是一个“添加航点”按钮。用户应该能够从控件拖动,导致标记出现在鼠标指针上,并将此标记放在地图上。

预期的行为几乎与现有的街头小人物相同。

问题是Google地图控件似乎与拖动相互作用,即使已明确禁用拖动,如下所示。

在示例代码中,第一次单击并拖动时,它按预期工作。第二次单击并拖动时,我得到一个“无拖动”图标,控件会产生一个鬼魂。我第三次拖,它再次起作用。在下一次拖动时,会出现“无阻力”。序列继续,奇怪的拖动工作,甚至拖动失败。

以下是我认为的相关部分:

<div id="map"></div>
<script>
    var spawning = false;
    var inProgress = false;
    var waypointSpawner;
    var targetLat;
    var targetLng;

    function initMap()
    {
        map = new google.maps.Map(document.getElementById('map'), {
            center: {lat: 0.0000, lng: 0.0000},
            zoom: 2
        });

        // Create the DIV to hold the control and call the CenterControl()
        // constructor passing in this DIV.
        var centerControlDiv = document.createElement('div');
        var centerControl = new CenterControl(centerControlDiv, map);

        centerControlDiv.index = 1;
        map.controls[google.maps.ControlPosition.LEFT_TOP].push(centerControlDiv);
    }

    function CenterControl(controlDiv, map) {

        // Set CSS for the control border.
        var controlUI = document.createElement('div');
        controlUI.style.backgroundColor = '#fff';
        controlUI.style.border = '2px solid #fff';
        controlUI.style.borderRadius = '3px';
        controlUI.style.boxShadow = '0 2px 6px rgba(0,0,0,.3)';
        controlUI.style.cursor = 'pointer';
        controlUI.style.marginBottom = '22px';
        controlUI.style.width = '40px';
        controlUI.style.height = '50px';
        controlUI.style.opacity = "0.7";
        controlUI.style.backgroundImage = "url('create_waypoint_icon.png')";
        controlUI.title = 'Add Waypoint';
        controlUI.draggable = "false";


    //controlDiv.draggable = "false";
    controlDiv.appendChild(controlUI);
    }

我无法让上面的代码在jsfiddle中工作,但还有其他一些例子说明了这个问题。

http://jsfiddle.net/maunovaha/jptLfhc8/

尝试拖放地图左上角的蓝色和绿色方块会导致一些意外行为。根据您的缩放级别,有些随机,您将获得各种不同的结果 -

1 - 什么都没发生。指针保持为手指并正常移动 2 - 手指指针变为“无阻力”但正常移动。
3 - 手指指针变为“无拖动”和蓝色和绿色半透明“粘贴”小部件 4 - 手指指针变为“无拖动”,小部件的蓝色或绿色半部分(取决于您的选择)随之而来。

这种行为在Google控件示例代码中也有些明显: https://developers.google.com/maps/documentation/javascript/examples/control-custom

在这种情况下,当文本突出显示时,您会看到“无拖动”图标。父控件似乎不可选,这是期望的目标。

我相信自定义控件正在获取某种“焦点”状态,再次单击它会清除焦点。这种行为在绿色/蓝色示例中很明显。也许控制是以某种方式“突出”的?

我试图实现How can I make a div unselectable?中给出的解决方案无效。我还尝试了各种方法使代码中的div不可分割,但这似乎没有任何影响。

我还尝试在程序的其他部分模拟鼠标点击,并双击控件,更改焦点/突出显示状态,但似乎API实际上不执行点击,只生成来自他们的事件。我找不到引起'真正'点击的方法。手动单击,然后单击并拖动工作。

我也尝试使控件可拖动,但即使拖动它也仍然有“无拖动”鼠标指针。

1 个答案:

答案 0 :(得分:0)

如果我理解你所说的内容,你希望能够从外面将标记拖到地图上,并在该位置上放置一个点。

我有以下解决方案。

首先我们需要构建地图:

function buildMap() {
        var g = google.maps;
        var mapOptions = {        
        center: new g.LatLng(52.052491, 9.84375),
        zoom: 4,
        mapTypeId: g.MapTypeId.ROADMAP,
        streetViewControl: false,
        panControl: false
      };
      map = new g.Map(document.getElementById("map"), mapOptions);
      iw = new g.InfoWindow();
      g.event.addListener(map, "click", function() {
        if (iw) iw.close()
      });
      drag_area = document.getElementById("markers");
      var b = drag_area.getElementsByTagName("div");
      b[0].onmousedown = initDrag
      dummy = new DummyOView()
    }

我们创建一个标准地图并添加infoWindows等功能,以便在添加标记时显示lat lng。

此外,我们得到了标记所在的位置,onMouseDown调用了一个函数(很快就会出现)。

我们使用b[0],因为我们在下面的标记中获得了第一组<div>标记,这是可拖动图标的位置:

<div id="markers">
  <div id="m1" class="drag" style="left:0; background-image: url('https://maps.gstatic.com/mapfiles/ms/icons/ltblue-dot.png')">
  </div>
</div>

DummyOView是一个地图OverlayView,它允许我们拖动到地图上并抓住坐标和位置。有关SO +积分的更多信息:More info

function DummyOView() {
  this.setMap(map);
  this.draw = function() {}
}

DummyOView.prototype = new google.maps.OverlayView();

initDrag函数是完成大部分工作的地方,这是一个非常冗长的函数,所以我对代码做了评论,任何有关澄清的问题都只是添加注释。

//function that allows us to drag the marker from the div to the map
function initDrag(e) {
  //allows us to drag the marker and keep record of the clientX client Y coordinates
  var j = function(e) {
    var a = {};
    if (!e) var e = window.event;
    a.x = e.clientX;
    a.y = e.clientY
    return a
  };
  //function called whenever the mouse moves. this will keep track of the marker as we move around
  var k = function(e) {
    //check to ensure that the object is of class drag - otherwise we could drag everything
    if (obj && obj.className == "drag") {
      var i = j(e),
        deltaX = i.x - l.x,
        deltaY = i.y - l.y;
      obj.style.left = (obj.x + deltaX) + "px";
      obj.style.top = (obj.y + deltaY) + "px";
      obj.onmouseup = function() {
        //get the information to check to see if the dragObj is on the map on mouse up
        var a = map.getDiv(),
          mLeft = a.offsetLeft,
          mTop = a.offsetTop,
          mWidth = a.offsetWidth,
          mHeight = a.offsetHeight;
        var b = drag_area.offsetLeft,
          areaTop = drag_area.offsetTop,
          oWidth = obj.offsetWidth,
          oHeight = obj.offsetHeight;
        //check to see if obj is in bounds of map div X and Y
        var x = obj.offsetLeft + b + oWidth / 2;
        var y = obj.offsetTop + areaTop + oHeight / 2;
        if (x > mLeft && x < (mLeft + mWidth) && y > mTop && y < (mTop + mHeight)) {
          var c = 1;
          var mapTemp = google.maps;
          var point = new mapTemp.Point(x - mLeft - c, y - mTop + (oHeight / 2));
          var proj = dummy.getProjection();
          var latlng = proj.fromContainerPixelToLatLng(point);
          var backImage = obj.style.backgroundImage.slice(4, -1).replace(/"/g, "");
          createDraggedMarker(latlng, backImage);
          fillMarker(backImage)
        }
      }
    }
    return false
  };

  //assign the event to a windows event
  obj = e.target ? e.target : e.srcElement;
  //if the object where the event took place is not called drag cancel the event
  if (obj.className != "drag") {
    if (e.cancelable) e.preventDefault();
    obj = null;
    return
  } else {
    z_index += 1;
    obj.style.zIndex = z_index.toString();
    obj.x = obj.offsetLeft;
    obj.y = obj.offsetTop;

    var l = j(e); //get the initial position of the marker relative to the client

    document.onmousemove = k;
    //if we lift the mouse up outside the map div set to null and leave where it is
    document.onmouseup = function() {
      document.onmousemove = null;
      document.onmouseup = null;
      if (obj) obj = null
    }
  }
  return false
}

只要单击并拖动鼠标,就会调用此函数。它注册了地图div的起始位置和位置,并检查onmouseup以查看当前鼠标位置是否在地图div上。如果是这样,我们在地图上创建一个标记,并将标记图标重新添加到div以允许重新标记。

//when the marker is dragged onto the map
//we call this function to create a marker on the map
function createDraggedMarker(position, iconImage) {
  var mapLocal = google.maps;
  var icon = {
    url: iconImage,
    size: new mapLocal.Size(32, 32),
    anchor: new mapLocal.Point(15, 32)
  };
  var marker = new mapLocal.Marker({
    position: position,
    map: map,
    clickable: true,
    draggable: true,
    crossOnDrag: false,
    optimized: false,
    icon: icon,
    zIndex: highestOrder()
  });

  mapLocal.event.addListener(marker, "click", function() {
    actual = marker;
    var lat = actual.getPosition().lat();
    var lng = actual.getPosition().lng();
    var innerHtml = "<div class='infowindow'>" + lat.toFixed(6) + ", " + lng.toFixed(6) + "<\/div>";
    iw.setContent(innerHtml);
    iw.open(map, this)
  });
  mapLocal.event.addListener(marker, "dragstart", function() {
    if (actual == marker) iw.close();
    z_index += 1;
    marker.setZIndex(highestOrder())
  })
}

将标记重新添加到div

//Used to replace the marker
//once we have moved it from its div
function fillMarker(a) {
  var div = document.createElement("div");
  div.style.backgroundImage = "url(" + a + ")";
  var padding;
  if (obj.id == "m1") {
    padding = "0px"
  }
  div.style.left = padding;
  div.id = obj.id;
  div.className = "drag";
  div.onmousedown = initDrag;
  drag_area.replaceChild(div, obj);
  obj = null
}

JSfiddle你可以使用:https://jsfiddle.net/q3wjrpdw/7/

任何问题随时可以提出。