I am integrating/including react-leaflet-editable to my existing project which relies 100% on react-leaflet v2.8.0. I am not able to upgrade at the moment as it requires too much changes to the entire project. Something we cannot afford at the moment. (Why change everything for one when one can change for all. Yes we will probably do this someday but not now)
so here is the code below. it works perfectly with react-leaflet v.3.x but the moment I siwtch to `version 2.8.0' it seizes to work.
What I have tried; Map is renamed to MapContainer in 3.x so I change that but the problem then becomes the whenCreated={setMap} parameter. I need a way to get that linked to the ReactLeafletEditable. or at least I think that is the problem.
I hope I have explained well. the code and link is below.
import React, { useRef } from "react";
import L, { Icon } from "leaflet";
import "leaflet-editable";
import ReactLeafletEditable from "react-leaflet-editable";
import {
MapContainer,
TileLayer,
LayersControl,
LayerGroup
} from "react-leaflet";
import "leaflet/dist/leaflet.css";
function Demo() {
const editRef = useRef();
const [map, setMap] = React.useState();
const editPolygon = () => {
editRef.current.startPolygon();
};
return (
<ReactLeafletEditable ref={editRef} map={map}>
<button onClick={editPolygon} className="editable-btn">
Create Polygon
</button>
<MapContainer
style={{
height: "700px",
backgroundColor: "",
flexGrow: "1",
cursor: `10`
}}
editable={true}
zoom={4}
maxZoom={18}
center={[35, 105]}
whenCreated={setMap}
>
<LayerGroup>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<TileLayer url="http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" />
</LayerGroup>
</MapContainer>
</ReactLeafletEditable>
);
}
export default Demo;
Link to project in 3.0: https://codesandbox.io/s/react-leaflet-editable-z7tnq?file=/src/App.js
link to react-leaflet-editable : https://www.npmjs.com/package/react-leaflet-editable
PS: You can just switch the react-leaflet version on the side to 2.8.0 see the behavior.
Thank you for all support
Use a ref in combination with a useEffect to get the map instance in react-leaflet v.2.x. With that way you imitate what whenCreated does in version 3.x
const [map, setMap] = React.useState();
const mapRef = useRef();
useEffect(() => {
if (!mapRef.current) return;
setMap(mapRef.current.leafletElement);
}, []);
<ReactLeafletEditable ref={editRef} map={map}>
<button onClick={editPolygon} className="editable-btn">
Create Polygon
</button>
<Map
style={{
height: "700px",
backgroundColor: "",
flexGrow: "1",
cursor: `10`
}}
ref={mapRef}
...
Demo
Related
I want to add more than one tilelayers to mapcontainer. I am not able to accomplish that. I have one tilelayer like this
const magnifiedTiles = L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")
and another one here:
export default function App(): JSX.Element {
return (
<>
<MapContainer center={center} zoom={13} scrollWheelZoom={true} style={{height: 'calc(100% - 30px)'}}>
<TileLayer
attribution='© OpenStreetMap contributors'
url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
/>
</>)
}
I can either get a map reference from map container and use like magnifiedTiles.addTo(<map>)but I dont know how to get the map reference. Other option is addLayer(). However, I am not able to access it with from L.Tilelayer.
I know it leaflet it was as simple as getting map reference and using map.addLayer().
You can easily get the map reference via a ref in react-leaflet v.4.x
const [map, setMap] = useState(null)
<MapContainer
center={center}
zoom={zoom}
scrollWheelZoom={false}
ref={setMap}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
and then use a useEffect to add any layer you want.
useEffect(()=> {
if (!map) return ;
map.addLayer(...);
},[])
Edit after you added the typescript tag:
Same as before only thing that changes you should install #types/react-leaflet and declare the map ref type.
import { Map as MapProp, tileLayer } from "leaflet";
...
const streets = tileLayer(
"https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}",
{
attribution:
'OpenStreetMap, CC-BY-SA, Mapbox',
maxZoom: 18,
id: "mapbox/streets-v11",
tileSize: 512,
zoomOffset: -1,
accessToken:
...
}
);
Source for streets layer that includes token
const [map, setMap] = useState<MapProp | null>(null);
...
useEffect(() => {
if (!map) return;
map.addLayer(streets);
}, [map]);
Demo
I am trying to make a choropleth map of the world but with city level detail where a region of world or country explored by a user gets a color.
So far I am able to find solutions to create a world map with country level shapes or polygons in geojson. This is what I currently have.
What I wish to achieve is when I zoom in should be able to see similar output but with city or state or province level details.
What I have is has been built using react-leaflet and geojson file that contains boundaries of all the countries in the world.
I've been looking all over the internet for city level geojson or a map library that can help me but no luck so far. Here is the code
import { MapContainer, Marker, GeoJSON, useMap, TileLayer } from 'react-leaflet';
import React, { useRef, useEffect, useState, useLayoutEffect } from 'react';
import mapData from './test.json';
const imagePin = '/images/map-pin.png';
import L from 'leaflet';
import LayersSelector from 'components/atoms/LeafletMap/LayersSelector';
import LeafletMapUtils from './logic';
import { MapView } from './types';
type IProps = {
pins: any;
center?: [number, number];
zoom?: number;
};
const Map = ({
pins = [],
center = [0.9137839459007647, 1.3199101440788825],
zoom = 2.3
}: IProps) => {
const mapRef = useRef();
const [mapView, setMapView] = useState(MapView.SATELLITE);
return (
<div className="h-full w-full">
<MapContainer
ref={mapRef}
center={[0.9137839459007647, 1.3199101440788825]}
zoom={zoom}
zoomSnap={0.1}
zoomControl={false}
// className={styles.leafletContainer}
scrollWheelZoom={true}
style={{ height: '100%', width: '100%' }}
// maxBounds={bounds}
// crs={L.CRS.Simple}
>
{mapView === MapView.JINNI && (
<GeoJSON
style={{
fillColor: '#EBEBEB',
fillOpacity: 1,
// color: '#717171',
weight: 0.5,
stroke: true,
color: '#000000'
// border: '1px solid #dddd'
}}
onEachFeature={(country, layer) =>
LeafletMapUtils.onEachCountry(country, layer)
}
// eslint-disable-next-line #typescript-eslint/ban-ts-comment
// #ts-ignore
data={mapData}
/>
)}
</MapContainer>
</div>
);
};
export default Map;
I found a Geojson file on the internet with polygons on all countries: https://datahub.io/core/geo-countries. I use Leaflet.js:
geojsondata = ... // the geojson data
readfromjson = L.geoJSON(geojsondata).addTo(map)
I am trying to create a minimap but for some reason, react-leaflet renders the map twice.
I think its the container is not big enough to contain the map so it translates it out but I don't get how big it's supposed to be.
The documentation doesn't really mention this.
import React from 'react';
import { MapContainer, TileLayer } from 'react-leaflet';
const MapStyle = {
height: '100px',
width: '100px',
};
const MiniMap = assetLocation => {
return (
<MapContainer center={[45.4, -75.7]} zoom={13} scrollWheelZoom={false} style={MapStyle}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
</MapContainer>
);
};
I implement it inside Antd's grid system
<Row>
<Space>
<Col>
<MiniMap assetLocation={item} />
<NavButtons id={id} />
</Col>
<Col>{ ...otherComponents }</Col>
</Space>
I was missing the Leaflet's CSS.
Just need to import it into the react component:
import 'leaflet/dist/leaflet.css';
import ReactMapboxGl, { Marker } from "react-mapbox-gl";
import React from "react";
const Map = ReactMapboxGl({
accessToken: process.env.REACT_APP_MAPBOX_TOKEN,
});
export default function App() {
return (
<Map
style="mapbox://styles/mapbox/streets-v9"
containerStyle={{
height: "100vh",
width: "100vw",
}}
center={[-74.006, 40.7128]}
>
<Marker coordinates={[-74.006, 40.7128]}>
<div>IAM HEEEEEEEEEEEEEEEEERE</div>
</Marker>
</Map>
);
}
This is a basic map showing using mapbox-react-gl.
There is no bug showing in console log but I can not see the marker on the map.
I think you didn't set the coordinates correctly (latitude, longitude)
They should be, based in your example [40.7128 -74.006]
Why I am getting:
./src/components/mapComponent/MapView.jsx
Attempted import error: 'Map' is not exported from 'react-leaflet'.
I am importing this in the component:
import React, { Component } from "react";
import { Map, TileLayer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
This is confusing me where to look as all looks to be correct in code....
Try with MapContainer component.
The MapContainer component is responsible for creating the Leaflet Map
instance and providing it to its child components, using a React
Context.
When creating a MapContainer element, its props are used as options to
create the Map instance.
Now you have to import MapContainer.
import { MapContainer, TileLayer, Marker } from 'react-leaflet';
<MapContainer
className="markercluster-map"
center={[51.0, 19.0]}
zoom={4}
maxZoom={18}
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='© OpenStreetMap contributors'
/>
</MapContainer>
Change Map to MapContainer.
import { MapContainer, TileLayer } from "react-leaflet";
This problem is occurring in the older version try using "react-leaflet": "^3.2.1", "leaflet": "^1.7.1", and it would resolve, if you are using react 17 and upper .
https://codesandbox.io/s/cluster-mapping-leaflet-9bkes
import { TileLayer, Tooltip, Marker, MapContainer } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import MarkerClusterGroup from "react-leaflet-markercluster";
import { customMarker } from "./constants";
import L from "leaflet";
const Cluster = () => {
let data = {
minLat: -6.1751,
maxLat: 55.7558,
minLong: 37.6173,
maxLong: 139.6917
};
const centerLat = (data.minLat + data.maxLat) / 2;
var distanceLat = data.maxLat - data.minLat;
var bufferLat = distanceLat * 0.05;
const centerLong = (data.minLong + data.maxLong) / 2;
var distanceLong = data.maxLong - data.minLong;
var bufferLong = distanceLong * 0.05;
const zoom = 4;
const cities = [
{ position: [22.583261, 88.412796], text: "A" },
{ position: [22.58289, 88.41366], text: "B" }
];
return (
<MapContainer
style={{ height: "480px", width: "100%" }}
zoom={zoom}
center={[centerLat, centerLong]}
bounds={[
[data.minLat - bufferLat, data.minLong - bufferLong],
[data.maxLat + bufferLat, data.maxLong + bufferLong]
]}
scrollWheelZoom={true}
>
<TileLayer url="http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
<MarkerClusterGroup>
{cities?.map((mark, i) => (
<Marker
style={{ color: "red" }}
key={i}
position={mark?.position}
icon={customMarker}
>
<Tooltip direction="top" offset={[10, 0]}>
<span style={{ fontSize: 14, fontWeight: "bold" }}>
{mark?.text}
</span>
</Tooltip>
</Marker>
))}
</MarkerClusterGroup>
</MapContainer>
);
};
export default Cluster;
export const customMarker = new L.Icon({
iconUrl: "https://unpkg.com/leaflet#1.5.1/dist/images/marker-icon.png",
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40]
});
You should use import {MapContainer} from "react-leaflet" instead of Map and before doing that install both react-leaflet and leaflet by
$ npm i leaflet react-leaflet
Hope this solve your problem
This problem is occurring in the newer version try using "react-leaflet": "^2.8.0","leaflet": "^1.7.1"and it would resolve