Marker with custom Label

Is there something like MarkerWithLabel that exists in react-google-maps/api?

Satish Kumar
fleetx engineering
3 min readSep 15, 2019

--

Recently we upgraded our frontend tech stack at fleetx.io. Along with upgrading react, webpack and all other libraries as a part of react migration from 15 to 16, we also decided to retire react-google-maps which is no longer maintained in favor of react-google-maps/api which is complete re-write of previous one.

But unfortunately while migrating to this new react google map library we ran into one problem. We at fleetx.io use very customized labels with marker and marker clusterer

For simplicity of this article, i will refer old library react-google-maps as v1 and new library react-google-maps/api as v2.

If you have used v1 you know that in that library we have an addon which let’s use custom labels with marker and one addon for clusterer also to support cluster of MarkerWithLabels.

So we were making use of these addons. But after moving to this v2 library we got into trouble because as of now(15 sept. 2019) it does not have anything like that just a simple text label(provided by google map) and that does not fulfill our needs.

So I started looking for solutions I even asked for help in v1 library community at spectrum. but unfortunately couldn't get any suitable solution.

but after lots of digging and thinking i was able to find a solution that was able to solve all of our problems.

I am going to share my solution here so other people may find it useful

I am going to share in two-parts
1. markerWithLabels without clusterer
2. markerWithLabels with clusterer

As a solution for a custom marker label, I used OverlayView with Marker of v2 library for both parts.

markerWithLabels without clusterer

this one is very simple I will just share the code, no need to explain much about it, it’s self-explanatory

const getPixelPositionOffset = (offsetWidth, offsetHeight, labelAnchor) => {
return {
x: offsetWidth + labelAnchor.x,
y: offsetHeight + labelAnchor.y,
};
};
<GoogleMap
options={options}
onLoad={onLoad}
>
<Marker
key='m'
position=
{marker.position}
{...marker}
>
</Marker>
<OverlayView
key='mwl'

position={marker.position}
mapPaneName={OverlayView.OVERLAY_MOUSE_TARGET}
getPixelPositionOffset={(x, y) => getPixelPositionOffset(x, y, { x: -30, y: -15 })}>
<div
style=
{{
background: `#203254`,
padding: `7px 12px`,
fontSize: '11px',
color: `white`,
borderRadius: '4px',
}}
>
{content}
</div>
</OverlayView>
</GoogleMap>
}

markerWithLabels with clusterer

const [markerLabels, setMarkerLabels] = React.useState([]);
const markes = ()=>{
....//create markers here or anyway you like
}
const getPixelPositionOffset = (offsetWidth, offsetHeight, labelAnchor) => {
return {
x: offsetWidth + labelAnchor.x,
y: offsetHeight + labelAnchor.y,
};
};
const markerLabelsHandler = (clusterer) => {
const markerLabelsList = [];
let allClusters = clusterer.clusters,
allMarkers;
forEach(allClusters, (cluster, clusterIndex) => {
allMarkers = cluster.getMarkers();
forEach(allMarkers, (marker, MarkerIndex) => {
labelAnchor = { x: -30, y: -15 }
if (allMarkers.length < MINIMUM_CLUSTER_SIZE) {
markerLabelsList.push(
<OverlayView
key=
{MarkerIndex}
position={marker.position}
mapPaneName= {OverlayView.OVERLAY_MOUSE_TARGET}
getPixelPositionOffset={(x, y) => getPixelPositionOffset(x, y, labelAnchor)}>
<div
style=
{{
background: `#203254`,
padding: `7px 12px`,
fontSize: '11px',
color: `white`,
borderRadius: '4px',
}}>
{marker.title}
</div>
</OverlayView>)
}
});
});
setMarkerLabels(markerLabelsList)
}
return <GoogleMap
options={options}
onLoad={onLoad}
>
<MarkerClusterer
onClusteringEnd=
{markerLabelsHandler}
ignoreHidden={true}
onClick={this.props.onMarkerClustererClick}
averageCenter
enableRetinaIcons
minimumClusterSize=
{MINIMUM_CLUSTER_SIZE}
maxZoom=
gridSize={50}
>
{markers}
</MarkerClusterer>
{markerLabels}</GoogleMap>

const markerLabelsHandler = (clusterer) => {
....}

I am calling this function on ‘onClusteringEnd’ event of MarkerClusterer

The reason behind this is that we can’t just create Labels and put them on map because then we wont be able to hide them when clustering happen.

so we are reading markers direcrtly from object(‘clusterer’) passed by onClusteringEnd event and then creating markerLabels based on that.

if (allMarkers.length < MINIMUM_CLUSTER_SIZE) {
....

I am checking this condition because only these markers will be visible others will be clustered, so those markerLabels have to be hidden. so creating marker labels for these only.

{marker.title}

this one is tricky while creating markers you have to pass title value so that can be used in markerLabels

Found this useful. Have a look at these other articles also.

--

--

Satish Kumar
fleetx engineering

AVP Engineering - frontend Apps at fleetx.io Ex-Aviso Inc. NITian 🎓