Reputation: 877
I've created a fiddle example here where anyone can check my problem.
That problem is that when two overlays (built with a svg
element and a path
inside it) are too close, i.e, side by side, and both shapes have irregular limits, then the last shape rendered is overlapping the first one.
Visually you can't appreciate it, but if you add, e.g., a click event to the path
dom elements to show their names, the last rendered shape is clickable in al its region, but the first one is not entirely clickable. The marked region in the following picture is not clickable for the bottom picture but it should be:
There is a css
rule to change the cursor when it is over a path
. You can also see that in the specified region the cursor does not change.
How can I avoid this overlapping? What I want is to do the bottom shape entirely clickable.
Upvotes: 3
Views: 2424
Reputation: 877
Finally I tried to find another solution like getting all elements under the mouse position and determine which path
was, at that moment, under the pointer, and execute the action on it. I was looking for a way to implement this solution and I found this post: solution!!, where there is just what I needed.
I think it is the best and more elegant way (at least better than I thought before) to solve my issue. Basically it adds the css rule pointer-events: none;
to the top svg
element which is blocking other path
elements. And to the path
objects I have added pointer-events: all;
. So the css styles should look like this:
svg.overlay {
pointer-events: none;
}
svg.overlay > path {
pointer-events: all;
}
The entire solution (you can see it also in a 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>
Upvotes: 2