Search code examples
javascriptreactjsgoogle-maps-api-3react-google-maps

How to change the default Marker used in the Google Maps API Drawing Layer controls


I would like to know how could I use a custom marker with google maps drawing controls. I want to do that because I need to place a marker when a user clicks in the map and have it open a info window (when clicked) and have a few custom actions in there (buttons and such).

I'm using react and @react-google-maps/api for this, but that might be besides the point since it is just a wrapper around the Maps Javascript API provided by Google.

From the docs it is possible to provide google.maps.MarkerOptions to the google.maps.drawing.DrawingManagerOptions. Unfortunately there is no option there to provide a custom Marker to be rendered.

I tried using the markercomplete() call back exposed by the google.maps.drawing.DrawingManager since it has the newly created Marker as parameter, and then doing something like this:

const handleNewMarker = (marker) => {
  marker.addListener('click', function() {
    setActiveMarker(marker);
  });
}

My map component would then be something like this:

<GoogleMap
  zoom={18}
  center={latLng}
>
  {activeMarker && <CustomInfoWindow anchor={activeMarker} />}
  <DrawingManager
    options={{
      markerOptions: {
        clickable: true,
        draggable: true,
      },
    }}
    onMarkerComplete={handleNewMarker}
  />
</GoogleMap>

Although this worked, it is not at all viable for production, for some reason the InfoWindow takes too much time to appear in the screen, that approach might be causing a memory leak and I don`t know why.

I might be missing something here, but on my research I didn't find a single soul trying to create a custom marker with the drawing tool, just custom markers by themselves which is relatively easy to do. My ideal case scenario, since I'm using React, would be to create a CustomMarker component with a CustomInfoWindow inside it, and just tell the drawing controls, "hey, take this marker and use it whenever a user tries to draw a new marker with your drawing tool".

Thank you.

Edit

Here is a screenshot of what I mean, that marker in the screen shot was placed there using the "new marker" drawing control, and I need the "new marker" drawing control to place a custom marker defined by me.

enter image description here


Solution

  • All you need to do is to set the icon property in the MarkerOptions, if I correctly understand your meaning of "custom marker". Below is an example using a SVG path for the icon.

    This snippet is in full JS but the same should work with the React library.

    var map;
    
    function initialize() {
    
      var mapOptions = {
        center: new google.maps.LatLng(-34.397, 150.644),
        zoom: 8
      };
    
      map = new google.maps.Map(document.getElementById('map'), mapOptions);
    
      var drawingManager = new google.maps.drawing.DrawingManager({
    
        drawingControl: true,
        drawingControlOptions: {
          position: google.maps.ControlPosition.TOP_CENTER,
          drawingModes: [google.maps.drawing.OverlayType.MARKER]
        },
        markerOptions: {
          draggable: false,
          icon: {
            path: "M-20,0a20,20 0 1,0 40,0a20,20 0 1,0 -40,0",
            fillColor: '#FF0000',
            fillOpacity: 0.6,
            anchor: new google.maps.Point(0, 0),
            strokeWeight: 0,
            scale: 1
          }
        }
      });
    
      drawingManager.setMap(map);
    }
    #map {
      height: 180px;
    }
    <div id="map"></div>
    
    <!-- Replace the value of the key parameter with your own API key. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize&libraries=drawing" async defer></script>

    Now if you need the marker to be clickable, have an Infowindow, etc. do you really need to use the drawing manager? Could you not simply listen for a map click event, and create a standard marker?

    Or possibly, use both? (Create the marker with the drawing manager and convert it to a standard marker by the use of the markercomplete event, which seems to be more or less what you are doing.)

    Edit:

    If you need to create a "real" marker with an InfoWindow, you can do it in the markercomplete event.

    var map;
    var infowindow;
    
    function initialize() {
    
      var mapOptions = {
        center: new google.maps.LatLng(-34.397, 150.644),
        zoom: 8
      };
    
      map = new google.maps.Map(document.getElementById('map'), mapOptions);
      infowindow = new google.maps.InfoWindow();
    
      var drawingManager = new google.maps.drawing.DrawingManager({
    
        drawingControl: true,
        drawingControlOptions: {
          position: google.maps.ControlPosition.TOP_CENTER,
          drawingModes: [google.maps.drawing.OverlayType.MARKER]
        }
      });
    
      drawingManager.setMap(map);
    
      google.maps.event.addListener(drawingManager, 'markercomplete', function(marker) {
    
        // Remove overlay from map
        marker.setMap(null); // Optional, but this will remove the drawn marker
        drawingManager.setDrawingMode(null); // Optional, but this will "disable" the drawing tools
    
        // Create the "real" marker
        createMarker(marker.getPosition());
      });
    }
    
    function createMarker(position) {
    
      var marker = new google.maps.Marker({
        position: position,
        map: map,
        title: 'Custom marker',
        icon: {
          path: "M-20,0a20,20 0 1,0 40,0a20,20 0 1,0 -40,0",
          fillColor: '#FF0000',
          fillOpacity: 0.6,
          anchor: new google.maps.Point(0, 0),
          strokeWeight: 0,
          scale: 1
        }
      });
    
      google.maps.event.addListener(marker, 'click', function() {
        infowindow.setContent('This is the content');
        infowindow.open(map, this);
      });
    }
    #map {
      height: 180px;
    }
    <div id="map"></div>
    
    <!-- Replace the value of the key parameter with your own API key. -->
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initialize&libraries=drawing" async defer></script>