Mapbox Gl Js Draw Circle

When our apps demand a web map, we turn to MapboxGL, a cut-edge open source mapping library that allows us to build fast, cute maps. Not too long after we started tinkering with MapboxGL, we were faced with the need to let the user draw polygons. Enter mapbox-gl-draw, an add-on to MapboxGL that gives you some simple draw controls, renders shapes on the screen as the user draws a betoken, line, or polygon, and gives y'all some nice event hooks.

Yous tin encounter mapbox-gl-describe in activeness in ZoLa's measurement tool:

In this case, we're still using the out-of-the-box functionality of the draw tools but accept added a custom control to cull between line and polygon mode, and a UI for displaying the measurement (and switching units!).

We recently encountered a need to take the user select geometries on a web map by radius from a center point. Mapbox-gl-draw does non include a circle-drawing way.

One approach would be to have the user select a heart point, and so enter a radius using a text input, only information technology would exist better if the user could see the circle they are defining as they define information technology, just like they can with the polygon and line tools.

What'due south a radius, really? Well, it's a line, and mapbox-gl-draw already has a line tool. And so, what we demand to do is modify the line tool with the post-obit rules:

  1. The user's outset click is the center indicate
  2. As the user moves the arrow, return both the line between the center bespeak and the arrow, and the circle that they are defining.
  3. The user's 2nd click always ends the drawing.
  4. When drawing is complete, the resulting GeoJSON is a Point characteristic for the eye betoken, with a radius property.

Hither's what it looks like in our app:

Using the custom radius mode to select census tracts

How we built it

After some snooping, we discovered that mapbox-gl-draw allows you to define custom cartoon modes, and has a overnice markdown file all about it. We didn't want to start from scratch, so we decided to hijack the Line manner.

          const draw = new MapboxDraw({
displayControlsDefault: false,
styles: drawStyles,
modes: Object.assign({
draw_radius: RadiusMode,
}, MapboxDraw.modes),
});

We instantiate mapbox-gl-depict using a modes property in the options. RadiusMode is our new custom mode which is actually simply the built-in line mode that's been modified to run into our needs.

To create RadiusMode, we started with importing the existing line tool.

          const RadiusMode = MapboxDraw.modes.draw_line_string;        

Then we define new functions for some of the line tool's result listeners, in gild to reach the rules described above.

Rule #1 works out of the box: the first click will fix the first vertex of the line.

For dominion #2, we get half of the functionality for free considering the line tool already draws the line betwixt the offset vertex and the pointer. To describe the circumvolve, we actually end up cartoon a circle-like polygon.

RadiusMode.toDisplayFeatures() is called with each move of the mouse, and fires display() for each GeoJSON feature that should be displayed in real time. The existing line tool displays the vertices and the line, then we added one more to display the circle-like polygon.

          const circleFeature = createGeoJSONCircle(eye, radiusInKm, state.line.id);          display(circleFeature);        

Creating the circle-like polygon was simple using an algorithm nosotros found in this Stack Overflow post. Given a eye point and radius in kilometers, it creates a 64-point polygon that resembles a circle.

          function createGeoJSONCircle(center, radiusInKm, parentId, points = 64) {
const coords = {
latitude: center[1],
longitude: middle[0],
};
const km = radiusInKm; const ret = [];
const distanceX = km / (111.320 * Math.cos((coords.latitude * Math.PI) / 180));
const distanceY = km / 110.574;
let theta;
let x;
let y;
for (permit i = 0; i < points; i += 1) {
theta = (i / points) * (2 * Math.PI);
x = distanceX * Math.cos(theta);
y = distanceY * Math.sin(theta);
ret.button([coords.longitude + 10, coords.latitude + y]);
}
ret.push button(ret[0]);
return {
type: 'Feature',
geometry: {
blazon: 'Polygon',
coordinates: [ret],
},
properties: {
parent: parentId,
},
};
}

Nosotros had originally attempted to utilise a MapboxGL circle marker, just by using a circle-similar polygon the feature still remains accurate even if the map is pitched!

For the best user experience when drawing a radius, we besides added a label layer to the map showing the in-progress radius in both standard and metric formats. We borrowed the aforementioned logic for switching from meters to kilometers, and feet to miles as was used in ZoLa'due south drawing tool.

The last footstep was to hijack RadiusMode.clickAnywhere() to force cartoon to cease after the second click (dominion #3 above). clickAnywhere(), equally the name suggests, is called when the user clicks anywhere after drawing begins.

          RadiusMode.clickAnywhere = function(land, e) {
// this ends the drawing after the user creates a second point, triggering this.onStop
if (state.currentVertexPosition === 1) {
state.line.addCoordinate(0, due east.lngLat.lng, e.lngLat.lat);
return this.changeMode('simple_select', { featureIds: [state.line.id] });
}
...
// default click handling remains the same, adding the vertex to the state.
}

There's a bit more to it, simply those are the highlights. In our app, we apply the GeoJSON Point feature created by the drawing tools to exercise an ST_Dwithin() query in PostGIS, selecting polygons that are within the specified distance of the center point.

You can inspect the total RadiusMode module here, and see it in activeness in our NYC Population Factfinder census data tool. We promise this will exist a useful starting betoken for anyone thinking of extending a mapbox-gl-draw manner or writing their own.

Happy hacking!

morrisonforianst.blogspot.com

Source: https://medium.com/nyc-planning-digital/building-a-custom-draw-mode-for-mapbox-gl-draw-1dab71d143ee

0 Response to "Mapbox Gl Js Draw Circle"

إرسال تعليق

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel