Я хочу создать собственный пользовательский элемент управления Google, используя API Javascript.
Элемент управления - кнопка "добавить путевую точку". Предполагается, что пользователь сможет перетащить элемент управления, заставив маркер появиться у указателя мыши, и поместите этот маркер на карту.
Предполагаемое поведение почти идентично существующей функции pegman.
Проблема в том, что элементы управления картой 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
В этом случае, когда текст выделен, вы получаете значок "без перетаскивания". Родительский элемент управления не может быть выбран, что является желаемой целью.
Я считаю, что пользовательский контроль приобретает какой-то статус "фокуса", а щелчок снова очищает фокус. Такое поведение проявляется в примере "зеленый/синий". Может быть, контроль "подсвечивается" каким-то образом?
Я попытался реализовать решения, приведенные в разделе Как я могу сделать div неизбираемым? без эффекта. Я также пробовал различные способы сделать div неразборчивым в коде, но это, похоже, не оказало никакого влияния.
Я также попытался имитировать щелчки мыши на других частях программы и дважды щелкнул элемент управления, чтобы изменить статус фокуса/выделения, но, похоже, API фактически не выполняет клики, а генерирует из них только события. Я не мог найти способ вызвать "настоящий" клик. Ручное нажатие, а затем перетаскивание и перетаскивание.
Я также попытался сделать управление перетаскиваемым, но у него все еще есть указатель мыши "без перетаскивания" даже при перетаскивании.
Если я правильно понимаю, что вы говорите, вы хотите, чтобы вы могли перетащить маркер на карту, извне, и поместить точку в эту позицию.
У меня есть следующее решение, которое делает это.
Сначала нам нужно построить карту:
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 + credit to: Дополнительная информация
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, чтобы разрешить краху.
//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/
Любые вопросы, не стесняйтесь спрашивать.