我在谷歌地图的OverlayView类中使用了具有定义和恒定边界的SVG,并且我的目的是在单击地图上的某个位置时(如果单击的位置在此边界内)绘制相应的区域边界。我决定不使用google的默认路径选项来绘制多边形,而是决定使用SVG路径元素。为了避免使用多个SVG元素,我想在一个SVG上使用多个路径元素(用于区域的多边形)。 为此,考虑到用户将更改缩放级别以适应任何缩放级别,我采用了viewBox属性以根据地图的缩放级别进行缩放。因此,主要思想是,当更改地图的缩放级别时,单个SVG标签内的所有路径元素也会根据需要分别对齐。 尽管一切似乎都正常,但单击不同的缩放级别时,相同的边界之间仍存在细微差异。我无法解决问题所在。
我的代码如下:
如果能帮助我指出此代码中的错误之处,我将不胜感激。
谢谢。
注意:要了解该问题并查看实际存在的问题,可以查看我的网站。由于尚未定义所有地标,因此在屏幕中间某处,某处建筑物和绿地中间都可以单击并查看问题,方法是在平移和缩放后单击同一区域,然后看到边界不重叠。但首先,您必须先单击底部的“获取信息”菜单栏,该菜单栏将模式设置为地图上的区域选择。 网址:https://www.mikkins.com/landplot/11.php
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div class="menu">
<div class="title">MENU</div>
<div class="wrapper"><div class="button">Get Info</div></div>
<ul class="nav">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Work</a></li>
<li><a href="#">Resources</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
<div class="intro" id="GMAP"></div>
<svg id="svg1" xmlns="http://www.w3.org/2000/svg">
</svg>
<script>
var overlay;
var polygonReturn=new Array();
var polygonBounds=new Array();
var _svgOW;
function initGMap()
{
var mapOptions={ center: {lat:40.88227, lng:29.251796} ,
zoom: 16 ,
mapTypeId:'satellite',
disableDefaultUI: false,
draggableCursor: 'auto',
scrollwheel: false
};
$GMAP=new
google.maps.Map(document.getElementById('GMAP'),mapOptions);
overlay=prepareOverlay($GMAP);
document.querySelector('.button').addEventListener('click',
function(e)
{
//toggle between pressed and not pressed states
for button
e.target.classList.toggle('pressed');
if(e.target.className.split('
').indexOf('pressed')>-1)
{
$GMAP.setOptions({draggableCursor:
'crosshair'});
google.maps.event.addListener($GMAP,'click',function(evt){
//if button is pressed then we are in
polygon info request mode
fetch("/findpolygon.php?
lat="+evt.latLng.lat()+"&lng="+evt.latLng.lng())
.then(function(response){ return
response.text();}).
then(function(strarr){
interimSlice=strarr.split('%');
polygonReturn=interimSlice[0].split(',');
console.log(polygonReturn);
polygonInfo=JSON.parse(interimSlice[1]).features[0].properties;
var pixelPath="";
var point=new Array();
polygonReturn.forEach((polygon)=>{
point=polygon.split(' ');
u=_svgOW.projection.fromLatLngToDivPixel(new
google.maps.LatLng({lat:parseFloat(point[1]),
lng:parseFloat(point[0])})
u.x=(u.x-parseFloat(_svgOW.svg.style.left)) /
(1<<$GMAP.getZoom());
u.y=(u.y-parseFloat(_svgOW.svg.style.top)) /
(1<<$GMAP.getZoom());
pixelPath+=`${u.x} ${u.y}L`;
});
pixelPath="M"+pixelPath;
pixelPath=pixelPath.slice(0,-2);
//Definition of new path element
var svgPath =
document.createElementNS('http://www.w3.org/2000/svg', 'path');
svgPath.setAttribute('id','path3');
svgPath.setAttribute('fill','none');
svgPath.setAttribute('stroke','yellow');
svgPath.setAttribute('stroke-width','0.000008');
svgPath.setAttribute('d',pixelPath);
overlay.addNewElement('#svg1',svgPath);
})
.catch(error=>console.error('Error: ',error));
});
} else {
$GMAP.setOptions({draggableCursor: 'auto'});
google.maps.event.clearListeners($GMAP,'click');
}
});
}
function prepareOverlay(map){
class SVGOverlay extends google.maps.OverlayView {
constructor(bounds, svg, map) {
super();
this.bounds = bounds;
this.svg = svg;
super.setMap(map);
}
onAdd() {
const svg = this.svg;
svg.style.position = 'absolute';
//Add the SVG element to a map pane/layer that is able to
receive mouse events:
const panes = super.getPanes();
panes.overlayMouseTarget.appendChild(svg);
const projection = super.getProjection(),
bounds = this.bounds,
sw =
projection.fromLatLngToDivPixel(bounds.getSouthWest()),
ne =
projection.fromLatLngToDivPixel(bounds.getNorthEast());
//Place the SVG element;
var vbox=sw.x+" "+ne.y+" "+(ne.x - sw.x)+" "+(sw.y - ne.y);
this.svg.setAttribute("viewBox",vbox);
}
/**
Whenever we need to (re)draw the overlay on the map, including
when first added.
*/
draw() {
//Here, we need to find the correct on-screen position for our
image.
//To achieve that, we simply ask the map's projection to
calculate viewport pixels from the image's lat/lng bounds:
const projection = super.getProjection(),
bounds = this.bounds,
sw =
projection.fromLatLngToDivPixel(bounds.getSouthWest()),
ne =
projection.fromLatLngToDivPixel(bounds.getNorthEast());
var scale = 1 << (map.getZoom());
//Place/resize the SVG element:
const s = this.svg.style;
s.left = sw.x + 'px';
s.top = ne.y + 'px';
s.width = (ne.x - sw.x) + 'px';
s.height = (sw.y - ne.y) + 'px';
var vbox="0 0 "+(ne.x - sw.x)/scale+" "+(sw.y - ne.y)/scale;
this.svg.setAttribute("viewBox",vbox);
}
}
function addEvent(target, type, handler) {
const targets = (typeof target === 'string') ?
Array.from(document.querySelectorAll(target))
: [target];
targets.forEach(t => google.maps.event.addDomListener(t, type,
handler));
}
function initOverlay() {
//Say which area we want the image to occupy:
const svgBounds = new google.maps.LatLngBounds(
new google.maps.LatLng(35, 25),
new google.maps.LatLng(44, 46),
);
_svgOW=new SVGOverlay(svgBounds, mySVG, map);
addEvent('path', 'click', e => {
console.log('Clicked!');
e.currentTarget.style.fill = '#' + Math.floor(Math.random() *
0xfffff);
e.stopPropagation();
});
addEvent('path', 'dblclick', e => {
//Avoid zooming here:
e.stopPropagation();
});
}
addEvent(window, 'load', initOverlay);
var TILE_SIZE=256;
return {
addNewElement: function (toWhere,element)
{
document.querySelector(toWhere).append(element)
},
}
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?
key=MY_APIKEY&callback=initGMap&language=&signed_in=false">
</script>
</body>
</html>