Search code examples
reactjsgoogle-mapsreact-google-maps

how can I change react-google-maps <DrawingManager> component prop drawingMode props in runtime without change component state


I'm using react-google-maps lib in my React project. I want that, after complete to draw a shape, the user can't draw anymore and the shape stays on the screen.

I have de flowing snippet:

<GoogleMap
  zoom={16}
  center={initialPosition}
  mapTypeId="satellite"
>
  <DrawingManager
    drawingMode={"polygon"}
    onPolygonComplete={onDrawComplete}
  />
</GoogleMap>

With this code, the use can draw any shape that he and how many shapes he want. I saw that I can change drawingMode of componente to null. I've tried to store this value in a component state, but when I tried to change this inside onDrawComplete() callback, the map re-renders and I don't want that behavior. Question: How can I change this prop to null without use component state?


Solution

  • You can achieve this by the following steps:

    1. Import the objects from the library:
    import {
      withGoogleMap,
      GoogleMap,
      Marker,
      Polyline,
      Circle,
      Rectangle,
      Polygon
    } from "react-google-maps";
    import { DrawingManager } from "react-google-maps/lib/components/drawing/DrawingManager";
    
    1. Declare different state variables for each of the overlay. These will be the variables that you will need in creating these different overlay objects. You should also have a variable for drawingControlEnabled to set the value of options>drawingControl parameter of Drawing Manager.
    this.state = {
          drawingControlEnabled: true,
          marker: null,
          polyline: null,
          circleRadius: null,
          circleCenter: null,
          rectangle: null,
          polygon: null,
          visible: true
        };
    
    1. Use drawing manager with onOverlayComplete parameter where it will go to a function that will listen everytime you are done drawing the overlay.
    <DrawingManager
              onOverlayComplete={this.overlay}
              defaultOptions={{
                drawingControlOptions: {
                  position: google.maps.ControlPosition.TOP_CENTER,
                  drawingModes: [
                    google.maps.drawing.OverlayType.CIRCLE,
                    google.maps.drawing.OverlayType.POLYGON,
                    google.maps.drawing.OverlayType.POLYLINE,
                    google.maps.drawing.OverlayType.RECTANGLE
                  ]
                }
              }}
              options={{
                drawingControl: this.state.drawingControlEnabled
              }}
            />
    
    1. In the onOverlayComplete function, you should set the drawingControlEnabled state to false. This will remove the Drawing Controls after the overlays are drawn. You should also have a switch case that will check the condition as to which overlay you had made. For each condition, get the value from the event.overlay for each overlay type and pass the value of the needed parameters for each overlay type in the state variables.
      overlay = e => {
        this.setState({
          drawingControlEnabled: false
        });
        console.log(e);
        switch (e.type) {
          case "marker":
            this.setState({
              marker: {
                lat: e.overlay.getPosition().lat(),
                lng: e.overlay.getPosition().lng()
              }
            });
            break;
          case "polyline":
            this.setState({
              polyline: e.overlay.getPath()
            });
            break;
          case "circle":
            this.setState({
              circleRadius: e.overlay.getRadius(),
              circleCenter: e.overlay.getCenter()
            });
            break;
          case "rectangle":
            this.setState({
              rectangle: e.overlay.getBounds()
            });
    
            break;
          case "polygon":
            this.setState({
              polygon: e.overlay.getPaths()
            });
            break;
        }
      };
    
    1. In the render() Area inside the object, add the different overlay object with the condition that check if the state variables for that object is not null. Doing this will only show the object once the state variables have values from the switch case above.
    {this.state.marker !== null && <Marker position={this.state.marker} />}
    
            {this.state.polyline !== null && (
              <Polyline path={this.state.polyline} />
            )}
            {this.state.circleRadius !== null && (
              <Circle
                radius={this.state.circleRadius}
                center={this.state.circleCenter}
                visible={this.state.visible}
              />
            )}
    
            {this.state.rectangle !== null && (
              <Rectangle bounds={this.state.rectangle} />
            )}
            {this.state.polygon !== null && <Polygon paths={this.state.polygon} />}
    

    Here is a working code sample. note: Put your API key in the index.js for it to work properly.