避免在 google 地图叠加层中重叠
Avoid overlapping in google maps overlays
我创建了一个 fiddle example here 任何人都可以检查我的问题的地方。
这个问题是,当两个叠加层(用 svg
元素和其中的 path
构建)太近时,即并排,并且两个形状都有不规则的限制,然后最后呈现的形状与第一个形状重叠。
视觉上你无法欣赏它,但是如果你添加,例如,一个点击事件到 path
dom 元素来显示它们的名字,最后呈现的形状在它的所有部分都是可点击的区域,但第一个不是完全可点击的。下图标记的区域,下图不可点击,但应该是:
有一个 css
规则可以在光标位于 path
上时更改光标。也可以看到在指定区域光标没有变化
如何避免这种重叠?我想要的是底部形状完全可以点击。
最后,我尝试找到另一种解决方案,例如获取鼠标位置下的所有元素,并确定当时哪个 path
在指针下,并对它执行操作。我一直在寻找一种方法来实现这个解决方案,我发现了这个 post: solution!!,那里正是我所需要的。
我认为这是解决我的问题的最好和更优雅的方式(至少比我之前想象的要好)。基本上它将 css 规则 pointer-events: none;
添加到阻止其他 path
元素的顶部 svg
元素。我向 path
个对象添加了 pointer-events: all;
。所以 css 样式应该是这样的:
svg.overlay {
pointer-events: none;
}
svg.overlay > path {
pointer-events: all;
}
整个解决方案(您也可以在jsfiddler example中看到它):
function initialize() {
var myLatLng = new google.maps.LatLng(42, -111.02783203125);
var mapOptions = {
zoom: 6,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
//polygon coords for Utah
var path = [
new google.maps.LatLng(41.983994270935625, -111.02783203125),
new google.maps.LatLng(42.00032514831621, -114.01611328125),
new google.maps.LatLng(36.96744946416931, -114.01611328125),
new google.maps.LatLng(37.00255267215955, -109.0283203125),
new google.maps.LatLng(40.97989806962013, -109.0283203125),
new google.maps.LatLng(41.0130657870063, -111.02783203125)
];
// custom overlay created
var overlay = new BW.PolyLineFill(path, map, 'red', '#000', 'original');
// polygon coords for conflict shape
var pathConflict = [
new google.maps.LatLng(42.00032514831621, -114.01611328125),
new google.maps.LatLng(41.983994270935625, -111.02783203125),
new google.maps.LatLng(41.0130657870063, -111.02783203125),
new google.maps.LatLng(40.97989806962013, -109.0283203125),
new google.maps.LatLng(47.00255267215955, -109.0283203125),
new google.maps.LatLng(46.96744946416931, -114.01611328125)
];
var overlayConflict = new BW.PolyLineFill(pathConflict, map, 'white', '#000', 'conflict');
}
///Start custom poly fill code
PolyLineFill.prototype = new google.maps.OverlayView();
function PolyLineFill(poly, map, fill, stroke, name) {
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < poly.length; i++) {
bounds.extend(poly[i]);
}
//initialize all properties.
this.bounds_ = bounds;
this.map_ = map;
this.$dom = null;
this.poly_ = poly;
this.polysvg_ = null;
this.fill_ = fill;
this.stroke_ = stroke;
this.name_ = name;
// Explicitly call setMap on this overlay
this.setMap(map);
}
PolyLineFill.prototype.onAdd = function() {
//createthe svg element
var svgns = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(svgns, "svg");
svg.setAttributeNS(null, "preserveAspectRatio", "xMidYMid meet");
var def = document.createElementNS(svgns, "defs");
//create the pattern fill
var pattern = document.createElementNS(svgns, "pattern");
pattern.setAttributeNS(null, "id", "lineFill-" + this.name_);
pattern.setAttributeNS(null, "patternUnits", "userSpaceOnUse");
pattern.setAttributeNS(null, "patternTransform", "rotate(-45)");
pattern.setAttributeNS(null, "height", "7");
pattern.setAttributeNS(null, "width", "7");
def.appendChild(pattern);
var rect = document.createElementNS(svgns, "rect");
rect.setAttributeNS(null, "id", "rectFill");
rect.setAttributeNS(null, "fill", this.fill_ || "red");
rect.setAttributeNS(null, "fill-opacity", "0.3");
rect.setAttributeNS(null, "stroke", this.stroke_ || "#000");
rect.setAttributeNS(null, "stroke-dasharray", "7,7");
rect.setAttributeNS(null, "height", "7");
rect.setAttributeNS(null, "width", "7");
pattern.appendChild(rect);
svg.appendChild(def);
//add path to the div
var path = document.createElementNS(svgns, 'path');
path.setAttributeNS(null, 'fill', 'url(#lineFill-' + this.name_ + ')');
path.setAttributeNS(null, 'stroke', '#000');
path.setAttributeNS(null, 'stroke-width', '1');
path.setAttributeNS(null, 'pointer-events', 'all');
this.path_ = path;
svg.appendChild(this.path_);
svg.style.borderStyle = 'none';
svg.style.borderWidth = '0px';
svg.style.position = 'absolute';
svg.style.pointerEvents = 'none';
svg.setAttribute('class', 'polygon');
this.$dom = svg;
// We add an overlay to a map via one of the map's panes.
// We'll add this overlay to the overlayLayer pane.
var panes = this.getPanes();
panes.overlayMouseTarget.appendChild(this.$dom);
var dragging = false;
google.maps.event.addDomListener(this.path_, 'mousedown', function(evt) {
dragging = false;
});
google.maps.event.addDomListener(this.path_, 'mousemove', function(evt) {
dragging = true;
});
var _self = this;
// onclick listener
google.maps.event.addDomListener(this.path_, 'click', function(evt) {
if (dragging) {
return false;
}
alert('clicked on ' + _self.name_);
});
}
PolyLineFill.prototype.AdjustPoints = function() {
//adjust the polygon points based on the projection.
var proj = this.getProjection();
var sw = proj.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = proj.fromLatLngToDivPixel(this.bounds_.getNorthEast());
var points = "";
for (var i = 0; i < this.poly_.length; i++) {
var point = proj.fromLatLngToDivPixel(this.poly_[i]);
if (i == 0) {
points += (point.x - sw.x) + ", " + (point.y - ne.y);
} else {
points += " " + (point.x - sw.x) + ", " + (point.y - ne.y);
}
}
return points;
}
PolyLineFill.prototype.draw = function() {
// Size and position the overlay. We use a southwest and northeast
// position of the overlay to peg it to the correct position and size.
// We need to retrieve the projection from this overlay to do this.
var overlayProjection = this.getProjection();
// Retrieve the southwest and northeast coordinates of this overlay
// in latlngs and convert them to pixels coordinates.
// We'll use these coordinates to resize the DIV.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's DIV to fit the indicated dimensions.
var div = this.$dom;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
this.path_.setAttributeNS(null, "d", 'M' + this.AdjustPoints() + 'z');
}
PolyLineFill.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
window.BW = {};
window.BW.PolyLineFill = PolyLineFill;
///end poly fill code
google.maps.event.addDomListener(window, 'load', initialize);
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.polygon: {
pointer-events: none;
}
.polygon > path {
cursor: pointer;
pointer-events: all;
}
.polygon > path:active {
cursor: -webkit-grabbing;
}
#map-canvas,
#map_canvas {
height: 100%;
}
@media print {
html,
body {
height: auto;
}
#map_canvas {
height: 650px;
}
}
<script src="http://maps.google.com/maps/api/js?sensor=false&.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="map-canvas"></div>
我创建了一个 fiddle example here 任何人都可以检查我的问题的地方。
这个问题是,当两个叠加层(用 svg
元素和其中的 path
构建)太近时,即并排,并且两个形状都有不规则的限制,然后最后呈现的形状与第一个形状重叠。
视觉上你无法欣赏它,但是如果你添加,例如,一个点击事件到 path
dom 元素来显示它们的名字,最后呈现的形状在它的所有部分都是可点击的区域,但第一个不是完全可点击的。下图标记的区域,下图不可点击,但应该是:
有一个 css
规则可以在光标位于 path
上时更改光标。也可以看到在指定区域光标没有变化
如何避免这种重叠?我想要的是底部形状完全可以点击。
最后,我尝试找到另一种解决方案,例如获取鼠标位置下的所有元素,并确定当时哪个 path
在指针下,并对它执行操作。我一直在寻找一种方法来实现这个解决方案,我发现了这个 post: solution!!,那里正是我所需要的。
我认为这是解决我的问题的最好和更优雅的方式(至少比我之前想象的要好)。基本上它将 css 规则 pointer-events: none;
添加到阻止其他 path
元素的顶部 svg
元素。我向 path
个对象添加了 pointer-events: all;
。所以 css 样式应该是这样的:
svg.overlay {
pointer-events: none;
}
svg.overlay > path {
pointer-events: all;
}
整个解决方案(您也可以在jsfiddler example中看到它):
function initialize() {
var myLatLng = new google.maps.LatLng(42, -111.02783203125);
var mapOptions = {
zoom: 6,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
//polygon coords for Utah
var path = [
new google.maps.LatLng(41.983994270935625, -111.02783203125),
new google.maps.LatLng(42.00032514831621, -114.01611328125),
new google.maps.LatLng(36.96744946416931, -114.01611328125),
new google.maps.LatLng(37.00255267215955, -109.0283203125),
new google.maps.LatLng(40.97989806962013, -109.0283203125),
new google.maps.LatLng(41.0130657870063, -111.02783203125)
];
// custom overlay created
var overlay = new BW.PolyLineFill(path, map, 'red', '#000', 'original');
// polygon coords for conflict shape
var pathConflict = [
new google.maps.LatLng(42.00032514831621, -114.01611328125),
new google.maps.LatLng(41.983994270935625, -111.02783203125),
new google.maps.LatLng(41.0130657870063, -111.02783203125),
new google.maps.LatLng(40.97989806962013, -109.0283203125),
new google.maps.LatLng(47.00255267215955, -109.0283203125),
new google.maps.LatLng(46.96744946416931, -114.01611328125)
];
var overlayConflict = new BW.PolyLineFill(pathConflict, map, 'white', '#000', 'conflict');
}
///Start custom poly fill code
PolyLineFill.prototype = new google.maps.OverlayView();
function PolyLineFill(poly, map, fill, stroke, name) {
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < poly.length; i++) {
bounds.extend(poly[i]);
}
//initialize all properties.
this.bounds_ = bounds;
this.map_ = map;
this.$dom = null;
this.poly_ = poly;
this.polysvg_ = null;
this.fill_ = fill;
this.stroke_ = stroke;
this.name_ = name;
// Explicitly call setMap on this overlay
this.setMap(map);
}
PolyLineFill.prototype.onAdd = function() {
//createthe svg element
var svgns = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(svgns, "svg");
svg.setAttributeNS(null, "preserveAspectRatio", "xMidYMid meet");
var def = document.createElementNS(svgns, "defs");
//create the pattern fill
var pattern = document.createElementNS(svgns, "pattern");
pattern.setAttributeNS(null, "id", "lineFill-" + this.name_);
pattern.setAttributeNS(null, "patternUnits", "userSpaceOnUse");
pattern.setAttributeNS(null, "patternTransform", "rotate(-45)");
pattern.setAttributeNS(null, "height", "7");
pattern.setAttributeNS(null, "width", "7");
def.appendChild(pattern);
var rect = document.createElementNS(svgns, "rect");
rect.setAttributeNS(null, "id", "rectFill");
rect.setAttributeNS(null, "fill", this.fill_ || "red");
rect.setAttributeNS(null, "fill-opacity", "0.3");
rect.setAttributeNS(null, "stroke", this.stroke_ || "#000");
rect.setAttributeNS(null, "stroke-dasharray", "7,7");
rect.setAttributeNS(null, "height", "7");
rect.setAttributeNS(null, "width", "7");
pattern.appendChild(rect);
svg.appendChild(def);
//add path to the div
var path = document.createElementNS(svgns, 'path');
path.setAttributeNS(null, 'fill', 'url(#lineFill-' + this.name_ + ')');
path.setAttributeNS(null, 'stroke', '#000');
path.setAttributeNS(null, 'stroke-width', '1');
path.setAttributeNS(null, 'pointer-events', 'all');
this.path_ = path;
svg.appendChild(this.path_);
svg.style.borderStyle = 'none';
svg.style.borderWidth = '0px';
svg.style.position = 'absolute';
svg.style.pointerEvents = 'none';
svg.setAttribute('class', 'polygon');
this.$dom = svg;
// We add an overlay to a map via one of the map's panes.
// We'll add this overlay to the overlayLayer pane.
var panes = this.getPanes();
panes.overlayMouseTarget.appendChild(this.$dom);
var dragging = false;
google.maps.event.addDomListener(this.path_, 'mousedown', function(evt) {
dragging = false;
});
google.maps.event.addDomListener(this.path_, 'mousemove', function(evt) {
dragging = true;
});
var _self = this;
// onclick listener
google.maps.event.addDomListener(this.path_, 'click', function(evt) {
if (dragging) {
return false;
}
alert('clicked on ' + _self.name_);
});
}
PolyLineFill.prototype.AdjustPoints = function() {
//adjust the polygon points based on the projection.
var proj = this.getProjection();
var sw = proj.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = proj.fromLatLngToDivPixel(this.bounds_.getNorthEast());
var points = "";
for (var i = 0; i < this.poly_.length; i++) {
var point = proj.fromLatLngToDivPixel(this.poly_[i]);
if (i == 0) {
points += (point.x - sw.x) + ", " + (point.y - ne.y);
} else {
points += " " + (point.x - sw.x) + ", " + (point.y - ne.y);
}
}
return points;
}
PolyLineFill.prototype.draw = function() {
// Size and position the overlay. We use a southwest and northeast
// position of the overlay to peg it to the correct position and size.
// We need to retrieve the projection from this overlay to do this.
var overlayProjection = this.getProjection();
// Retrieve the southwest and northeast coordinates of this overlay
// in latlngs and convert them to pixels coordinates.
// We'll use these coordinates to resize the DIV.
var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());
// Resize the image's DIV to fit the indicated dimensions.
var div = this.$dom;
div.style.left = sw.x + 'px';
div.style.top = ne.y + 'px';
div.style.width = (ne.x - sw.x) + 'px';
div.style.height = (sw.y - ne.y) + 'px';
this.path_.setAttributeNS(null, "d", 'M' + this.AdjustPoints() + 'z');
}
PolyLineFill.prototype.onRemove = function() {
this.div_.parentNode.removeChild(this.div_);
this.div_ = null;
}
window.BW = {};
window.BW.PolyLineFill = PolyLineFill;
///end poly fill code
google.maps.event.addDomListener(window, 'load', initialize);
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.polygon: {
pointer-events: none;
}
.polygon > path {
cursor: pointer;
pointer-events: all;
}
.polygon > path:active {
cursor: -webkit-grabbing;
}
#map-canvas,
#map_canvas {
height: 100%;
}
@media print {
html,
body {
height: auto;
}
#map_canvas {
height: 650px;
}
}
<script src="http://maps.google.com/maps/api/js?sensor=false&.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="map-canvas"></div>