I have been using react leaflet succesful with Int/Float coordinates like [51.505, -0.09]
however, i have longitude and Latitude indicator included on my coordinates like ['51.505W', '-0.09S'].
First options runs well with this code.
const position = [51.505, -0.09]
render(
<MapContainer center={position} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={position}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>
)
Thie second options breaks with error Invalid LatLng object How best can i handle this
Leaflet, and by extension react-leaflet, expects latitude longitude to simple numbers, either in the form of an array of 2 numbers [number, number], or an object in the format { lat: number, lng: number }. Coordinates like ['51.505W', '-0.09S'] don't fit that pattern. But they can be easily transformed with a simple function that strips the letter character from the string and returns a number:
function transformCoords(pair) {
return pair.map(coordString => {
return Number(
coordString
.replace('N', '')
.replace('S', '')
.replace('E', '')
.replace('W', '')
)
})
}
This will take in an array of the format ['51.505W', '-0.09S'] and will return an array like [51.505, -0.09], which can then be properly fed to a Marker position prop:
const position = ['51.505W', '-0.09S']
render(
<MapContainer ...>
<Marker position={transformCoords(position}) />
</MapContainer>
)
Related
Invalid LatLng object: (NaN, NaN) appears with react-leaflet, and comes from leaflet itself, as it seems to come from the core library, even if coordinates are actually valid.
Code:
const plottedPoints: LatLong[] = [
[29.69937, -95.32803],
[30, 30],
[29.69937, -95.32803]
]
const polylineTraveledOptions: PathOptions = {lineCap: 'square', lineJoin: 'miter', color: blue50, weight: 4}
return(
<div id="map" style={{height: '400px', width: '555px'}}>
<MapContainer
// Won't let the user zoom out too much and see outside the world's layout
zoomSnap={0.5}
zoomDelta={0.5}
// We have a custom positioned zoom control
zoomControl={false}
scrollWheelZoom={false}
// Fixes the map's drag to its bounds
maxBoundsViscosity={1}
style={{height: '100%', width: '100%'}}>
<TileLayer
attribution='© Stadia Maps, © OpenMapTiles © OpenStreetMap contributors'
url="https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png"
/>
<ZoomControl position="bottomright" />
<Polyline pathOptions={polylineTraveledOptions} positions={plottedPoints} />
</MapContainer>
</div>
)
I'm also setting the mapBounds:
const map = useMap()
// Zooms in the correct size for the polyline we've set
const mapBounds = [[29.69937, -95.32803], [29.69937, -95.32803]]
map.fitBounds(mapBounds, {padding: [30, 30]})
// Won't let the user zoom to a world's map that's duplicated
map.setMinZoom(2)
// Won't let the user drag outside of the world's map
map.setMaxBounds([
[-90, -300],
[90, 300],
])
May it because it doesn't support overlapping of vectors on Polylines, as two of the coords are on the same location?
Or is it because the mapBounds() function would be on the same point, instead of something that can be calculated as a square?
Or else...?
There's also not much out there on how to fix it, a part of this link: https://github.com/IvanSanchez/Leaflet.Polyline.SnakeAnim/issues/29 which is about the snake animation - and I don't think it's related.
Please, enlighten me.
My marker is currently draggable with event listener of dragend. I'm able to get that specific point's lag and long, but I want to get the north, south, east and west coordinates.
Im thinking getBound() is what I need but I don't know how to call it in functional React.
Any help much appreciated.
import React from 'react';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet'
import "./Map.css"
function Map({children}) {
return (
<>
{children}
<MapContainer center={[40.678177, -73.944160]} zoom={13} scrollWheelZoom={false}>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker
eventHandlers={{
dragend : (e)=>{
console.log(e)}
}}
draggable={true}
position={[40.678177, -73.944160]}
>
<Popup>
test
</Popup>
</Marker>
</MapContainer>
</>
)
};
export default Map;
A latlng point doesn't have a bounds. But you can use leaflet-geometryutil's destination function to get points at a certain distance to the north, south, east, and west:
import L from 'leaflet';
import 'leaflet-geometryutil';
const distance = 100 // in meters
// within your component:
eventHandlers={{
dragend : (e) => {
const n = L.GeometryUtil.destination(e.latlng, 0, distance)
const s = L.GeometryUtil.destination(e.latlng, 180, distance)
const e = L.GeometryUtil.destination(e.latlng, 90, distance)
const w = L.GeometryUtil.destination(e.latlng, 270, distance)
}}
Now you have points directly north, south, east, and west, exactly distance meters from where the dragend event happens.
I am using react-leaflet and rc-tabs and while selecting different row in a table I want to display appropriate marker. I want to draw a line from a row to a certain marker when hover with the help of react-lineto, which accepts only classNames as points (well, coordinates too, but this is not suitable for me) so I need an individual class of a marker, a class that can determine a marker on map.
How can I achieve that?
It seems there is no className attribute for every marker, just for group of markers...
okey, after a day spent here I made an marker's icon classnames unique and after that draw a line between my table's hovered row and marker on the map.
return (
<LeafMap center={[deviceCoordinatesLat, deviceCoordinatesLong]} zoom={14} style={{height: "90vh"}}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution="© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors"
/>
{props.devices.map(device => (
<Marker
className={device.serial}
key={device.id}
position={[degreesToCoord(device.coordinates)[0], degreesToCoord(device.coordinates)[1]]}
icon={hoveredItem.id === device.id ?
markerBigBlue :
new L.Icon({
iconUrl: require('../little-blue-dot.png'),
iconSize: new L.Point(15, 15),
className: "little-blue-dot-" + device.id
})
}
>
{hoveredItem.id === device.id ?
<LineTo
*from={"leaflet-marker-icon little-blue-dot-" + device.id + " leaflet-zoom-animated leaflet-interactive"}*
to={"invisible-blue-dot-" + device.id}
borderWidth={1}
zIndex={100}
borderColor="#0C86B8"
/>
: <div></div>}
<Popup>
<span>{device.model} {device.serial}</span>
</Popup>}
</Marker>
))}
</LeafMap>
)
I am using react-leaflet, and can get a market to appear. The is just not working.
I've simply copied the example code. Could there be conflicts with other packages? Or do I need particular versions of leaflet, react and react-dom for this to work?
My cursor doesn't change on mouseover the map.
I have made sure I have the correct css so the map and marker render correctly.
Any help would be greatly appreciated, I am fairly new at this, so it is likely a silly error.
import React from 'react';
import ReactDOM from 'react-dom';
import { Map, TileLayer, Marker, Popup } from 'react-leaflet';
class SimpleExample extends React.Component {
constructor() {
super();
this.state = {
lat: 51.505,
lng: -0.09,
zoom: 13,
};
}
render() {
const position = [this.state.lat, this.state.lng]
return (
<Map center={position} zoom={this.state.zoom}>
<TileLayer
attribution='© OpenStreetMap contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
/>
<Marker position={position}>
<Popup>
<span>A CSS3 popup. <br /> Easily customizable.</span>
</Popup>
</Marker>
</Map>
);
}
}
ReactDOM.render(<SimpleExample />, document.getElementById('root'));
Check your index file and see if the css file/js file for leaflet are for version 0.7.7 or 1.0. If it is on 1.0, replace them with:
https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css
https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js
We need to disable duplicated world maps at the left and right side of the main world map, which is showing by default.
Problem is that we need exact zoom level there and sometimes leaflet showing duplicates...
Is it possible to remove duplicates at all?
You will disable the noWrap property of your TiledLayer (which extends GridLayer). Documentation here
var layer = new L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
noWrap: true
});
If you use react-leafet you can set this prop in TileLayer component:
<MapContainer
center={{ lat: 51.505, lng: -0.09 }}
zoom={5}
style={mapStyle}
scrollWheelZoom={true}
>
<TileLayer
noWrap={true}
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>