Popup not appear on MapBox - reactjs

Help please, i`m not understande why i`m not see popup next to mark on map, i have selectedMarker state and state have coordinates and title, but when i click on mark i don`t see popup with title.
import Map, {Marker, Popup} from 'react-map-gl';
import getCenter from 'geolib/es/getCenter';
import {SearchPageProps} from '#/interfaces';
import 'mapbox-gl/dist/mapbox-gl.css';
interface ISelectedMarker {
long: number;
lat: number;
title: string;
}
const ReactMap = ({searchResultItems}: SearchPageProps) => {
const coordinates = searchResultItems.map(({long, lat}) => ({
longitude: long,
latitude: lat,
}));
const [selectedMarker, setSelectedMarker] = useState<ISelectedMarker | null>(null);
const center = getCenter(coordinates);
const [viewPort, setViewPort] = useState({
longitude: center ? center.longitude : 0,
latitude: center ? center.latitude : 0,
zoom: 11,
});
console.log(selectedMarker?.title);
return (
<Map
mapStyle={'mapbox://styles/nealesha/cle7nqemb00bj01te4og4kd05'}
initialViewState={viewPort}
mapboxAccessToken={process.env.mapbox_key}
onMove={evt => setViewPort(evt.viewState)}>
{searchResultItems.map(({long, lat, title}, index) => (
<div key={`${long}_${lat}_${index}`}>
<Marker longitude={long} latitude={lat} anchor={'left'}>
<p
role={'img'}
aria-label={'push-pin'}
onClick={() => setSelectedMarker({long, lat, title})}
className={'cursor-pointer text-2xl'}>
📌
</p>
</Marker>
{selectedMarker?.long === long && (
<Popup longitude={long} latitude={lat}>
<div>{title}</div>
</Popup>
)}
</div>
))}
</Map>
);
};
export default ReactMap;
I don`t found some exaples for nextJs or react in mapbox docs

Related

react-map-gl load map on the location of the user

Using react 18 and react-map-gl 7.0.11, im not able to load the map on the location of the user.
I am able to get this button on the screen using the GeoLocateControl component
https://i.stack.imgur.com/fBy1y.png
<Map
{...viewState}
reuseMaps
mapStyle="mapbox://styles/mapbox/streets-v9"
mapboxAccessToken={process.env.REACT_APP_MAPBOX_KEY}
onMove={(evt) => setViewState(evt.viewState)}
>
<GeolocateControl
positionOptions={{
enableHighAccuracy: true,
}}
trackUserLocation={true}
onGeolocate={(pos) => {
setViewState({
...viewState,
longitude: pos.coords.longitude,
latitude: pos.coords.latitude,
});
}}
/>
</Map>
Is there a way, to trigger the button click to move the map and the blue dot to the current location of the user on mount of the component (map), without setting up event listeners? I tried the method of declaring a ref, and using useCallback to trigger the ref, but it did not work.
Any suggestions?
as per https://blog.logrocket.com/using-mapbox-gl-js-react/: you can do something like:
function MyMap() {
const [viewport, setViewport] = useState({});
useEffect(() => {
navigator.geolocation.getCurrentPosition((pos) => {
setViewport({
...viewport,
latitude: pos.coords.latitude,
longitude: pos.coords.longitude,
zoom: 3.5,
});
});
}, []);
return (
<div>
{viewport.latitude && viewport.longitude && (
<div>
<h1>Your Location:</h1>
<Map
mapboxAccessToken="MAPBOX_TOKEN"
initialViewState={viewport}
mapStyle="mapbox://styles/mapbox/streets-v11"
>
<Marker
longitude={viewport.longitude}
latitude={viewport.latitude}
/>
</Map>
</div>
)}
</div>
);
}

Need To back draggable marker's lat and lang to the main page from where it called

I want to work with draggable marker to collect lat and lang and after marker moving, want to take lat and lng from select using marker. My googlemap react js code is
class GoogleMaps extends Component {
constructor(props) {
super(props);
this.getLangLat = this.getLangLat.bind(this);
}
loadMap = (map, maps) => {
let marker = new maps.Marker({
position: { lat: 40.856795, lng: -73.954298 },
map,
draggable: true
});
};
getLangLat(e) {
//this.lat = e
console.log("Lat",e.lat);
console.log("Lng",e.lng);
this.lat = e.lat
this.lng = e.lng
// this.props.lat = e.lat;
//this.props.lng = e.lng;
}
render() {
return (
<div style={{ height: "400px", width: "400px" }}>
<GoogleMapReact
bootstrapURLKeys={{ key: "xxxxxxx" }}
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={10}
onClick={this.getLangLat}
yesIWantToUseGoogleMapApiInternals
onGoogleApiLoaded={({ map, maps }) => this.loadMap(map, maps)}
/>
</div>
);
}
}
export default GoogleMaps;
My another page, from where is called
import GoogleMaps from './GoogleMaps';
const SignUp = ({ handleChange, newState, alert }) => {
return(
<GoogleMaps></GoogleMaps>
)
}
How can I get lang and lat from draggable marker in google map? In react Js

