question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Performance issue dynamically adding many markers

See original GitHub issue

I have a map that loads additional markers when the user pans/zooms.

Looking for any ideas here on how I can manage the performance issues as the number of markers grows and each map move results in a re-render of every marker.

What’s worse is our search method returns paginated marker results so each map move can result in 1-10 additional re-renders of all markers on the map.

Here is what it looks like…

MyGoogleMap.jsx

import React, {Component, PropTypes} from 'react';
import {withGoogleMap, GoogleMap, Marker, KmlLayer} from 'react-google-maps';
import {maps as gmaps} from 'google';
import {MARKER_CONFIG} from 'map-utils';

class MyGoogleMap extends Component {
    constructor(props) {
        super(props);

        this._markers = {};
        this._MARKER_SPRITE_PATH = '/static/main/img/sprites/sprite-markers@2x.png';
        this._HOVER_Z_INDEX = 1001;
    }

    render() {
        const {
            markers,
            zoom,
            position,
            mapOptions,
            onDragStart,
            onDragEnd,
            onIdle,
            onGoogleMapLoaded,
            getMarkerLabelText
        } = this.props;
        const renderedMarkers = (markers && markers.length > 0)
            ? markers.map(marker => {
                const {
                    spot,
                    state
                } = marker;
                const {
                    spotId,
                    latitude,
                    longitude,
                    activeMarker,
                    selectedRate,
                    facility,
                    title
                } = spot;
                const markerType = (selectedRate.unavailable)
                    ? 'disabled'
                    : (activeMarker)
                        ? 'large'
                        : 'medium';
                const icon = {
                    url: this._MARKER_SPRITE_PATH,
                    ...MARKER_CONFIG[markerType][state].icon
                };
                const zIndex = (state === 'hover')
                    ? this._HOVER_Z_INDEX
                    : (activeMarker)
                        ? this._HOVER_Z_INDEX - 1
                        : null;
                const markerText = getMarkerLabelText({selectedRate});
                const labelFontSize = (markerText.length > 5)
                    ? `${parseInt(MARKER_CONFIG[markerType][state].label.fontSize.replace('px', ''), 10) - 2}px`
                    : MARKER_CONFIG[markerType][state].label.fontSize;

                return (
                    <Marker
                        ref={node => {
                            this._markers[spotId] = {
                                node,
                                markerType
                            };
                        }}
                        key={spotId}
                        icon={icon}
                        title={title}
                        label={
                            (markerType === 'disabled' && state === 'default')
                                ? ''
                                : {
                                    text: markerText,
                                    color: MARKER_CONFIG[markerType][state].label.color,
                                    fontSize: labelFontSize,
                                    fontWeight: 'bold',
                                    fontFamily: 'Open Sans,sans-serif'
                                }
                        }
                        position={new gmaps.LatLng(latitude, longitude)}
                        zIndex={zIndex}
                    />
                );
            })
            : null;

        return (
            <GoogleMap
                ref={onGoogleMapLoaded}
                zoom={zoom}
                defaultCenter={position}
                options={mapOptions}
                onDragStart={onDragStart}
                onDragEnd={onDragEnd}
                onIdle={onIdle}
            >
                {renderedMarkers}
            </GoogleMap>
        );
    }
}

MyGoogleMap.propTypes = {
    markers: PropTypes.array.isRequired,
    zoom: PropTypes.number.isRequired,
    position: PropTypes.object.isRequired,
    mapOptions: PropTypes.object.isRequired,
    onDragStart: PropTypes.func.isRequired,
    onDragEnd: PropTypes.func.isRequired,
    onIdle: PropTypes.func.isRequired,
    onGoogleMapLoaded: PropTypes.func.isRequired,
    getMarkerLabelText: PropTypes.func.isRequired
};

export default withGoogleMap(MyGoogleMap);

And the parent render method (the markers come from the state and are updated when the map moves causing a re-render of the MyGoogleMap.jsx)…

return (
    <MyGoogleMap
        ref={node => { this._map = node; }}
        containerElement={
            <div
                style={{
                    height: '100%'
                }}
            />
        }
        mapElement={
            <div
                style={{
                    height: '100%'
                }}
            />
        }
        markers={markers}
        zoom={zoom}
        position={position}
        mapOptions={this._mapOptions}
        onDragStart={this._onDragStart}
        onDragEnd={this._onDragEnd}
        onIdle={this._onIdle}
        onGoogleMapLoaded={this._onGoogleMapLoaded}
        getMarkerLabelText={this._getMarkerLabelText}
    />
);

Any help would be greatly appreciated, kinda stumped here. Thanks in advance!

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:13

github_iconTop GitHub Comments

10reactions
ntomkincommented, Jan 8, 2019

Adding key to MarkerClusterer saved the day.

1reaction
bmakuhcommented, Aug 14, 2017

@walreyes thanks for the tip! Working with the Google Maps API was way more of a pain than I envisioned it being, but we got it shipped, so thanks for the help! I appreciate it.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Adding many markers using leaflet slows down browser
Adding many markers (10000) using leaflet is slowing down the browser. markers are moving after every 5 sec. How can performance issue solved ......
Read more >
Bug: Poor performance adding markers: each ... - Issue Tracker
I'm currently batch-adding a few hundred MarkerOptions to the map and it takes about 500ms for 250 markers. In the maps V1 we...
Read more >
Performance issue with native map and custom markers
On react-native my custom markers (they are react-native dynamic views, not just images (if they where just images, they could be directly ...
Read more >
Leaflet.markercluster | Marker Clustering plugin for Leaflet
Creates a Feature Group that adds its child layers into a parent group when added to a map (e.g. through L.Control.Layers). Typical usage...
Read more >
Performant Custom Map Markers for React-Native-Maps
This works okay until you have multiple markers. Even adding 10 custom markers to the map like this can cause serious performance issues...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found