shishy
shishy

Reputation: 817

React Leaflet: How to have Multiselect on Map

I'm using React and React-Leaflet to generate a map of circleMarkers given data points and their Lat/Long coordinates. I have no issues rendering a map of data, and even being able to change the data rendered if a user filters by filter type on a sidebar.

<Map center={[this.props.data[0].Latitude, this.props.data[0].Longitude]} zoom={12}>
    <TileLayer
      attribution="&amp;copy <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
    />

    /* code for rendering circleMarkers goes here */

</Map>

When a user clicks on a marker, I have it so a popup appears on the map for the data with a little blurb about the corresponding point.

<CircleMarker center={[entry.Latitude, entry.Longitude]} color={this.determineMarkerColor(entry)} radius={this.computeMarkerSize(entry)}>
          <Popup>
              <span>Radius is for: {this.props.filterType} </span>
          </Popup>
</CircleMarker>

Is there a way to configure the Map so that it can figure out when a user is trying to, for example, shift click to select multiple points and then pass the selected points as an array? Or, even better, how can I make the Map interactive so a user can drag and drop a custom area (like drawing a square or circle) and select all rendered points WITHIN that area?

I'm planning on passing this array of selected data to another component that will graph it.

Any advice on where to look for this would be appreciated.

Upvotes: 2

Views: 3732

Answers (2)

alumedot
alumedot

Reputation: 51

It's already almost 3 years passed away but here is my solution with pressing shift and selecting an area of markers, maybe it will be useful for somebody

Map has onmousedown & onmouseup methods

<Map
  ref={saveMap}
  onmousedown={onMouseDown} // set start position in state
  onmouseup={onMouseUp} // end position and logic to select markers
  className="leaflet-container"
  center={position}
  zoom={viewport.zoom}
>

With onmousedown it is possible to find the start position when the user pressed shift and started to move the mouse to select an area

onmousedown returns an event with latlng property - start position:

const onMouseDown = useCallback((e: LeafletMouseEvent) => {
  if (e.originalEvent.shiftKey) { // check if the shift key been pressed
    setStartPoint(e.latlng);
  }
}, []);

onmouseup also returns an event with latlng property - end position:

const onMouseUp = useCallback((e: LeafletMouseEvent) => {
  if (e.originalEvent.shiftKey && startPoint) {
    const bounds = new L.LatLngBounds(startPoint, e.latlng); // creates a class which will help to identify if an element is within the selection boundaries
    const selectedIds: string[] = [];

    for (let i = 0; i < orders?.length; i++) {
      const { geometry: { coordinates } } = orders[i];
      const point = new L.LatLng(coordinates[0], coordinates[1]);
      bounds.contains(point) && selectedIds.push(orders[i].properties.entry);
    }
    onSelectOrder(selectedIds);
    setStartPoint(null);
  }
}, [onSelectOrder, orders, startPoint]);

It works pretty well for my purposes to select multiple orders on the map

Upvotes: 5

Rodius
Rodius

Reputation: 2311

You could play around with leaflet-draw in order to get the selection tool that you want. With leaflet-draw you can draw polygons, circles, rectangles, etc and get the bounds of the figure you've drawn. There's also a library called point-in-polygon that can return the coordinates inside a boundaries parameter.

TLDR:

  1. Draw polygon with Leaflet Draw and get the bounds of your drawn figure.
  2. Filter your markers that have their {latitude, longitude} inside the bounds with Point-in-polygon.

Upvotes: 4

Related Questions