google map shows random location as center, even when center is specified

I'm using the package google-maps-react to show gmaps in my react app. Everything works fine, except for the fact that the map initially shows a random location as the center, even when I've specified co-ordinates for the center and initial center. How can I fix this so that the map centers on the co-ordinates I've specified initially?
const MapContainer = React.memo((props) => {
const [map, setMap] = useState();
const [center, setCenter] = useState({ lat: 59.913, lng: 10.752 });
var bounds = new props.google.maps.LatLngBounds();
const setMapObj = (mapProps, map) => {
setMap(map);
};
useDeepCompareEffect(() => {
if (props.markers.length === 1) {
setCenter(props.markers[0]);
}
for (var i = 0; i < props.markers.length; i++) {
bounds.extend(
new props.google.maps.LatLng(props.markers[i].lat, props.markers[i].lng)
);
}
if (map) {
map.fitBounds(bounds);
}
}, [props.markers, map]);
return (
<div className={props.className}>
{/* TODO -> Store api key in .env file */}
{console.log(center)}
<Map
google={props.google}
style={{ borderRadius: "10px" }}
center={center}
initialCenter={center}
onReady={setMapObj}
zoom={4}
bounds={bounds}
>
{props.markers.map((item, index) => {
if (item.lat && item.lng)
return (
<Marker key={index} position={{ lat: item.lat, lng: item.lng }} />
);
})}
</Map>
</div>
);
});
Your code is trying to set a center AND fit a particular bounds. The latter will cause the center to change in order to fit all of the markers in the viewport.

How to use vanilla JS with React component (zoom to bounds on load react mapbox gl)

I am looking to be able to zoom to bounds when my component mounts.
I know this vanilla JS code can achieve the zoom to bounds, but not sure how to massage this into the React code below (I think a need a REF?):
var bounds = new mapboxgl.LngLatBounds();
parkDate.features.forEach(function(feature) {
bounds.extend(feature.geometry.coordinates);
});
map.fitBounds(bounds, {
padding: {top: 20, bottom:20, left: 20, right: 20}
})
Component:
import React, { useState } from "react";
import ReactMapGL, { Marker } from "react-map-gl";
import * as parkDate from "./data.json";
const mapIcon: any = require('../images/mapIcon.png');
export default function App() {
const [viewport, setViewport] = useState({
latitude: 45.4211,
longitude: -75.6903,
width: "100%",
height: "400px",
zoom: 10
});
const [selectedPark, setSelectedPark] = useState(null);
return (
<div>
<ReactMapGL
{...viewport}
mapboxApiAccessToken="pk.eyJ1IjoiYmVubmtpbmd5IiwiYSI6ImNrY2ozMnJ5dzBrZ28ycnA1b2Vqb2I0bXgifQ.ZOaVtzsDQOrAovh9Orh13Q"
mapStyle="mapbox://styles/mapbox/streets-v11"
onViewportChange={viewport => {
setViewport(viewport);
}}
>
{parkDate.features.map(park => (
<Marker
key={park.properties.PARK_ID}
latitude={park.geometry.coordinates[1]}
longitude={park.geometry.coordinates[0]}
>
<button
className="marker-btn"
onClick={e => {
e.preventDefault();
setSelectedPark(park);
}}
>
<img src={mapIcon} alt="Map Pointer Icon" />
</button>
</Marker>
))}
</ReactMapGL>
{selectedPark ? (
<div>
<h2>{selectedPark.properties.NAME}</h2>
<p>{selectedPark.properties.DESCRIPTIO}</p>
<button onClick={e => {
e.preventDefault();
setSelectedPark(null);
}}>X</button>
</div>
) : null}
</div>
);
}
Got it working like this:
import React, { useState } from "react";
import ReactMapGL, { Marker, WebMercatorViewport } from "react-map-gl";
import * as parkData from "./data.json";
const mapIcon: any = require('../images/mapIcon.png');
const applyToArray = (func, array) => func.apply(Math, array)
const getBoundsForPoints = (points) => {
console.log('Points:', points)
// Calculate corner values of bounds
const pointsLong = points.map(point => point.geometry.coordinates[0])
const pointsLat = points.map(point => point.geometry.coordinates[1])
const cornersLongLat = [
[applyToArray(Math.min, pointsLong), applyToArray(Math.min, pointsLat)],
[applyToArray(Math.max, pointsLong), applyToArray(Math.max, pointsLat)]
]
// Use WebMercatorViewport to get center longitude/latitude and zoom
const viewport = new WebMercatorViewport({ width: 600, height: 600 })
// #ts-ignore
.fitBounds(cornersLongLat, { padding: {top:150, bottom:200, left:100, right:150} })
const { longitude, latitude, zoom } = viewport
return { longitude, latitude, zoom }
}
const myMap = () => {
const bounds = getBoundsForPoints(parkData.features);
const [viewport, setViewport] = useState({
width: "100%",
height: "600px",
...bounds
});
const [selectedPark, setSelectedPark] = useState(null);
return (
<div>
<ReactMapGL
{...viewport}
mapboxApiAccessToken="pk.eyJ1IjoiYmVubmtpbmd5IiwiYSI6ImNrY2ozMnJ5dzBrZ28ycnA1b2Vqb2I0bXgifQ.ZOaVtzsDQOrAovh9Orh13Q"
mapStyle="mapbox://styles/mapbox/streets-v11"
onViewportChange={viewport => {
setViewport(viewport);
}}
>
{parkData.features.map(park => (
<Marker
key={park.properties.PARK_ID}
latitude={park.geometry.coordinates[1]}
longitude={park.geometry.coordinates[0]}
>
<button
className="marker-btn"
onClick={e => {
e.preventDefault();
setSelectedPark(park);
}}
>
<img src={mapIcon} alt="Map Pointer Icon" />
</button>
</Marker>
))}
</ReactMapGL>
{selectedPark ? (
<div>
<h2>{selectedPark.properties.NAME}</h2>
<p>{selectedPark.properties.DESCRIPTIO}</p>
<button onClick={e => {
e.preventDefault();
setSelectedPark(null);
}}>X</button>
</div>
) : null}
</div>
);
}
export default myMap;

