如何知道 Google 地图何时在平移之后重新定位了一个或所有标记
How to know when Google Maps has repositioned a or all Markers after Pan
我用map.panTo(perthLatLng);
移动地图。然后我等待空闲事件 addListenerOnce(map, 'idle', panDone);
到目前为止一切顺利,但是在“panDone”时间,我的地图标记仍处于“旧”屏幕 Top/Left 位置并且尚未迁移到其新位置 x/y.
当 Google 地图最终将我的标记位置与新 Pan 同步时,是否有事件或其他启发式让我知道?
编辑: 因为地图 API 键你不能 运行 testmap.html 直接从 Github 文件,但您可以将 testmap.html 复制到您的文件系统并从那里激活(double-click 或 file:// URL)。
下面是我为解决这个难题而尽力而为的完整 SSCCE 策略。我使用 CSS 转换为:-
- 检测地图 API 何时最终在 Pan
之后重新定位我的标记
- 顺利地将我的标记转移到旅程中的下一个位置
注意:一旦“重播”功能可用,我将很快用大量新代码更新 Brotkrumen:-(
另请注意,对于 运行 下面的示例,只需将代码复制到 HTML 文件并单击它。但在此之前,您还必须将 Hansel and Gretal 的副本复制到同一文件夹。
如果您有 another/better 诱捕 Google-Map-API-PanTo-Really-Really-Finished 的方法,请告诉我。 “空闲”事件有助于了解地图图块何时就位,仅此而已。
PS。如果有人认为 CSS Transitions 在这里没有任何价值,这应该用现有的口吃库来完成,那么请不要用相同的东西来混淆这个问题。
<!DOCTYPE html>
<html>
<head>
<title>Smooth Runnings</title>
<script type="application/javascript">
'use strict';
/* identification division.
* program-id. GotTheMovesLikeJagger.
* author. Richard Maher.
* version. 1.0
*/
document.addEventListener("DOMContentLoaded", isDOMIsGood);
const MARKER_SELECTOR = "img[src*='hg.png'";
const MARKER_SRC = "http://localhost/hg.png";
const myLatLng = { lat: -25.363, lng: 131.044 };
var mapDiv, protagonists, HandG, map, observer, markerDiv,
markerStyle, travelListener;
var dest = [
{ lat: -31.9523, lng: 115.8613 },
{ lat: -33.8688, lng: 151.2093 },
{ lat: -27.4705, lng: 153.0260 },
{ lat: -34.9285, lng: 138.6007 }
];
var destIndex = 0;
var touchDown = false;
function isDOMIsGood(e) {
console.log("DOM");
mapDiv = document.getElementById("map");
}
function initMap() {
console.log("Init");
map = new google.maps.Map(mapDiv, {
zoom: 4,
center: myLatLng,
});
observer = new MutationObserver(waitForMarker);
protagonists = {size: new google.maps.Size(45, 40),
scaledSize: new google.maps.Size(45, 40),
url: MARKER_SRC};
google.maps.event.addListenerOnce(map,'tilesloaded', tilesUp);
}
function tilesUp() {
console.log("Map Tiles Here");
travelListener = google.maps.event.addListener(map, 'center_changed', centerChanged);
observer.observe(mapDiv, {
childList : true,
subtree : true ,
attributes : true ,
characterData : false
});
HandG = new google.maps.Marker(
{
position: myLatLng,
map: map,
draggable: false,
title: "HandG",
zIndex: 12,
visible: true,
icon: protagonists,
optimized: false
});
}
function makeDestCenter(){
console.log("Panning to new Center");
map.panTo(dest[destIndex]);
}
function centerChanged() {
console.log("Center changed Left = " + markerStyle.left + " Top = " + markerStyle.top);
markerDiv.style.visibility = "hidden";
markerDiv.style.transitionDuration = "1ms";
markerDiv.style.transitionTimingFunction = "linear";
markerDiv.style.transitionProperty = "left, top";
markerDiv.addEventListener('transitionend', quiesced, { 'once': true });
markerDiv.addEventListener('transitioncancel', quiesced, { 'once': true });
}
function quiesced(e) {
markerDiv.style.visibility = "visible";
console.log("Quiesced " + e.type + " left " + markerStyle.left + " top " + markerStyle.top);
setTimeout(handover, 0);
}
function handover(e) {
console.log("in handover left " + markerStyle.left + " top " + markerStyle.top);
markerDiv.style.transitionDuration = 2000 + "ms";
markerDiv.style.transitionTimingFunction = "linear";
markerDiv.addEventListener('transitionend', incrSteps, { 'once': true });
markerDiv.style.transitionProperty = "left, top";
HandG.setPosition(dest[destIndex]);
}
function startLeg(e) {
console.log("start leg " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
}
function cancelLeg(e) {
console.log("Cancel leg " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
markerDiv.style.transitionDuration = "0s";
}
function incrSteps(e) {
console.log("Incr Steps " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
if (++destIndex >= dest.length) {
console.log("Journey's end");
markerDiv.style.transitionDuration = "0s";
travelListener.remove();
return;
}
setTimeout(makeDestCenter,0);
}
function waitForMarker(mutations, myInstance) {
outer:
for (var i=0; i<mutations.length; i++){
if (mutations[i].type == "attributes" &&
mutations[i].target.tagName == "IMG" &&
mutations[i].target.src.toLowerCase().indexOf(MARKER_SRC) != -1){
touchDown = true;
break outer;
}
if (mutations[i].type != "childList" ||
mutations[i].addedNodes.length == 0)
continue;
for (var j=0; j<mutations[i].addedNodes.length; j++) {
var node = mutations[i].addedNodes[j];
if (node.tagName == "DIV" && node.firstChild && node.firstChild.tagName == "IMG" &&
node.firstChild.src.toLowerCase().indexOf(MARKER_SRC) != -1){
touchDown = true;
break outer;
}
}
}
if (touchDown) {
console.log("Got Marker");
myInstance.disconnect();
var markerImgs = document.querySelectorAll(MARKER_SELECTOR);
if (markerImgs.length != 1) {
throw new Error("Expecting one and only one Hansel and Gretal. Found: " + markerImgs.length);
};
markerDiv = markerImgs[0].parentNode;
markerStyle = getComputedStyle(markerDiv);
markerDiv.addEventListener('transitionstart', startLeg);
markerDiv.addEventListener('transitioncancel', cancelLeg);
console.log("Left = " + markerStyle.left + " Top = " + markerStyle.top);
setTimeout(makeDestCenter,0);
}
}
</script>
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly&channel=2" async
></script>
<style type="text/css">
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
</html>
我用map.panTo(perthLatLng);
移动地图。然后我等待空闲事件 addListenerOnce(map, 'idle', panDone);
到目前为止一切顺利,但是在“panDone”时间,我的地图标记仍处于“旧”屏幕 Top/Left 位置并且尚未迁移到其新位置 x/y.
当 Google 地图最终将我的标记位置与新 Pan 同步时,是否有事件或其他启发式让我知道?
编辑: 因为地图 API 键你不能 运行 testmap.html 直接从 Github 文件,但您可以将 testmap.html 复制到您的文件系统并从那里激活(double-click 或 file:// URL)。
下面是我为解决这个难题而尽力而为的完整 SSCCE 策略。我使用 CSS 转换为:-
- 检测地图 API 何时最终在 Pan 之后重新定位我的标记
- 顺利地将我的标记转移到旅程中的下一个位置
注意:一旦“重播”功能可用,我将很快用大量新代码更新 Brotkrumen:-(
另请注意,对于 运行 下面的示例,只需将代码复制到 HTML 文件并单击它。但在此之前,您还必须将 Hansel and Gretal 的副本复制到同一文件夹。
如果您有 another/better 诱捕 Google-Map-API-PanTo-Really-Really-Finished 的方法,请告诉我。 “空闲”事件有助于了解地图图块何时就位,仅此而已。
PS。如果有人认为 CSS Transitions 在这里没有任何价值,这应该用现有的口吃库来完成,那么请不要用相同的东西来混淆这个问题。
<!DOCTYPE html>
<html>
<head>
<title>Smooth Runnings</title>
<script type="application/javascript">
'use strict';
/* identification division.
* program-id. GotTheMovesLikeJagger.
* author. Richard Maher.
* version. 1.0
*/
document.addEventListener("DOMContentLoaded", isDOMIsGood);
const MARKER_SELECTOR = "img[src*='hg.png'";
const MARKER_SRC = "http://localhost/hg.png";
const myLatLng = { lat: -25.363, lng: 131.044 };
var mapDiv, protagonists, HandG, map, observer, markerDiv,
markerStyle, travelListener;
var dest = [
{ lat: -31.9523, lng: 115.8613 },
{ lat: -33.8688, lng: 151.2093 },
{ lat: -27.4705, lng: 153.0260 },
{ lat: -34.9285, lng: 138.6007 }
];
var destIndex = 0;
var touchDown = false;
function isDOMIsGood(e) {
console.log("DOM");
mapDiv = document.getElementById("map");
}
function initMap() {
console.log("Init");
map = new google.maps.Map(mapDiv, {
zoom: 4,
center: myLatLng,
});
observer = new MutationObserver(waitForMarker);
protagonists = {size: new google.maps.Size(45, 40),
scaledSize: new google.maps.Size(45, 40),
url: MARKER_SRC};
google.maps.event.addListenerOnce(map,'tilesloaded', tilesUp);
}
function tilesUp() {
console.log("Map Tiles Here");
travelListener = google.maps.event.addListener(map, 'center_changed', centerChanged);
observer.observe(mapDiv, {
childList : true,
subtree : true ,
attributes : true ,
characterData : false
});
HandG = new google.maps.Marker(
{
position: myLatLng,
map: map,
draggable: false,
title: "HandG",
zIndex: 12,
visible: true,
icon: protagonists,
optimized: false
});
}
function makeDestCenter(){
console.log("Panning to new Center");
map.panTo(dest[destIndex]);
}
function centerChanged() {
console.log("Center changed Left = " + markerStyle.left + " Top = " + markerStyle.top);
markerDiv.style.visibility = "hidden";
markerDiv.style.transitionDuration = "1ms";
markerDiv.style.transitionTimingFunction = "linear";
markerDiv.style.transitionProperty = "left, top";
markerDiv.addEventListener('transitionend', quiesced, { 'once': true });
markerDiv.addEventListener('transitioncancel', quiesced, { 'once': true });
}
function quiesced(e) {
markerDiv.style.visibility = "visible";
console.log("Quiesced " + e.type + " left " + markerStyle.left + " top " + markerStyle.top);
setTimeout(handover, 0);
}
function handover(e) {
console.log("in handover left " + markerStyle.left + " top " + markerStyle.top);
markerDiv.style.transitionDuration = 2000 + "ms";
markerDiv.style.transitionTimingFunction = "linear";
markerDiv.addEventListener('transitionend', incrSteps, { 'once': true });
markerDiv.style.transitionProperty = "left, top";
HandG.setPosition(dest[destIndex]);
}
function startLeg(e) {
console.log("start leg " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
}
function cancelLeg(e) {
console.log("Cancel leg " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
markerDiv.style.transitionDuration = "0s";
}
function incrSteps(e) {
console.log("Incr Steps " + e.propertyName + " left " + e.target.style.left + " top " + e.target.style.top);
if (++destIndex >= dest.length) {
console.log("Journey's end");
markerDiv.style.transitionDuration = "0s";
travelListener.remove();
return;
}
setTimeout(makeDestCenter,0);
}
function waitForMarker(mutations, myInstance) {
outer:
for (var i=0; i<mutations.length; i++){
if (mutations[i].type == "attributes" &&
mutations[i].target.tagName == "IMG" &&
mutations[i].target.src.toLowerCase().indexOf(MARKER_SRC) != -1){
touchDown = true;
break outer;
}
if (mutations[i].type != "childList" ||
mutations[i].addedNodes.length == 0)
continue;
for (var j=0; j<mutations[i].addedNodes.length; j++) {
var node = mutations[i].addedNodes[j];
if (node.tagName == "DIV" && node.firstChild && node.firstChild.tagName == "IMG" &&
node.firstChild.src.toLowerCase().indexOf(MARKER_SRC) != -1){
touchDown = true;
break outer;
}
}
}
if (touchDown) {
console.log("Got Marker");
myInstance.disconnect();
var markerImgs = document.querySelectorAll(MARKER_SELECTOR);
if (markerImgs.length != 1) {
throw new Error("Expecting one and only one Hansel and Gretal. Found: " + markerImgs.length);
};
markerDiv = markerImgs[0].parentNode;
markerStyle = getComputedStyle(markerDiv);
markerDiv.addEventListener('transitionstart', startLeg);
markerDiv.addEventListener('transitioncancel', cancelLeg);
console.log("Left = " + markerStyle.left + " Top = " + markerStyle.top);
setTimeout(makeDestCenter,0);
}
}
</script>
<script
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly&channel=2" async
></script>
<style type="text/css">
#map {
height: 100%;
}
/* Optional: Makes the sample page fill the window. */
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="map"></div>
</body>
</html>