Is there a way to avoid overlapping of markers and labels in react mapbox-gl?

564 views Asked by At

How to avoid marker and label overlapping in mapbox gl using react?

Am trying to avoid the overlap of labels when the labels are very close to each other in both zoom-in and zoom-out conditions.

Is there any way that we can overcome this issue in mapbox-gl when coded in react?

import React, {
    createRef,
    useMemo
} from "react";

import ReactMapboxGl, {
    Marker,
    ZoomControl
} from "!react-mapbox-gl";
import mapbox from './mapbox.png';
import './mapbox.css';
import mapboxgl from '!mapbox-gl';
import "mapbox-gl/dist/mapbox-gl.css";

const Map = ReactMapboxGl({
    accessToken: "some token",
});


function Mapbox(props) {

    const markers = props.locationData;
    const zoomValue = useMemo(() => markers.map(() => createRef()), []);
    const getZoomValue = (e) => {
        for (let i = 0; i < markers.length; i++) {
            if (zoomValue[i] !== null && zoomValue[i].current !== (undefined || null)) {
                if (e.getZoom() === 12) {
                    zoomValue[i].current.style.fontSize = "20px";
                    zoomValue[i].current.style.color = "yellow";
                } else if (e.getZoom() > 12 && e.getZoom() <= 15) {
                    zoomValue[i].current.style.fontSize = "15px";
                    zoomValue[i].current.style.color = "yellow";
                } else if (e.getZoom() > 15 && e.getZoom() <= 17) {
                    zoomValue[i].current.style.fontSize = "10px";
                    zoomValue[i].current.style.color = "yellow";
                } else if (e.getZoom() > 17) {
                    zoomValue[i].current.style.fontSize = "5px";
                    zoomValue[i].current.style.color = "yellow";
                }
            }
        }
    }

    return ( <
        Map className = "map-main"
        viewport = {
            {
                latitude: 1.74328,
                longitude: 106.34792,
                zoom: 12,
            }
        }
        containerStyle = {
            {
                width: "100vw",

            }
        }
        style = ''
        center = {
            [106.989441, 1.45678]
        }
        zoom = {
            [12]
        }
        scrollZoom = {
            true
        }
        boxZoom = {
            true
        }
        onZoom = {
            (e) => {
                getZoomValue(e)
            }
        }
        maxBounds = {
            [
                [106.2006, 1.3890],
                [108.0700, 1.5680], {
                    padding: 200
                }
            ]
        }
        bearing = {
            [217.3]
        } >
        <
        div > {
            markers.map((mark, index) => {
                    return ( <
                        Marker key = {
                            index
                        }
                        coordinates = {
                            [mark.eastLong, mark.northLat]
                        }
                        anchor = "bottom" >
                        <
                        div className = "marker-text" >
                        <
                        img style = {
                            {
                                width: '8px',
                                height: '8px'
                            }
                        }
                        src = {
                            mapbox
                        }
                        alt = "mark" > < /img> <
                        div ref = {
                            zoomValue[index]
                        }
                        className = {
                            "marker-text"
                        } > {
                            mark?.location
                        } < /div> <
                        /div> <
                        /Marker>)
                    })
            } <
            /div> <
            ZoomControl position = "top-left" / >
            <
            /Map>

        )
    }

    export default Mapbox;

I could see that there are some items to add like text-allow-overlap and icon-allow-overlap, but am not sure where to add it.

1

There are 1 answers

0
ictekin On

Related CSS code below:

.marker-text {
  position: relative;
  z-index: 1;
}

Update the component inside the Mapbox component:

<Marker
  key={index}
  coordinates={[mark.eastLong, mark.northLat]}
  anchor="bottom"
>
  <div className="marker-text">
    <img style={{ width: '8px', height: '8px' }} src={mapbox} alt="mark" />
    <div ref={zoomValue[index]} className="marker-label">
      {mark?.location}
    </div>
  </div>
</Marker>

Define your CSS class, except for the map component:

.marker-label {
  position: absolute;
  top: -10px; /* or any other value */
  left: 10px; /* or any other value */
  background-color: yellow;
  font-size: 15px;
  color: yellow;
  padding: 2px 5px;
  white-space: nowrap;
}

After making these adjustments, the labels will be prevented from overlapping each other in convergence and divergence situations. You can customize the appearance of the tags according to your needs and get the desired result by adjusting the CSS values.