The project concept is to get geolocation and showing Mapbox map using API...
import ReactDOM from "react-dom";
import React, { useRef, useEffect } from "react";
import { geolocated } from "react-geolocated";
import mapboxgl from "mapbox-gl";
import fetchFakeData from "./api/fetchFakeData";
import Popup from "./components/Popup";
import "./App.css";
mapboxgl.accessToken ="pk.eyJ1IjoiamFja3Nvbi1rYXNpIiwiYSI6ImNrbzdsaDJvNTFvc3Eycm9pdTRxYmRxZjUifQ.BzA0w0U7lP0Ka3FcKkI_1Q";
const App = (props) => {
const mapContainerRef = useRef(null);
const popUpRef = useRef(new mapboxgl.Popup({ offset: 15 }));
// initialize map when component mounts
useEffect(() => {
const map = new mapboxgl.Map({
container: mapContainerRef.current,
// See style options here: https://docs.mapbox.com/api/maps/#styles
style: "mapbox://styles/mapbox/streets-v11",
center: [props.lat, props.long],
zoom: 12.5
});
// add navigation control (zoom buttons)
map.addControl(new mapboxgl.NavigationControl(), "bottom-right");
map.on("load", () => {
// add the data source for new a feature collection with no features
map.addSource("random-points-data", {
type: "geojson",
data: {
type: "FeatureCollection",
features: []
}
});
// now add the layer, and reference the data source above by name
map.addLayer({
id: "random-points-layer",
source: "random-points-data",
type: "symbol",
layout: {
// full list of icons here: https://labs.mapbox.com/maki-icons
"icon-image": "bakery-15", // this will put little croissants on our map
"icon-padding": 0,
"icon-allow-overlap": true
}
});
});
map.on("moveend", async () => {
// get new center coordinates
const { lng, lat } = map.getCenter();
// fetch new data
const results = await fetchFakeData({ longitude: lng, latitude: lat });
// update "random-points-data" source with new data
// all layers that consume the "random-points-data" data source will be updated automatically
map.getSource("random-points-data").setData(results);
});
// change cursor to pointer when user hovers over a clickable feature
map.on("mouseenter", "random-points-layer", (e) => {
if (e.features.length) {
map.getCanvas().style.cursor = "pointer";
}
});
// reset cursor to default when user is no longer hovering over a clickable feature
map.on("mouseleave", "random-points-layer", () => {
map.getCanvas().style.cursor = "";
});
// add popup when user clicks a point
map.on("click", "random-points-layer", (e) => {
if (e.features.length) {
const feature = e.features[0];
// create popup node
const popupNode = document.createElement("div");
ReactDOM.render(<Popup feature={feature} />, popupNode);
// set popup on map
popUpRef.current
.setLngLat(feature.geometry.coordinates)
.setDOMContent(popupNode)
.addTo(map);
}
});
// clean up on unmount
return () => map.remove();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return <div className="map-container" ref={mapContainerRef} />
};
export default geolocated({
positionOptions: {
enableHighAccuracy: false
},
userDecisionTimeout: 5000
})(App);
class Gps extends React.Component {
constructor() {
super();
this.state = {
latitude: "",
longitude: ""
};
this.getMyLocation = this.getMyLocation.bind(this);
}
componentDidMount() {
this.getMyLocation();
}
getMyLocation() {
const location = window.navigator && window.navigator.geolocation;
if (location) {
location.getCurrentPosition(
(position) => {
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude
});
},
(error) => {
this.setState({
latitude: "err-latitude",
longitude: "err-longitude"
});
}
);
}}
render() {
const { latitude, longitude } = this.state;
return (
<div>
<App lat={latitude} long={longitude} />
</div>
);
}
}
please see this link "codesandbox" : https://codesandbox.io/s/determined-river-7dt0h?file=/src/App.js
props didn't work.
see this lines:
center: [props.lat, props.long]
<App lat={latitude} long={longitude} / >
screenshot
The Problem
The Lat and Lng were initialized to an empty string, but the center property is expecting an array of numbers.
Solution
In Gps component, initialize the lat and long state values to a number as opposed to an empty string
this.state = {
latitude: 38.8951,
longitude: -77.0364
};
In my case, I was using it for web and the issue was causing because of the height of the div in which I was rendering map component. When I set the minHeight for that div, it worked fine for me.
Related
I have a component in my react application that uses maps but the map is not loading how can I solve this problem
import React, { useEffect, useMemo } from 'react';
import { MarkerClusterer } from '#googlemaps/markerclusterer';
const Map = () => {
const locations = useMemo(
() => [
{ lat: -31.56391, lng: 147.154312 },
{ lat: -33.718234, lng: 150.363181 },
{ lat: -33.727111, lng: 150.371124 },
],
[],
);
useEffect(() => {
const script = document.createElement('script');
script.src = `https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_API_KEY}`;
script.async = true;
script.defer = true;
document.body.appendChild(script);
script.onload = () => {
if (typeof window.google !== 'undefined' && window.google.maps) {
const map = new window.google.maps.Map(document.getElementById('map'), {
zoom: 3,
center: { lat: -28.024, lng: 140.887 },
});
const infoWindow = new window.google.maps.InfoWindow({
content: '',
disableAutoPan: true,
});
// Create an array of alphabetical characters used to label the markers.
const labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
// Add some markers to the map.
const markers = locations.map((position, i) => {
const label = labels[i % labels.length];
const marker = new window.google.maps.Marker({
position,
label,
});
// markers can only be keyboard focusable when they have click listeners
// open info window when marker is clicked
marker.addListener('click', () => {
infoWindow.setContent(label);
infoWindow.open(map, marker);
});
return marker;
});
// Add a marker clusterer to manage the markers.
MarkerClusterer.factory({ markers, map });
}
};
}, [locations]);
return <div id='map' />;
};
export default Map;
this is my build i want to collect markers with cluster but i fail
enter image description here
in console i see these errors
![Topluluk Tarafından Doğrulandı simgesi](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAQAAAAngNWGAAABDUlEQVR4AYXRgUZDYRjH4TegFTKgpEqiFJgoWAoMEQGBgBboChaaAKxLKAhAhQqAdAmpBIQolkCFqp2nITvNKXuA7+/Hhzey5OWjE4Nq3rzY1f9/NGHPB549492+8Ww060iCS2XdctZdI3GsECmb+HJoIX6x6EgDm+lURTH+YB7V9nAqE5WNme4YKuOiY6iMe6PaQxUUIuTbswgFVNJwA8sO3Bn6yR6bWZMSNtJwDtuWfHpQxaPx9C9zadil7jrCigbq6UXceNIVKTWUIqypm2ytJdTiNyNeXclF6GttOVfeDEc7qzjR23r3OMFqZKng1kw0mXGLrfibHTScOZWgGv9TdC6ROFeMTgwYiIxvJzMRWQbeGZUAAAAASUVORK5CYII=)
I want the markers to appear in clusters on the map, but even the map does not appear
I am just exploring Mapmyindia.
I have gone through the basic location display on the map.
I am not getting how to display polyline on map.
code for location
app.js
import "./App.css";
import SideBar from "./componants/SideBar";
import Map from "mapmyindia-react";
// import MapmyIndia, { MapMarker } from "react-mapmyindia";
function App() {
return (
<div className="App">
Hello
<Map
markers={[
{
position: [21.1588329, 72.7688111],
draggable: true,
zoom: 15,
title: "Marker title",
onClick: (e) => {
console.log("clicked ");
},
onDragend: (e) => {
console.log("dragged");
},
onMouseover: (e) => {
console.log("Mouse over");
},
},
]}
/>
{/* <Map /> */}
<SideBar></SideBar>
</div>
);
}
export default App;
Which result this
Now, Please help with drawing polyline.
I guess you're using the npm package for maps. If you go through the library's code in gitHub, you can see the owner has only added marker functionality. You can simply copy the code from there and add it manually to your project and then add the polyline functionality and then pass the data as props from your app.js file like you're doing for markers.
renderPolylines = () => {
const { polylines = [] } = this.props;
if (!this.map) {
return;
}
polylines.map(m => {
if (m?.position && Array.isArray(m.position)) {
const { position, color, weight, opacity } = m;
let points = [];
position.map(p => {
const { lat, lng } = p;
const center = new L.LatLng(lat, lng);
points.push(
new L.LatLng(center.lat, center.lng))/*array of wgs points*/
})
const polyline = new L.Polyline(points, { color, weight, opacity });
this.map.addLayer(polyline);
this.polylines.push(polyline);
}
});
};
Props for rendering polyline from app.js
polylines = {[
{
position: [
{
lat: 18.5014,
lng: 73.805,
},
{
lat: 18.5414,
lng: 73.855,
},
{
lat: 18.5514,
lng: 73.855,
},
{
lat: 18.5614,
lng: 73.855,
},
],
color: "red",
weight: 4,
opacity: 0.5,
},
]}
I have created this component for dispay a marker when i search a city, but when i create a new search a new marker as added but the previous as not deleted. Have you an idea for resolve this problem ?
import { useState, useEffect } from "react";
import { useMap } from "react-leaflet";
import "leaflet-control-geocoder/dist/Control.Geocoder.js";
import L from "leaflet";
import icon from "./../constants/homeIcon";
import { PrintAddress } from "../components/Map/styles";
const SearchBar = () => {
const map = useMap();
let [printInfo, setPrintinfo] = useState("");
useEffect(() => {
let geocoder = L.Control.Geocoder.nominatim({
geocodingQueryParams: {
limit: 3,
addressdetails: 1,
namedetails: 1,
countrycodes: "fr",
},
});
L.Control.geocoder({
query: "",
placeholder: "Search your address",
defaultMarkGeocode: false,
geocoder,
})
.on("markgeocode", function (e) {
let latlng = e.geocode.center;
L.marker(latlng, { icon })
.bindPopup(e.geocode.name)
.openPopup()
.addTo(map);
map.panTo(latlng);
L.circle(latlng, {
color: "#000",
fillColor: "#7AEDAD",
radius: 10000,
}).addTo(map);
setPrintinfo(e.geocode.name);
})
.addTo(map);
}, [map]);
return <PrintAddress className="printInfo">{printInfo}</PrintAddress>;
};
export default SearchBar;
use a layerGroup outside the component to store the circle and the marker and every time you add a new marker clear the layer Group and add the new to be able to delete it the next time you add another marker.
const layerGroup = L.layerGroup(); // init the empty layerGroup
const SearchBar = () => {
const map = useMap();
...
L.Control.geocoder({
query: '',
placeholder: 'Search your address',
defaultMarkGeocode: false,
geocoder
})
.on('markgeocode', function (e) {
layerGroup.clearLayers(); // lear the layerGroup from previous stored circle and marker
let latlng = e.geocode.center;
L.marker(latlng, { icon })
.bindPopup(e.geocode.name)
.openPopup()
.addTo(layerGroup); // add the marker to the layerGroup
map.panTo(latlng);
L.circle(latlng, {
color: '#000',
fillColor: '#7AEDAD',
radius: 10000
}).addTo(layerGroup); // add the circle to th elayerGroup
setPrintinfo(e.geocode.name);
map.addLayer(layerGroup); // here add the layerGroup to th emap
})
.addTo(map);
}, [map]);
Demo
I'm trying to move some markers around the map but after update the array which contains the info about the coordinates of them nothing happens, it's just blinking but not moving.
BusMarker.js (Customer Marker)
import React, { useState, useEffect } from 'react'
import { Marker } from 'react-native-maps'
const BusMarker = props => {
const { longitude, latitude, plate } = props
const [coordinates] = useState({
longitude: Number(longitude),
latitude: Number(latitude)
})
return (
<Marker
key={`bus-${plate}-${new Date().getMilliseconds()}`}
coordinate={coordinates}
image={require('../../img/icon/bus-icon.png')}>
</Marker>
)
}
export default BusMarker
Map.js
import React, { useState, useEffect, Fragment, useCallback, useRef } from 'react'
import { StyleSheet, View, Text } from 'react-native'
import { useSelector, useDispatch } from 'react-redux'
import MapView, { PROVIDER_GOOGLE} from 'react-native-maps'
import BusMarker from './BusMarker'
import { useFocusEffect } from 'react-navigation-hooks'
const Maps = () => {
const [busLocation, setBusLocation] = useState([
{
"plate": "CAR1203",
"latitude": 0,
"longitude": 0,
},
])
const [region] = useState({
latitude: 0,
longitude: 0,
latitudeDelta: 0.0143,
longitudeDelta: 0.0134,
})
const _renderBusesOnMap = busLocation => {
if (busLocation.length > 0) {
return busLocation.map(({ plate, longitude, latitude }) => {
return (
<BusMarker key={plate} plate={plate} longitude={longitude} latitude={latitude} />
)
})
}
}
const updateLocations = () => {
const newPosition = [
{
"plate": "CAR1203",
"latitude": 0,
"longitude": 1,
},
]
const timeout = setInterval(() => {
setBusLocation(newPosition)
}, 1000)
}
useEffect(updateLocations, [])
return (
<MapView
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={region}
showsCompass={false}
showsTraffic={false}
showsIndoors={false}
showsBuildings={false}
showsPointsOfInterest={false}
loadingEnabled={false}
>
{_renderBusesOnMap(busLocation)}
</MapView>
)
}
const styles = StyleSheet.create({
map: {
flex: 1,
backgroundColor: '#ffff',
height: '100%'
},
})
export default Maps
Why is it not updating its location on the map?
I'm using the following versions on this project:
React Native: 0.60.5
React Native Maps: 0.25.0
Try this instead:
const BusMarker = props => {
const { longitude, latitude, plate } = props;
const coordinates = {
longitude: Number(longitude),
latitude: Number(latitude)
};
return (
<Marker
key={`bus-${plate}-${new Date().getMilliseconds()}`}
coordinate={coordinates}
/>
);
};
const Maps = () => {
const [busLocation, setBusLocation] = useState([
{
plate: "CAR1203",
latitude: 37.78825,
longitude: -122.4324
}
]);
const [region] = useState({
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
});
const _renderBusesOnMap = busLocation => {
if (busLocation.length > 0) {
return busLocation.map(({ plate, longitude, latitude }) => {
return (
<BusMarker
key={plate}
plate={plate}
longitude={longitude}
latitude={latitude}
/>
);
});
}
};
const updateLocations = () => {
const newPosition = [
{
plate: "CAR1203",
latitude: 37.78845,
longitude: -122.4424
}
];
const timeout = setInterval(() => {
setBusLocation(newPosition);
}, 1000);
};
useEffect(updateLocations, []);
return (
<MapView
provider={PROVIDER_GOOGLE}
style={styles.map}
initialRegion={region}
showsCompass={false}
showsTraffic={false}
showsIndoors={false}
showsBuildings={false}
showsPointsOfInterest={false}
loadingEnabled={false}
>
{_renderBusesOnMap(busLocation)}
</MapView>
);
};
The main problem I think is the way you set coordinates inside BusMarker. There is no need to use useState there. You can just set coordinates as an object with the latitude and longitude values you receive from props.
I've adjusted the coordinates to make it easier to test.
Update
I will try to add to this answer, by explaining my understanding of the behavior. I will explain by giving a more general example. So let's say you have code like this:
const Component = props => {
const [data, setData] = useState(props);
// ...
Now props will be set as the initial value of data.
But useState won't update on props change this way. So even though the props have changed, data still holds the value it was initially passed. To tell data to update on props change you could use useEffect inside Component:
useEffect(() => {
setData(props);
}, [props]);
But like I said in my original answer, there is no reason to use useState in this situation. We don't need to keep Component's state in sync with the parent props as we can simply use props directly. So don't use the useEffect approach I've given as it's unnecessary, it's just to give an example.
I'm trying to adapt this example from https://github.com/mapbox/mapbox-react-examples/tree/master/basic,
import React from 'react'
import ReactDOM from 'react-dom'
import mapboxgl from 'mapbox-gl'
mapboxgl.accessToken = 'pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4M29iazA2Z2gycXA4N2pmbDZmangifQ.-g_vE53SD2WrJ6tFX7QHmA';
class Application extends React.Component {
constructor(props: Props) {
super(props);
this.state = {
lng: 5,
lat: 34,
zoom: 1.5
};
}
componentDidMount() {
const { lng, lat, zoom } = this.state;
const map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/streets-v9',
center: [lng, lat],
zoom
});
map.on('move', () => {
const { lng, lat } = map.getCenter();
this.setState({
lng: lng.toFixed(4),
lat: lat.toFixed(4),
zoom: map.getZoom().toFixed(2)
});
});
}
render() {
const { lng, lat, zoom } = this.state;
return (
<div>
<div className="inline-block absolute top left mt12 ml12 bg-darken75 color-white z1 py6 px12 round-full txt-s txt-bold">
<div>{`Longitude: ${lng} Latitude: ${lat} Zoom: ${zoom}`}</div>
</div>
<div ref={el => this.mapContainer = el} className="absolute top right left bottom" />
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById('app'));
to a case in which, rather than displaying the map's center, I would like to display the latitude and longitude of the mouse position.
So far, I've managed to simply log it to the console:
import React from 'react';
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = 'pk.eyJ1Ijoia3VydHBlZWsiLCJhIjoiY2p6cnVneWdvMHlzeDNqcWo0dm83ZzZ2eiJ9.yUCSreTRcKs12uT5PTCztg';
export default class Map extends React.Component {
componentDidMount() {
this.map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/outdoors-v11',
center: [-119.5591, 37.715],
zoom: 9
});
this.map.on('load', function(e) {
e.target.on('mousemove', function(e) {
console.log(JSON.stringify(e.point));
console.log(JSON.stringify(e.lngLat.wrap()));
});
});
}
componentWillUnmount() {
this.map.remove();
}
render() {
const style = {
position: 'absolute',
top: 0,
bottom: 0,
width: '100%'
};
return <div style={style} ref={el => this.mapContainer = el} />;
}
}
This writes lines like the following to the console:
{"x":972,"y":272}
{"lng":-118.90266689452113,"lat":37.86205552587528}
However, rather than logging the coordinates to the console, I would like to invoke this.setState() like in the example so that I can render the coordinates in a child component.
The problem is, within the on('mousemove', ...) callback function, this is not the component. I've read about using arrow functions (which are lexically scoped) to work around this, but it seems to me that in this case, I need a 'normal' function(e) in order to capture the event.
How can I setState() with the mouse coordinates in this example?
It's possible to use arrow functions just like any other function
this.map.on('load', e => {
e.target.on('mousemove', e => {
this.setState({}) //correct this
})
})