Ok, here is my problem, I'll put a picture to illustrate it easier.
I need the user to draw some polygons, representing the coverage area.
The polygon needs to have fixed number of points (vertex) because it goes into a processing algorithm later, and it would be really slow if a polygon can contain a lot of points.
Anyway, in my example lets stick to hexagons (6 points).
The user need to be able to drag the polygon around and modify it, but not change the number of points.
I tried setting the editable: true
option for the polygon, it works fine, but it gives me the situation shown on the picture. It creates a handle for every point, and another handle (semi-transparent) in the middle between each points. Now, if the user moves that semi-transparent point, it will add another point (vertex) to the polygon, and add additional two handles in the middle of newly created lines. That gives us a 7 point polygon.
The best option would be to remove those semi-transparent handles, so the user can only drag polygon points, and it that way he can't affect the total number of points.
Can I achieve this using google maps editable option?
Ok, here is my problem, I'll put a picture to illustrate it easier.
I need the user to draw some polygons, representing the coverage area.
The polygon needs to have fixed number of points (vertex) because it goes into a processing algorithm later, and it would be really slow if a polygon can contain a lot of points.
Anyway, in my example lets stick to hexagons (6 points).
The user need to be able to drag the polygon around and modify it, but not change the number of points.
I tried setting the editable: true
option for the polygon, it works fine, but it gives me the situation shown on the picture. It creates a handle for every point, and another handle (semi-transparent) in the middle between each points. Now, if the user moves that semi-transparent point, it will add another point (vertex) to the polygon, and add additional two handles in the middle of newly created lines. That gives us a 7 point polygon.
The best option would be to remove those semi-transparent handles, so the user can only drag polygon points, and it that way he can't affect the total number of points.
Can I achieve this using google maps editable option?
Share Improve this question edited Dec 12, 2013 at 6:08 Kara 6,22616 gold badges53 silver badges58 bronze badges asked Apr 4, 2012 at 14:31 ZolaKtZolaKt 4,7218 gold badges45 silver badges68 bronze badges 2- Can you provide a jsfiddle example? – Argiropoulos Stavros Commented Apr 4, 2012 at 16:35
- I cant provide you a working example because I'm using an external library for gmaps (not really important, it is just a wrapper, gmap3.net). Here is the code jsfiddle.net/m4uvN/1. Before you ask why setTimeout() :), the callback doesn't return in the right moment. It returns the polygon before it is rendered in the map, so I have to delay the deleting a little – ZolaKt Commented Apr 4, 2012 at 18:25
5 Answers
Reset to default 10Another way to achieve what you want is to forego the built-in edit-ability of the polygon and implement it yourself. This is more powerful and flexible.
First, don't make the polygon editable. Next, make a Marker for each corner of the polygon. Finally, make each marker draggable and an event listener on it's "drag" event to update the polygon.
Making the markers and adding the event listener:
for (var i=0; i<coordinates.length; i++){
marker_options.position = coordinates[i];
var point = new google.maps.Marker(marker_options);
google.maps.event.addListener(point, "drag", update_polygon_closure(polygon, i));
}
Where update_polygon_closure is defined as:
function update_polygon_closure(polygon, i){
return function(event){
polygon.getPath().setAt(i, event.latLng);
}
}
Full code is in a jsfiddle here: https://jsfiddle.net/3L140cg3/16/
Since no one seems to have a better solution, I'm marking my workaround as accepted, in case someone stumbles upon the same problem. Not very pretty, but gets the job done
The only solution I found so far is to hide the handles manually after the polygon has been drawn. The problem here is that the handles don't have any CSS class or id, so I have to hide all divs with opacity 0.5 (opacity of the handles). It works, but it is pretty risky, considering that something else might have the same opacity and doesn't need to be hidden.
// variables
var map, path, color;
polygon = new google.maps.Polygon({
paths: path,
strokeColor: color,
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: color,
fillOpacity: 0.10,
editable: true,
});
polygon.setMap(map);
setTimeout(function(){ map.find('div[style*=opacity: 0.5]').hide(); }, 50);
As a slight improvement to @zolakt's answer, you can both hide the midpoint divs on the polygon and add a mousedown event listener to track when a midpoint is clicked to prevent dragging and changing the polygon:
// hide the midpoints (note that users can still click where the hidden midpoint
// divs are and drag to edit the polygon
$('#multi_markers div[style*="opacity: 0.5"]').hide();
// get the paths for the current polygon
var octopusPaths = HotelLib.octopusPolygon.getPaths();
// track when a polygon midpoint is clicked on
google.maps.event.addListener(HotelLib.octopusPolygon, 'mousedown', function(mdEvent) {
// if a midpoint is clicked on, mdEvent.edge will have an integer value
if(mdEvent.edge || (mdEvent.edge == 0)){
// immediately reset the polygon to its former paths
// effectively disabling the drag to edit functionality
HotelLib.octopusPolygon.setPaths(octopusPaths);
// hide the midpoints again since re-setting the polygon paths
// will show the midpoints
$('#multi_markers div[style*="opacity: 0.5"]').hide();
}
});
I just created an alternative solution to this without having to fiddle around with setTimeout
or the polyline creation. This is also a somewhat global solution, so you can basically drop it in any established program that uses Google Maps.
We'll use MutationObserver to observe when those midpoint nodes appear on the DOM and then instantly hide them. They should start appearing when something is set as editable.
Basically just put this anywhere after the map is initialized:
var editMidpointNodeObserver = new MutationObserver(function(list, observer)
{
if($('#mapwrapper div[style*="opacity: 0.5"]').parent('div[style*="cursor: pointer"]').length > 0)
{
$('#mapwrapper div[style*="opacity: 0.5"]').parent('div[style*="cursor: pointer"]').remove();
}
});
editMidpointNodeObserver.observe($('#mapwrapper')[0], { childList: true, subtree: true });
Change the #mapwrapper
to whatever the id of your Google Maps wrapper element is. I am using jQuery here, so therefore the $('#mapwrapper')[0]
to convert jQuery object to a native DOM object. Should work without jQuery as well, I am assuming you know how to convert this to vanilla js.
We also just straight up remove the nodes, so no need to worry about user being able to click invisible ones by accident or otherwise.
MutationObserver should be supported in all browsers: https://caniuse.com/mutationobserver
I would recommend also to delete any extra vertex, in case the user manage to create it from hiden point:
google.maps.event.addListener(
localityPolygon.getPath(),
"insert_at",
(function (key) {
return function (index) {
if (localityPolygon.getPath().getLength() > 6) {
localityPolygon.getPath().removeAt(index);
setTimeout(function () {
var map = document.getElementById("dialogMap");
var divs = map.querySelectorAll("div[style*='opacity: 0.5']");
divs.forEach(function (div) {
div.style.display = "none";
});
}, 50);
}
};
})(key)
);