Is it possible to set a radius of an array of coordinates?

890 views Asked by At

I'm still a beginner in working with google maps and ReactJS. I'm using google-maps-react to plot my map.

I have a property that is rendered on the map. This property is a set of several polygons, all of these polygons together form the property (farm).

When I click on a particular polygon, I get all the coordinates of that polygon that was clicked:

enter image description here

I would like to know, is it possible to show a 10km radius surrounded by the selected polygon?

From what I've researched, it is possible to show a radius through a single point, that is, a single latitude, and a single longitude. In my case, a polygon can have hundreds of latitutes and hundreds of longitutes. As you can see in the image above.

Can you tell me how do I configure a 10km radius based on the polygon that was selected?

I put my code into codesandbox

Here where I plot my map:

import React, { useState, useEffect } from "react";
import { Map, Polygon, GoogleApiWrapper } from "google-maps-react";
import data from "./api/coordinates.json";

const Colors = {
  SELECTED: "blue",
  DEFAULT: "#02482b",
  OVER: "red"
};

const Maps = () => {
  const [poligons, setPoligons] = useState([]);
  const [selected, setSelected] = useState([]);
  const [polygonOptions, setPolygonOptions] = useState({
    strokeColor: Colors.DEFAULT,
    strokeOpacity: 0.8,
    strokeWeight: 2,
    fillColor: Colors.DEFAULT,
    fillOpacity: 0.35,
    polygonKey: 1
  });
  const [areaPosition, setAreaPosition] = useState({
    lat: -22.735840991240327,
    lng: -47.574046945850164
  });

  const reduceMap = () => {
    const _poligons = data.reduce((acc, [coords]) => {
      const paths = coords.map(([lng, lat]) => ({ lng, lat }));
      acc.push(paths);
      return acc;
    }, []);
    setPoligons(_poligons);
  };

  useEffect(() => {
    reduceMap();
  }, []);

  const selectedArea = (polygon) => {
    for (let i = 0; i < selected.length; i++) {
      const _polygon = selected[i];
      _polygon.setOptions({ fillColor: Colors.DEFAULT });
    }
    setSelected([polygon]);
    polygon.setOptions({ fillColor: Colors.SELECTED });
  };

  const handleClick = (props, polygon, event) => {
    setAreaPosition({ lat: event.latLng.lat(), lng: event.latLng.lng() });
    const paths = polygon.getPaths().getArray();
    const coordinates = paths.map((path) => {
      const points = path.getArray();
      return points.map((point) => [point.lng(), point.lat()]);
    });

    selectedArea(polygon);
    console.log("polygon selected: ", coordinates);
  };

  const handleMouseOver = (props, polygon) => {
    polygon.setOptions({
      fillColor:
        polygon.fillColor !== Colors.SELECTED ? Colors.OVER : Colors.SELECTED
    });
  };

  const handleMouseOut = (props, polygon) => {
    polygon.setOptions({
      fillColor:
        polygon.fillColor !== Colors.SELECTED ? Colors.DEFAULT : Colors.SELECTED
    });
  };

  return (
    <>
      <Map
        google={google}
        style={{ width: "90%", height: "70%", marginTop: "10px" }}
        zoom={13}
        initialCenter={{
          lat: `${areaPosition.lat}`,
          lng: `${areaPosition.lng}`
        }}
        clickableIcons={false}
        className={"map"}
        center={{ lat: `${areaPosition.lat}`, lng: `${areaPosition.lng}` }}
      >
        {poligons.map((coord, i) => (
          <Polygon
            key={`polygon-${i}`}
            onMouseover={handleMouseOver}
            onMouseout={handleMouseOut}
            paths={coord}
            options={polygonOptions}
            onClick={handleClick}
          />
        ))}
      </Map>
    </>
  );
};

export default GoogleApiWrapper({
  apiKey: ""
})(Maps);

Thank you in advance.

1

There are 1 answers

