Utilizing Google Maps API V3 to Snap to Vertices of Different Polygon

When creating adjacent polygons with shared borders, I am facing a challenge. In the example image provided, when drawing a polygon for Montana next to Idaho, it is important to ensure that the borders align properly without any overlaps or gaps. However, clicking directly on the nodes of the Idaho polygon to connect them with Montana proves to be difficult as the nodes are not clickable. Making the nodes invisible compromises the accuracy of the border alignment, leading to potential issues with holes or overlaps between the two polygons.

Is there a feature available to snap a drawn polygon to a node of an existing polygon? If not, is there a way to enable direct clicks on the nodes for better precision? Despite setting the polygon's properties to editable: false and clickable: false, the boundary and nodes still do not allow interaction.

I have searched through the API documentation but have not found any information regarding snapping functionality.

Answer №1

PolySnapper: a simple tool for snapping polygon vertices.

If you're interested, check out this repository on Github along with a related jsfiddle.

To demonstrate how it works, here is a brief example:

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")
      }
});
      
//start by enabling the manager (enter drawing mode)
PS.enable();

//user draws the polygon, point by point, while snapping if needed.
//get the finished polygon from the manager.
the_poly = PS.polygon();

//then disable the manager (exit drawing mode and clean up poly).
//now you can use the_poly as a reference to your polygon
PS.disable();

Note: The western shape on the jsfiddle example is intentionally not set to be snapable (see the polygons property) so only the eastern shape will snap :)

//only one global variable
//SM will represent the SnapManager instance.
var SM = null;

