如何在Google Maps API中为OpenStreetMap瓦片设置正确归属信息?
解决Google Maps切换OSM图层时版权信息自动重置的问题
问题核心
Google Maps API在切换地图类型、平移、缩放等操作时,会自动重绘右下角的版权信息区域,导致通过DOM临时修改的OSM归属文本被覆盖。而API的ImageMapType和ImageMapTypeOptions类中,并没有直接为自定义图层设置版权信息的配置项,因此需要通过更可靠的方式实现持久化替换。
最优方案:用MutationObserver监听DOM变化
通过MutationObserver可以实时监测版权文本元素的内容变化,一旦Google重写了文本,立即自动替换为OSM的标准归属信息,无需依赖定时器或监听所有地图交互事件。
实现代码
// 初始化地图后创建MutationObserver实例 const copyrightObserver = new MutationObserver((mutations) => { const currentMapType = map.getMapTypeId(); if (currentMapType !== "OSM") return; mutations.forEach((mutation) => { // 监听元素内容或子节点变化 if (mutation.type === 'childList' || mutation.type === 'characterData') { const copyrightSpans = document.querySelectorAll("div.gmnoprint > div.gm-style-cc span"); copyrightSpans.forEach(item => { // 仅替换默认的版权提示文本,避免重复修改 if (item.textContent.includes("Image may be subject to copyright")) { item.innerHTML = `© <a href="https://www.openstreetmap.org">OpenStreetMap contributors</a>`; } }); } }); }); // 定位版权容器并启动监听 const copyrightContainer = document.querySelector("div.gmnoprint > div.gm-style-cc"); if (copyrightContainer) { copyrightObserver.observe(copyrightContainer, { childList: true, subtree: true, characterData: true }); } // 保留地图类型切换监听,确保初始切换时立即生效 map.addListener('maptypeid_changed', function() { const currentMapType = map.getMapTypeId(); if (currentMapType === "OSM") { setTimeout(() => { const copyrightSpans = document.querySelectorAll("div.gmnoprint > div.gm-style-cc span"); copyrightSpans.forEach(item => { item.innerHTML = `© <a href="https://www.openstreetmap.org">OpenStreetMap contributors</a>`; }); }, 100); // 缩短延迟,后续重写由Observer处理 } });
代码说明
MutationObserver会实时监控版权容器的内容变化,一旦Google重写文本就触发替换逻辑,彻底解决地图操作导致的文本重置问题。- 添加文本内容判断,避免重复修改已经正确的OSM归属信息,提升性能。
- 保留
maptypeid_changed监听作为初始触发,配合短延迟确保切换到OSM图层时立即显示正确版权信息。
备选方案:自定义版权控件
如果不想依赖DOM监听,可以创建自定义版权控件,手动添加到地图右下角的默认位置:
// 自定义OSM版权控件 function OSMCopyrightControl() {} OSMCopyrightControl.prototype = { onAdd: function(map) { this.container = document.createElement('div'); this.container.className = 'gmnoprint gm-style-cc'; this.container.innerHTML = `© <a href="https://www.openstreetmap.org">OpenStreetMap contributors</a>`; // 监听地图类型变化,控制控件显示/隐藏 map.addListener('maptypeid_changed', () => { this.container.style.display = map.getMapTypeId() === "OSM" ? 'block' : 'none'; // 切换到OSM时隐藏原生版权容器 if (map.getMapTypeId() === "OSM") { document.querySelector("div.gmnoprint > div.gm-style-cc").style.display = 'none'; } else { document.querySelector("div.gmnoprint > div.gm-style-cc").style.display = 'block'; } }); map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(this.container); return this.container; }, onRemove: function(map) { this.container.parentNode.removeChild(this.container); } }; // 将控件添加到地图 map.controls[google.maps.ControlPosition.BOTTOM_RIGHT].push(new OSMCopyrightControl());
注意事项
- 自定义控件需要使用Google Maps的默认样式类(
gmnoprint gm-style-cc),才能和原生版权信息位置、样式保持一致。 - 需要处理原生版权容器的显示状态,避免自定义控件和原生文本重叠。
内容的提问来源于stack exchange,提问作者Robbie Jackson
相关产品推荐
相关产品推荐

