1

currently, I'm displaying a single copy of the map. while panning at the edge of the graph or zooming out further from the makers changing their positions. I want to have the markers stay in their position even when these operations are done how can I achieve that.

codesanbox - https://codesandbox.io/s/mapbox-marker-issue-03cdc

index.js

import "mapbox-gl/dist/mapbox-gl.css";
import "react-map-gl-geocoder/dist/mapbox-gl-geocoder.css";
import React, { useState, useRef, useCallback } from "react";
import { render } from "react-dom";
import MapGL from "react-map-gl";
import Pins from "./pins";

import CITIES from "./cities.json";
const MAPBOX_TOKEN =
  "pk.eyJ1Ijoic21peWFrYXdhIiwiYSI6ImNqcGM0d3U4bTB6dWwzcW04ZHRsbHl0ZWoifQ.X9cvdajtPbs9JDMG-CMDsA";

const App = () => {
  const [viewport, setViewport] = useState({
    latitude: 37.7577,
    longitude: -122.4376,
    zoom: 8
  });
  const mapRef = useRef();
  const handleViewportChange = useCallback(
    (newViewport) => setViewport(newViewport),
    []
  );

  return (
    <div style={{ height: "100vh" }}>
      <MapGL
        ref={mapRef}
        {...viewport}
        width="90vw"
        height="90vh"
        onViewportChange={handleViewportChange}
        mapboxApiAccessToken={MAPBOX_TOKEN}
        mapOptions={{
          renderWorldCopies: false,
          maxBounds: [
            [-180, -90], // Southwest coordinates
            [180, 90] // Northeast coordinates
          ]
        }}
      >
        <Pins data={CITIES} onClick={() => {}} />
      </MapGL>
    </div>
  );
};

render(<App />, document.getElementById("root"));

pins.js

import * as React from "react";
import { Marker } from "react-map-gl";

const ICON = `M20.2,15.7L20.2,15.7c1.1-1.6,1.8-3.6,1.8-5.7c0-5.6-4.5-10-10-10S2,4.5,2,10c0,2,0.6,3.9,1.6,5.4c0,0.1,0.1,0.2,0.2,0.3
  c0,0,0.1,0.1,0.1,0.2c0.2,0.3,0.4,0.6,0.7,0.9c2.6,3.1,7.4,7.6,7.4,7.6s4.8-4.5,7.4-7.5c0.2-0.3,0.5-0.6,0.7-0.9
  C20.1,15.8,20.2,15.8,20.2,15.7z`;

const SIZE = 20;

// Important for perf: the markers never change, avoid rerender when the map viewport changes
function Pins(props) {
  const { data, onClick } = props;

  return data.map((city, index) => (
    <Marker
      key={`marker-${index}`}
      longitude={city.longitude}
      latitude={city.latitude}
    >
      <svg
        height={SIZE}
        viewBox="0 0 24 24"
        style={{
          cursor: "pointer",
          fill: "#d00",
          stroke: "none",
          transform: `translate(${-SIZE / 2}px,${-SIZE}px)`
        }}
      >
        <path d={ICON} />
      </svg>
    </Marker>
  ));
}

export default React.memo(Pins);

data - https://github.com/visgl/react-map-gl/raw/master/examples/.data/cities.json

Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
Syntax Hacker
  • 314
  • 1
  • 5
  • 18

1 Answers1

0

You have run into a limitation with react-map-gl: https://github.com/visgl/react-map-gl/issues/786

you cannot use maxBounds because react-map-gl is not using mapbox-gl-js's built-in interaction handling logic. To constrain the map bounds you should do something like

_onViewportChange = (viewport) => {
  const oldViewport = this.state.viewport;
  if (Math.abs(oldViewport.longitude - viewport.longitude) > 180) {
    // wrapped around the 180th meridian
    return;
  }
  this.setState({viewport});
}

As a workaround, you can remove the settings maxBounds and renderWorldCopies. Or follow the advice in that thread.

Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
  • I came across this same issue, and looked at the link provided above, but the solution provided here has been downvoted, I don't know the reason but the implementation didn't work for me, if you scroll down until **kieranongh** post you will find a solution that works as it did in my case – Ricardo Sanchez Jun 29 '21 at 17:01