google.maps.event.addDomListener(window, "load", function () {
  
  //centering the map in Vancouver
  var vancouver = {
      lat: 49.269858,
      lng: -123.137283
  }
  
  //coordinates for Granville Island.
  //you should fetch these coordinates from your server
  var granville_coords = [
    // coordinates here...
];
    
  //coordinates of blocks east of Burrard.
  var burrard_coords = [
    // coordinates here...
  ];
  
  //creating a satellite view Google Map centered 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
  });
  
  //customizing the style of the polygons
  var polystyle = {
      strokeColor: '#BADA55',
      strokeOpacity: 0.8,
      strokeWeight: 2,
      fillColor: '#C0FFEE',
      fillOpacity: 0.35
  }
  
  //options for Granville polygon.
  var poly1_opts = $.extend({
      paths: granville_coords,
      map: map,
      snapable: true
  }, polystyle);
    
  //options for Burrard polygon
  var poly2_opts = $.extend({
    paths: burrard_coords,
      map: map
  }, polystyle);
  
  //creating the polygons  
  var granville = new google.maps.Polygon(poly1_opts);
  var burrard   = new google.maps.Polygon(poly2_opts);
  
  /*
      For demo purposes, let's put two Google Maps Polys into the polygon array.
      In your application, populate this array with
      all the polygons you want to snap to, likely retrieved from a database.
  */
  polygons = [granville, burrard];
  
  /*
  Creating the SnapManager.
    API details: http://stackoverflow.com/a/33338065/568884 
    Will move 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")
      }
  });
  
...

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.com/jordanarseno/polysnapper/master/polysnapper.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.google.com/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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

JQuery and CSS can be used to create a div overlay without impacting the positions of other divs on the

Is there a way to make a div overlay other divs (like a dropdown list) without affecting the positions of other divs? I have a #hidden div that appears when you hover over a #HoverMe div, but it moves the position of other divs when hovered. How can I ...

Access the information from the text box and text area, then store it into a cookie using either jQuery or JavaScript

I need to save the text entered in a textbox within an iframe. How can I achieve this using jQuery or JavaScript? Any assistance would be greatly appreciated. ...

What is the best way to retrieve the chosen value from a dropdown menu when utilizing a partial view in MVC?

In my current project, I am implementing a partial view to embed one view inside another. The partial view contains a dropdown menu, and I need to retrieve the selected value from that dropdown in order to display another dropdown based on the selection ma ...

Retrieve the names of keys from a JSON array for every version of browsers

I have a JSON array and I want to extract the key names associated with each object. Despite my initial search efforts turning up no effective solutions, I managed to create my own approach: var data = [{ Id: 25 }, {Year: 18} ]; $.each(data, function (i ...

Is there a way to identify the Xpath after clicking a button that adds a row to the JQGrid?

Seeking the Xpath for the Row that was added upon clicking a button. Need to click on the datepicker in the first row and first column to select a date. How can I locate the Xpath for this date picker element? See my code snippet below `<table ...

Mastering the art of filtering JSON data with multiple conditions using .filter() and .includes() in JavaScript and React

Forgive me if this is a straightforward question, as I am new to the world of programming. My current project involves creating a web application that filters quotes based on specific keywords. The quotes are stored in JSON format, here's a glimpse at ...

Tips for managing child records while the parent record is still being created

When dealing with creating or editing an Excursion record, there is a form that includes nested excursion_images, which are created through a remote call using JavaScript (Fine Uploader). While this solution works perfectly for editing an Excursion, it en ...

Is the check for 'is integer' satisfactory?

Is the following 'is integer' function sufficient: function isInteger( input ) { return Number(input) === parseInt(input); } I want this function to return true for inputs like 12, 13, '14', '-1', Number.MAX_VALUE (round ...

Is it possible to merge two jQuery functions into a single one?

Here are my two jQuery functions: $(document).on('change','.states',function(){ //on change of select }); $(document).on('click','.date_control',function(){ //on click of input .date_control }); I am lookin ...

Press a button to navigate through a series of web pages

Currently, I am working on a website focused on profiles. The challenge I am facing is implementing fixed side buttons (SKIP and ADD) that will cycle through the list of profiles. I understand that I may need to create an array to store all the profiles, ...

Instructions on creating the effect of rainwater cascading over text and spilling onto a webpage

Is it possible to make the rain flow over my text? Below is the code snippet from my JSFiddle: function strop(cleft, ctop, d) { var drop = document.createElement('div'); drop.className = 'punct'; drop.style.left = cleft + & ...

Can you explain the function of this.$nextTick()?

I'm a beginner with Vue.js and I'm trying to wrap my head around the logic of using nextTick in a method. I have two components set up like this: IsTuruIslem.vue <template> ... <t-row> <is-turu-islem-goruntule ref="isTuru ...

Leveraging server.ts for Development with Angular 5 Universal

I decided to give the new Angular Universal Starter a try for my latest Angular 5 project. Instead of providing multiple options, they now only offer the Angular CLI version as a starting point. I've been able to successfully run my project in product ...

JavaScript is proving to be uncooperative in allowing me to modify the

Despite searching through previously asked questions, I have been unable to find a solution to my issue. I am struggling with changing an image source upon clicking the image itself. The following is a snippet of my HTML code: <img id="picture1" oncli ...

While attempting to upload a file in my Mocha Node.js test, I encountered the message: "Received [Object null prototype] { file: { ... }}"

Everywhere I find the solution in white : app.use(bodyParser.urlencoded({extended: true})); I can use JSON.stringify(req.files) However, I am sure there is a way to fix my problem. My Mocha test : it('handles file upload', async function () { ...

Accessing id3 v2.4 tags using the built-in capabilities of Chrome's Javascript FileReader and DataView

After discovering the solution provided by ebidel, individuals can extract id3v1 tags using jDataView: document.querySelector('input[type="file"]').onchange = function (e) { var reader = new FileReader(); reader.onload = function (e) { ...

Guide to transferring/managing information to/from a form using jquery

I am currently in the process of constructing some new posts and they can be linked to a file, task, or event. Therefore, I have included a section for each attachment type in my new_post_form. My inquiry is regarding how to prevent data submission if the ...

Encountering difficulties with uploading files and images in a Node.js environment

Currently, I am learning node js and express js on Tutorial Point. In the course, I attempted to upload a document but encountered an error that says "Cannot read property 'file' of undefined." Can someone please assist me in resolving this issue ...

Exploring the World of Browserify Submodules

/xyz /abc.js /abcdef.js /index.js When working with node.js, if you use the require statement for a directory (require('xyz')), it will automatically search for an index.js file within that directory and return the exports defined in that ...

Combining elements from a single array list and transferring them to another array list using Angular 4

In my arrayList called selectedSources, I have items such as: this.selectedSources.push( { id: 0, text: "A" }, { id: 1, text: "B" }, { id: 2, text: "C" }, { id: 3, text: "D"} ); The user has the option to select one or more of these items. When i ...