0
Pagemag On
  1. You can get the bounds of your polygon
  2. set the center of the bounds as the starting point of your radius
  3. get the distance between the center of your bounds to either the northeast or southwest point of the bounds to get the maximum radius that your polygon has
  4. Add this distance to your 10km radius

Here's a code snippet of my function when clicking the polygon:

onPolyClick = (props, polygon, e) => {
    console.log("onclick:");

    //getting the bounds of my polygon
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < props.paths.length; i++) {
      bounds.extend(props.paths[i]);
    }

    //getting the distance of the edge of the polygon bounds
    let boundsEdgeDistance = google.maps.geometry.spherical.computeDistanceBetween(
      bounds.getCenter(),
      bounds.getNorthEast()
    );

    //setting center of the bounds as polygonCenter and adding the calculated distance to the 10km radius
    this.setState({
      polygonCenter: bounds.getCenter(),
      radius: 10000 + boundsEdgeDistance
    });
  };

Here's the working code andd the whole code snippet:

import React, { Component } from "react";
import { Map, GoogleApiWrapper, Polygon, Circle } from "google-maps-react";
import data from "./data.json";
const dataArray = [];
const polygonPath = [];
//putting my json data in an array
dataArray.push(data.coordinates);

//formatting the json data to have lat and lng
for (let x = 0; x < dataArray[0].length; x++) {
  let coords = { lat: dataArray[0][x][0], lng: dataArray[0][x][1] };
  polygonPath.push(coords);
}

export class MapContainer extends Component {
  state = {
    center: { lat: 32.321, lng: -64.757 },
    polygonCenter: null,
    radius: null
  };

  onPolyClick = (props, polygon, e) => {
    console.log("onclick:");

    //getting the bounds of my polygon
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < props.paths.length; i++) {
      bounds.extend(props.paths[i]);
    }

    //getting the distance of the edge of the polygon bounds
    let boundsEdgeDistance = google.maps.geometry.spherical.computeDistanceBetween(
      bounds.getCenter(),
      bounds.getNorthEast()
    );

    //setting center of the bounds as polygonCenter and adding the calculated distance to the 10km radius
    this.setState({
      polygonCenter: bounds.getCenter(),
      radius: 10000 + boundsEdgeDistance
    });
  };

  onPolyHover = (props, polygon, e) => {
    console.log("onHover:");
    console.log(polygon.getPaths());
    polygon.setOptions({ fillColor: "#ff00ff" });
  };

  onPolyHoverOut = (props, polygon, e) => {
    console.log("onHover:");

    polygon.setOptions({ fillColor: "#0000FF" });
  };
  render() {
    if (!this.props.loaded) return <div>Loading...</div>;

    return (
      <div>
        <Map
          className="map"
          google={this.props.google}
          onClick={this.onMapClicked}
          initialCenter={{
            lat: -47.7027099655629,
            lng: -22.26485424139211
          }}
          style={{ height: "100%", position: "relative", width: "100%" }}
          zoom={15}
        >
          <Polygon
            paths={polygonPath}
            strokeColor="#0000FF"
            strokeOpacity={0.8}
            strokeWeight={2}
            fillColor="#0000FF"
            fillOpacity={0.35}
            onClick={this.onPolyClick}
            onMouseover={this.onPolyHover}
            onMouseout={this.onPolyHoverOut}
          />

          {this.state.radius !== null && (
            <Circle
              radius={this.state.radius}
              center={this.state.polygonCenter}
              onMouseover={() => console.log("mouseover")}
              onClick={(props, circle) => console.log(circle.getRadius())}
              onMouseout={() => console.log("mouseout")}
              strokeColor="transparent"
              strokeOpacity={0}
              strokeWeight={5}
              fillColor="#FF0000"
              fillOpacity={0.2}
            />
          )}
        </Map>
      </div>
    );
  }
}
export default GoogleApiWrapper({
  apiKey: "YOUR_API_KEY",
  libraries: ["geometry"]
})(MapContainer);