[英]Google maps API v3, Multiple custom markers, with different info windows
[英]Using custom popups instead of info windows on Google Maps with multiple markers
在 Google 地圖上自定義信息窗口存在局限性/風險,因為 Google 將來可能會改變他們實施信息窗口 CSS 的方式。 如果您想顯着更改設計,推薦的方法是使用自定義彈出窗口。
但是,Google 自己的關於使用自定義彈出窗口的文檔並沒有說明如何做一些我認為大多數用戶都想知道的關鍵事情。
1) 如何使用帶有多個標記的自定義彈出窗口?
2) 如何切換/隱藏/顯示與特定標記關聯的自定義彈出窗口?
這是我正在使用的創建自定義彈出窗口的文檔: https : //developers-dot-devsite-v2-prod.appspot.com/maps/documentation/javascript/examples/overlay-popup
任何幫助是極大的贊賞。
編輯 - 添加代碼示例和圖像:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Custom Popups</title>
<style>
/* 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;
}
/* The popup bubble styling. */
.popup-bubble {
/* Position the bubble centred-above its parent. */
display: none;
position: absolute;
top: 0;
left: 0;
transform: translate(-50%, -100%);
/* Style the bubble. */
background-color: white;
/* padding: 5px; */
border-radius: 5px;
font-family: sans-serif;
overflow-y: auto;
/* height: 250px; */
/* width: 250px; */
box-shadow: 0px 2px 10px 1px rgba(0,0,0,0.5);
}
/* The parent of the bubble. A zero-height div at the top of the tip. */
.popup-bubble-anchor {
/* Position the div a fixed distance above the tip. */
position: absolute;
width: 100%;
bottom: /* TIP_HEIGHT= */ 8px;
left: 0;
}
/* This element draws the tip. */
.popup-bubble-anchor::after {
content: "";
position: absolute;
top: 0;
left: 0;
/* Center the tip horizontally. */
transform: translate(-50%, 0);
/* The tip is a https://css-tricks.com/snippets/css/css-triangle/ */
width: 0;
height: 0;
/* The tip is 8px high, and 12px wide. */
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: /* TIP_HEIGHT= */ 8px solid white;
}
/* JavaScript will position this div at the bottom of the popup tip. */
.popup-container {
cursor: auto;
height: 0;
position: absolute;
/* The max width of the info window. */
width: 200px;
}
.info-window-img {
height: 170px;
width: 250px;
}
.info-window-text {
padding: 5px;
}
.info-window h1 {
font-size: 18px;
text-align: left;
margin: 0px;
}
.info-window a {
color: #E85A71;
decoration: none;
}
</style>
</head>
<body>
<div id="map"></div>
<script>
var stories = [
{
"name": "First place",
"url": "www.example.com",
"category": "first category",
"lat": 53.3498,
"lng": 6.2603
},
{
"name": "Second place",
"url": "www.example2.com",
"category": "second category",
"lat": 53.0,
"lng": 6.2603
}
];
var map, popup, Popup;
var popups = [];
function addMarkerInfo() {
var bounds = new google.maps.LatLngBounds();
var markers = []
var clusterStyles = [
{
textColor: 'white',
url: `{{ url_for('static', filename='images/') }}` + 'clusterimage.png',
height: 50,
width: 50
}
];
var mcOptions = {
styles: clusterStyles,
}
for (var i = 0; i < stories.length; i++) {
var story = stories[i]
var url = story.url;
var storyname = story.name;
var storycategory = story.category;
var contentString =`
<h1><a href="${url}">${storyname}</a></h1>
<p>${storycategory}</p>`;
const marker = new google.maps.Marker({
position: {lat: story.lat, lng: story.lng},
map: map
});
markers.push(marker)
bounds.extend(marker.position);
map.fitBounds(bounds, 50);
var opt = {
maxZoom: 17,
mapTypeControl: false,
streetViewControl: false
};
map.setOptions(opt);
// POPUP STARTS HERE
Popup = createPopupClass();
popup = new Popup(
new google.maps.LatLng(story.lat, story.lng),
contentString
);
popup.setMap(map);
// popup.draw();
popups[0] = popup;
console.log(popup.containerDiv);
marker.addListener('click', function () {
});
// POPUP ENDS HERE
}
var markerCluster = new MarkerClusterer(map, markers, mcOptions);
}
/** Initializes the map and the custom popup. */
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
});
addMarkerInfo();
}
/**
* Returns the Popup class.
*
* Unfortunately, the Popup class can only be defined after
* google.maps.OverlayView is defined, when the Maps API is loaded.
* This function should be called by initMap.
*/
function createPopupClass() {
/**
* A customized popup on the map.
* @param {!google.maps.LatLng} position
* @param {!Element} content The bubble div.
* @constructor
* @extends {google.maps.OverlayView}
*/
function Popup(position, string) {
this.position = position;
var content = document.createElement('div');
content.classList.add('popup-bubble');
content.classList.add('info-window');
content.innerHTML = string;
// This zero-height div is positioned at the bottom of the bubble.
var bubbleAnchor = document.createElement('div');
bubbleAnchor.classList.add('popup-bubble-anchor');
bubbleAnchor.appendChild(content);
// This zero-height div is positioned at the bottom of the tip.
this.containerDiv = document.createElement('div');
this.containerDiv.classList.add('popup-container');
this.containerDiv.appendChild(bubbleAnchor);
// Optionally stop clicks, etc., from bubbling up to the map.
google.maps.OverlayView.preventMapHitsAndGesturesFrom(this.containerDiv);
}
// ES5 magic to extend google.maps.OverlayView.
Popup.prototype = Object.create(google.maps.OverlayView.prototype);
/** Called when the popup is added to the map. */
Popup.prototype.onAdd = function() {
this.getPanes().floatPane.appendChild(this.containerDiv);
};
/** Called when the popup is removed from the map. */
Popup.prototype.onRemove = function() {
if (this.containerDiv.parentElement) {
this.containerDiv.parentElement.removeChild(this.containerDiv);
}
};
/** Called each frame when the popup needs to draw itself. */
Popup.prototype.draw = function() {
var divPosition = this.getProjection().fromLatLngToDivPixel(this.position);
// Hide the popup when it is far out of view.
var display =
Math.abs(divPosition.x) < 4000 && Math.abs(divPosition.y) < 4000 ?
'block' :
'none';
if (display === 'block') {
this.containerDiv.style.left = divPosition.x + 'px';
this.containerDiv.style.top = divPosition.y + 'px';
}
if (this.containerDiv.style.display !== display) {
this.containerDiv.style.display = display;
}
};
return Popup;
}
</script>
<script src="https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/markerclusterer.js">
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key={{GOOGLE_KEY}}&callback=initMap">
</script>
</body>
</html>
嗨,我希望 2 年后回答還為時不晚......我為這個限制所做的是
創建標記時,除了傳遞位置和地圖外,我還傳遞了一個名為 targetID 的自定義屬性,該 ID 的值將以某種方式與您要顯示的信息相關。 就我而言,它是房屋 ID:
const marker = new google.maps.Marker({
position: {lat: markerLat, lng: markerLong},
map,
targetId: houseId
})
創建 Popup 類時,我添加了第三個參數,稱為 popupID,並在添加該類 popup-container 后將此 popupID 作為 id 添加到 this.containerDiv:
function Popup(position, string, popupId) {
this.position = position;
.
.
.
this.containerDiv.setAttribute('id', popupId)
在創建彈出窗口的新實例時,我只傳遞我在標記中傳遞的相同 id 作為第三個參數:
popup = new Popup(
new google.maps.LatLng(story.lat, story.lng),
contentString,
houseId
)
由於 this.ContainerDiv 現在將 houseId 作為 Id 並且每個標記在自定義屬性中都有 houseId,現在我可以創建一個將偵聽器附加到每個標記的函數(在我的情況下我想要懸停效果)並且這個偵聽器可以獲得一個元素通過 Id 並修改此元素的樣式:
function attachListeners (someMarker){
someMarker.addListener("mouseover", () => {
let myPopup = document.getElementById(someMarker.targetId)
myPopup.style.display = "block";
myPopup.onmouseout = () => {
myPopup.style.display = "none"
}
})
}
在此之后,在將標記推送到標記數組之前,您只需要調用該函數並傳遞標記
.
.
.
attachListener(marker);
markers.push(marker)
我希望你理解我的解決方案並且它對你有用
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.