I am drawing polygons that are adjacent and whose borders are shared. Looking at the example image below, if I were to draw a polygon for Montana, I'd like to be able to click on the nodes of the Idaho polygon for the part of the border that is the same to ensure the borders don't overlap or have holes. However, the nodes don't allow clicks directly on them, and if I make the nodes invisible then the accuracy is worsened and I'll probably end up with holes or overlaps between the two polygons.
Is there a way to snap a drawing to a node of an existing polygon? If not, is there at least a way to make it so that I can click directly where the nodes are? I've set the polygon's properties to editable: false and clickable: false, but the boundary of the polygon (and the nodes) still disallows clicks.
I haven't seen any documentation in the API for snapping.
I am drawing polygons that are adjacent and whose borders are shared. Looking at the example image below, if I were to draw a polygon for Montana, I'd like to be able to click on the nodes of the Idaho polygon for the part of the border that is the same to ensure the borders don't overlap or have holes. However, the nodes don't allow clicks directly on them, and if I make the nodes invisible then the accuracy is worsened and I'll probably end up with holes or overlaps between the two polygons.
Is there a way to snap a drawing to a node of an existing polygon? If not, is there at least a way to make it so that I can click directly where the nodes are? I've set the polygon's properties to editable: false and clickable: false, but the boundary of the polygon (and the nodes) still disallows clicks.
I haven't seen any documentation in the API for snapping.
Share Improve this question asked Nov 21, 2013 at 22:29 SkittermSkitterm 4,5959 gold badges42 silver badges56 bronze badges 5- 2 Find the nearest vertex of the polygon to your mouse click. – geocodezip Commented Nov 21, 2013 at 22:34
- @geocodezip: Thanks. I assume the best way to do that would be using the Geometry Library for google maps. I'll give that a try. – Skitterm Commented Nov 21, 2013 at 22:51
- If you draw a rough border for Montana, you can then move the points and they'll snap to the Idaho points. – brouxhaha Commented Nov 21, 2013 at 22:54
- This seems relevant stackoverflow./questions/10694378/… – geocodezip Commented Nov 21, 2013 at 23:32
- I like this example by Wolfgang Pichler, snaps to polylines and between vertices, but might be useful (would allow you to snap anywhere on the edge of the polygon, not just to the vertices). – geocodezip Commented Nov 22, 2013 at 0:16
1 Answer
Reset to default 8PolySnapper: easy polygon vertice snapping.
I created this this github repo and plementary jsfiddle.
A brief example might look like:
var PS = PolySnapper({
map: map,
threshold: 20,
key: 'shift',
keyRequired: true,
polygons: polygons,
polystyle: polystyle,
hidePOI: true,
onEnabled: function(){
console.log("enabled")
},
onDisabled: function(){
console.log("disabled")
},
onChange: function(){
console.log("a point was added, removed, or moved")
}
});
//first enable the manager (enter drawing mode)
PS.enable();
//user draws the polygon, point by point, snapping when necessary.
//now, retrieve the polygon from the manager.
the_poly = PS.polygon();
//and disable the manager (exit drawing mode and clean up poly).
//you should now use the_poly as a polygon reference
PS.disable();
Note: By design, the western shape on jsfiddle is not set to snapable
(see above polygons
property) so only the eastern shape will snap :)
//the only global variable
//SM will bee the SnapManager instance.
var SM = null;
google.maps.event.addDomListener(window, "load", function () {
//we will center the map here
var vancouver = {
lat: 49.269858,
lng: -123.137283
}
//granville island coordinates.
//you should be fetching your coordinates from your server
var granville_coords = [
{lat: 49.27158485202591, lng: -123.13729763031006},
{lat: 49.27277488695786, lng: -123.13691139221191},
{lat: 49.27316689217891, lng: -123.13613891601562},
{lat: 49.27319489243262, lng: -123.13474416732788},
{lat: 49.27248088099777, lng: -123.13384294509888},
{lat: 49.2696667352996, lng: -123.13049554824829},
{lat: 49.268546632648494,lng: -123.13055992126465},
{lat: 49.268350612069995,lng: -123.13066720962524},
{lat: 49.2684906268484, lng: -123.13146114349365},
{lat: 49.268546632648494,lng: -123.13249111175537},
{lat: 49.26888266611402, lng: -123.13347816467285},
{lat: 49.26889666745873, lng: -123.13401460647583},
{lat: 49.2706328034105, lng: -123.1368041038513 }
];
//coordinates of blocks just east of burrard.
var burrard_coords = [
{lat: 49.267972570183545, lng: -123.145751953125},
{lat: 49.2679445669656, lng: -123.14085960388184},
{lat: 49.27032478374826, lng: -123.14077377319336},
{lat: 49.27138884351881, lng: -123.14176082611084},
{lat: 49.27309689147504, lng: -123.14356327056885},
{lat: 49.27267688516586, lng: -123.14467906951904},
{lat: 49.27152884967477, lng: -123.14553737640381},
{lat: 49.269834748503946, lng: -123.1459450721740}
];
//make the satellite view google map, center it in Vancouver.
map = new google.maps.Map(document.getElementById("map_div"), {
center: new google.maps.LatLng(vancouver.lat, vancouver.lng),
zoom: 16,
mapTypeId: google.maps.MapTypeId.HYBRID
});
//this style is easier on the eyes than the default black.
//BADASS and COFFEE hex to the rescue.
var polystyle = {
strokeColor: '#BADA55',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#C0FFEE',
fillOpacity: 0.35
}
//options for granville polygon.
//SNAPABLE = TRUE
var poly1_opts = $.extend({
paths: granville_coords,
map: map,
snapable: true
}, polystyle);
//options for burrard polygon
//SNAPABLE not present (false)
var poly2_opts = $.extend({
paths: burrard_coords,
map: map
}, polystyle);
//let's make the polygons
var granville = new google.maps.Polygon(poly1_opts);
var burrard = new google.maps.Polygon(poly2_opts);
/*
For demo purposes, lets just put two gmaps Polys into the polygon array.
For your application purposes, you would populate this array with
all of the polygons you want to snap to - likely driven from the DB.
*/
polygons = [granville, burrard];
/*
Now, we make the SnapManager.
See http://stackoverflow./a/33338065/568884 for API
Will be transferred to Github soon.
*/
SM = PolySnapper({
map: map,
marker: new google.maps.Marker(),
threshold: 20,
keyRequired: false,
polygons: polygons,
polystyle: polystyle,
hidePOI: true,
onEnabled: function(){
console.log("enabled")
},
onDisabled: function(){
console.log("disabled")
}
});
//add the buttons initial state on top of the map.
renderCpanel(false);
});
//when user clicks log poly button, pull the poly out of the manager and console.log it.
$(document).on("click", "#query", function(){
console.log( SM.poly().getPath().getArray() );
});
//just a small render function to re-draw the buttons whenever the enabled state is flipped on and off.
function renderCpanel(drawing){
var t = $("#control-panel").html();
var html = _.template(t, {drawing: drawing});
$("#cp-wrap").html(html);
}
//attach the click handlers to the button. #cp-wrap is never added or removed
//from the DOM, so its safe to bind the listeners to it.
$("#cp-wrap").on("click", "button", function(){
var action = $(this).data("action");
if (action == 'new') SM.enable();
else if(action == 'query') console.log( SM.polygon() )
else SM.disable();
renderCpanel( (action == 'new') );
});
body {
margin: 0;
padding: 0;
font: 12px sans-serif;
}
#cp-wrap{
position: absolute;
top: 10px;
left:120px;
background-color:white;
}
#cp-wrap button{
font-size: 22px;
}
<script src="https://rawgit./jordanarseno/polysnapper/master/polysnapper.js"></script>
<script src="http://underscorejs/underscore-min.js"></script>
<script src="https://ajax.googleapis./ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.google./maps/api/js?.js"></script>
<div style='position:relative;'>
<div id="map_div" style="height: 600px; width:100%;"></div>
<div id='cp-wrap'></div>
</div>
<script id='control-panel' type='text/template'>
<% if(drawing) { %>
<button data-action='cancel' >cancel</button>
<button data-action='query' >log poly</button>
<% } else { %>
<button data-action='new' >new poly</button>
<% } %>
</script>