1

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

Alexandre Krabbe
  • 727
  • 1
  • 13
  • 33

1 Answers1

2

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>
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
  • Thanks for the reply, I need the marker created to be clickable because I'm creating a application that uses the poly line and the polygon drawing controls alongside with the marker control to allow the user to do some marking on map that will later be used on a city data analysis. The marker will allow the user to "Mark" a influence point in a given city. That point have some properties, like name and value (those properties is what I want the user to edit on the info window accessible though clicking on that newly created marker. – Alexandre Krabbe Jun 04 '20 at 14:24
  • I've tried creating a vector of markers and using the `markercomplete` call back add a new marker to that vector. Then inside the google maps I just iterate through that vector creating markers, but this time using a custom marker component with the info window I created. However that only seems to worm when reloading the map, at the moment the user adds a new marker using the drawing control, that custom marker is in fact created, but it is not clickable. I believe it is because there are actually 2 markers, my custom one and the default one on top of mine, so what I click is the default one. – Alexandre Krabbe Jun 04 '20 at 14:28
  • If I just use the map `onClick` call back to create the marker it works, but that will decentralize the controls for the user since they are already using poly lines to mark streets and polygons to mark districts in a city. Do you know how could I use the `markcomplete` event and not have two stacked markers? I was wondering if it would be possible to use the marker drawing control just to get the position of the point clicked but not actually create the default marker, then I would use that position to create my custom marker. – Alexandre Krabbe Jun 04 '20 at 14:30
  • Yes, I understand, but then you should do it as we both mentioned already: create the Marker with the drawing manager and when done, create the final "real" marker (and remove the one created with the drawing tools). I will add this part to my answer. – MrUpsidown Jun 04 '20 at 14:35
  • Please check the second snippet in my answer which does what you asked for except that it *will* create the default marker, and remove it right away. You can't even tell this is happening so that should be fine and I don't think you could do that differently. – MrUpsidown Jun 04 '20 at 14:54