Integrating the google map component with the react HOC?

import React,{Component } from 'react';
import {
withGoogleMap,
GoogleMap,
withScriptjs,
Marker,
InfoWindow,
} from 'react-google-maps';
import {compose, withProps, withStateHandlers} from 'recompose';
import places from 'places.json';
class MapComponent extends Component {
constructor (props) {
super (props);
this.state = {
zoom: 11,
center: {lat: 29.969516, lng: -90.103866},
markers: [],
lat:'',
lng:'',
markersLoaded: false,
};
}
componentDidMount () {
let geocoder = new window.google.maps.Geocoder ();
geocoder.geocode ({address: 'Bakerstreet, 2'}, function (results, status) {
if (status == 'OK') {
this.setState ({
lat: results[0].geometry.location.lat (),
lng: results[0].geometry.location.lng (),
});
} else {
console.log (
'Geocode was not successful for the following reason:',
status
);
}
});
}
render () {
const { lat, lng } = this.state;
const GoogleMapExample = withGoogleMap (props => (
<GoogleMap
defaultZoom={props.zoom}
defaultCenter={props.center}
options={{styles: props.mapdynamic ? darkThemeStyle : lightThemeStyle}}
>
{props.places &&
props.places.map ((place, i) => {
let lat = parseFloat (place.latitude, 10);
let lng = parseFloat (place.longitude, 10);
return (
<Marker
id={place.id}
key={place.id}
position={{lat: lat, lng: lng}}
icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
onMouseOver={props.onToggleOpen.bind (this, i)}
>
{props.infoWindows[i].isOpen &&
<InfoWindow onCloseClick={props.onToggleOpen.bind (i)}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>
));
return (
<div>
<GoogleMapExample
center={{lat: 40.6451594, lng: -74.0850826}}
zoom={10}
places={places} />
</div>
);
}
}
export default compose (
withProps ({
googleMapURL: 'https://maps.googleapis.com/maps/api/js?key=YOUR KEY&libraries=geometry,drawing,places',
loadingElement: <div style={{height: `100%`}} />,
containerElement: (
<div style={{height: '100%', width: '100%', padding: '10px'}} />
),
mapElement: <div style={{height: '100%'}} />,
}),
withStateHandlers (
props => ({
infoWindows: props.places.map (p => {
return {isOpen: false};
}),
}),
{
onToggleOpen: ({infoWindows}) => selectedIndex => ({
infoWindows: infoWindows.map ((iw, i) => {
iw.isOpen = selectedIndex === i;
return iw;
}),
}),
}
),
withScriptjs,
withGoogleMap
) (MapComponent);
I am here by writing the google map component using the react order component.
But when I am trying to run this I am getting some kind of error.
Could you some one take a look into it and let me know what are the
issues here. I am getting following error like Invariant Violation:
Required props containerElement or mapElement is missing. You need to
provide both of them. The google.maps.Map instance will be
initialized on mapElement and it's wrapped by containerElement. You
need to provide both of them since Google Map requires the DOM to have
height when initialized.
Regards
You have additionally used withGoogleMap hoc in render method which you don't need
render () {
const { lat, lng } = this.state;
return (
<GoogleMap
defaultZoom={10}
defaultCenter={{lat: 40.6451594, lng: -74.0850826}}
options={{styles: props.mapdynamic ? darkThemeStyle : lightThemeStyle}}
>
{places &&
places.map ((place, i) => {
let lat = parseFloat (place.latitude, 10);
let lng = parseFloat (place.longitude, 10);
return (
<Marker
id={place.id}
key={place.id}
position={{lat: lat, lng: lng}}
icon="http://maps.google.com/mapfiles/ms/icons/blue-dot.png"
onMouseOver={props.onToggleOpen.bind (this, i)}
>
{props.infoWindows[i].isOpen &&
<InfoWindow onCloseClick={props.onToggleOpen.bind (i)}>
<div>{place.name}</div>
</InfoWindow>}
</Marker>
);
})}
</GoogleMap>
);
}

Resources