不在 App.js 中时,React 传单地图位置会出现故障
React leaflet map location glitches when not in App.js
我正在尝试在我的 React 应用程序中使用 Leaflet 地图,但我 运行 遇到了一个奇怪的问题。我告诉我的地图在 whenReady 函数中平移到用户的当前地理位置(如果他们允许访问他们的位置),但是当它这样做时,地图会出现故障。是什么让这个怪异的是它只发生在我将我的地图放在我从 App.js 路由到的视图中(我想将它与导航栏一起显示)。当它位于 App.js 本身时,这不会发生并且地图会正确显示我的位置。我附上图片来说明我的意思:
当地图位于App.js时:
当地图在另一个组件中时:
这是我针对这两种情况的代码:
地图在App.js时的代码:
import React, {Component} from 'react';
import L from 'leaflet';
import './MapView.css';
import fence from './assets/fence.png';
import pin from './assets/pin.png';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
class App extends Component {
constructor() {
super();
this.state = {
markers: [],
center: [51.505, -0.09]
};
this.addMarker = this.addMarker.bind(this)
}
fence = L.icon({
iconUrl: fence,
iconSize: [46.3125, 51.5625], // size of the icon
iconAnchor: [22, 25], // point of the icon which will correspond to marker's location
popupAnchor: [0, -25]
});
addMarker = (e) => {
const {markers} = this.state
markers.push(this.state.center)
this.setState({markers})
}
render() {
const self = this;
return (
<div className="map-container">
<button onClick={this.addMarker} className="btn">+</button>
<div className="center"></div>
<MapContainer
className="map"
minZoom= {8}
zoom={20}
center = {this.state.center}
whenReady={(map) => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(function (location) {
console.log(location);
map.target.panTo(new L.LatLng(location.coords.latitude, location.coords.longitude))
var marker = L.marker([location.coords.latitude, location.coords.longitude], {icon: L.icon({
iconUrl: pin,
iconSize: [24, 38], // size of the icon
iconAnchor: [12.5, 40], // point of the icon which will correspond to marker's location
popupAnchor: [0, -50]
})} ).addTo(map.target);
marker.bindPopup("Your current location")
marker.openPopup()
});
}
map.target.on("drag", function (e) {
self.setState({center: map.target.getCenter()})
});
map.target.on("zoom", function (e) {
self.setState({center: map.target.getCenter()})
})
}}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
></TileLayer>
{this.state.markers.map((position, idx) =>
<Marker key={`marker-${idx}`} icon={this.fence} position={position}>
<Popup>
<span>Title<br/></span>
</Popup>
</Marker>
)}
</MapContainer>
</div>
);
}
}
export default App;
地图在另一个视图中时的代码,路由自App.js:
//App.js
import React from "react";
import "./App.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import MapView from './MapView';
import AddView from './AddView';
import Navbar from './Navbar';
function App() {
return (
<div className="App">
<Router>
<Navbar/>
<Switch>
<Route exact from="/" component={MapView} />
<Route exact path="/new" component={AddView} />
</Switch>
</Router>
</div>
);
}
export default App;
//MapView.js
import React, {Component} from 'react';
import L from 'leaflet';
import './MapView.css';
import fence from './assets/fence.png';
import pin from './assets/pin.png';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
class MapView extends Component {
constructor() {
super();
this.state = {
markers: [],
center: [51.505, -0.09]
};
this.addMarker = this.addMarker.bind(this)
}
fence = L.icon({
iconUrl: fence,
iconSize: [46.3125, 51.5625], // size of the icon
iconAnchor: [22, 25], // point of the icon which will correspond to marker's location
popupAnchor: [0, -25]
});
addMarker = (e) => {
const {markers} = this.state
markers.push(this.state.center)
this.setState({markers})
}
render() {
const self = this;
return (
<div className="map-container">
<button onClick={this.addMarker} className="btn">+</button>
<div className="center"></div>
<MapContainer
id="map"
className="map"
minZoom= {8}
zoom={20}
center = {this.state.center}
whenReady={(map) => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(function (location) {
localStorage.setItem('latitude', location.coords.latitude)
localStorage.setItem('longitude', location.coords.longitude)
let latitude= location.coords.latitude;
let longitude= location.coords.longitude;
console.log(location);
map.target.panTo(new L.LatLng(latitude, longitude))
var marker = L.marker([latitude, longitude], {icon: L.icon({
iconUrl: pin,
iconSize: [24, 38],
iconAnchor: [12.5, 40],
popupAnchor: [0, -50]
})} ).addTo(map.target);
marker.bindPopup("Your current location")
marker.openPopup()
});
} else {
console.log("Ik kom erin bro wtf")
let latitude = localStorage.getItem('latitude') ?? 51.505
let longitude = localStorage.getItem('longitude') ?? -0.09
map.target.panTo(new L.LatLng(latitude, longitude))
}
map.target.on("drag", function (e) {
self.setState({center: map.target.getCenter()})
});
map.target.on("zoom", function (e) {
self.setState({center: map.target.getCenter()})
})
}}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
></TileLayer>
{this.state.markers.map((position, idx) =>
<Marker key={`marker-${idx}`} icon={this.fence} position={position}>
<Popup>
<span>Title<br/></span>
</Popup>
</Marker>
)}
</MapContainer>
</div>
);
}
}
export default MapView;
//Navbar.js
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import {
Link
} from "react-router-dom";
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
bar: {
height: '7.5vh',
}
}));
function Navbar() {
const classes = useStyles();
return (
<AppBar position="static" className={classes.bar}>
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
Work in progress
</Typography>
<Link color="inherit" to="/new">Report construction</Link>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
);
}
export default Navbar;
我对 Leaflet 了解不多,因为这是我用它制作的第一个应用程序,所以如果我混淆了这背后的一些理论,请考虑到这一点。有谁知道我的代码、我的思维方式是否有问题,或者这背后是否有我遗漏的传单理论?我期待听到任何答案。
这是因为您将地图缩放设置为20,而上限为19。您可以在此处找到更多原因
您所要做的就是在 TileLayer
组件上设置 maxZoom
和 maxNativeZoom
props
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
maxNativeZoom={19}
maxZoom={22}
/>
您可能想在 whenReady() 内平移到您的位置之前尝试设置延迟。函数启动时地图可能没有完全渲染,这可能会解决问题
setTimeout(() => { this.goToLocation() }, 1000);
我正在尝试在我的 React 应用程序中使用 Leaflet 地图,但我 运行 遇到了一个奇怪的问题。我告诉我的地图在 whenReady 函数中平移到用户的当前地理位置(如果他们允许访问他们的位置),但是当它这样做时,地图会出现故障。是什么让这个怪异的是它只发生在我将我的地图放在我从 App.js 路由到的视图中(我想将它与导航栏一起显示)。当它位于 App.js 本身时,这不会发生并且地图会正确显示我的位置。我附上图片来说明我的意思:
当地图位于App.js时:
当地图在另一个组件中时:
这是我针对这两种情况的代码:
地图在App.js时的代码:
import React, {Component} from 'react';
import L from 'leaflet';
import './MapView.css';
import fence from './assets/fence.png';
import pin from './assets/pin.png';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
class App extends Component {
constructor() {
super();
this.state = {
markers: [],
center: [51.505, -0.09]
};
this.addMarker = this.addMarker.bind(this)
}
fence = L.icon({
iconUrl: fence,
iconSize: [46.3125, 51.5625], // size of the icon
iconAnchor: [22, 25], // point of the icon which will correspond to marker's location
popupAnchor: [0, -25]
});
addMarker = (e) => {
const {markers} = this.state
markers.push(this.state.center)
this.setState({markers})
}
render() {
const self = this;
return (
<div className="map-container">
<button onClick={this.addMarker} className="btn">+</button>
<div className="center"></div>
<MapContainer
className="map"
minZoom= {8}
zoom={20}
center = {this.state.center}
whenReady={(map) => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(function (location) {
console.log(location);
map.target.panTo(new L.LatLng(location.coords.latitude, location.coords.longitude))
var marker = L.marker([location.coords.latitude, location.coords.longitude], {icon: L.icon({
iconUrl: pin,
iconSize: [24, 38], // size of the icon
iconAnchor: [12.5, 40], // point of the icon which will correspond to marker's location
popupAnchor: [0, -50]
})} ).addTo(map.target);
marker.bindPopup("Your current location")
marker.openPopup()
});
}
map.target.on("drag", function (e) {
self.setState({center: map.target.getCenter()})
});
map.target.on("zoom", function (e) {
self.setState({center: map.target.getCenter()})
})
}}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
></TileLayer>
{this.state.markers.map((position, idx) =>
<Marker key={`marker-${idx}`} icon={this.fence} position={position}>
<Popup>
<span>Title<br/></span>
</Popup>
</Marker>
)}
</MapContainer>
</div>
);
}
}
export default App;
地图在另一个视图中时的代码,路由自App.js:
//App.js
import React from "react";
import "./App.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import MapView from './MapView';
import AddView from './AddView';
import Navbar from './Navbar';
function App() {
return (
<div className="App">
<Router>
<Navbar/>
<Switch>
<Route exact from="/" component={MapView} />
<Route exact path="/new" component={AddView} />
</Switch>
</Router>
</div>
);
}
export default App;
//MapView.js
import React, {Component} from 'react';
import L from 'leaflet';
import './MapView.css';
import fence from './assets/fence.png';
import pin from './assets/pin.png';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
class MapView extends Component {
constructor() {
super();
this.state = {
markers: [],
center: [51.505, -0.09]
};
this.addMarker = this.addMarker.bind(this)
}
fence = L.icon({
iconUrl: fence,
iconSize: [46.3125, 51.5625], // size of the icon
iconAnchor: [22, 25], // point of the icon which will correspond to marker's location
popupAnchor: [0, -25]
});
addMarker = (e) => {
const {markers} = this.state
markers.push(this.state.center)
this.setState({markers})
}
render() {
const self = this;
return (
<div className="map-container">
<button onClick={this.addMarker} className="btn">+</button>
<div className="center"></div>
<MapContainer
id="map"
className="map"
minZoom= {8}
zoom={20}
center = {this.state.center}
whenReady={(map) => {
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(function (location) {
localStorage.setItem('latitude', location.coords.latitude)
localStorage.setItem('longitude', location.coords.longitude)
let latitude= location.coords.latitude;
let longitude= location.coords.longitude;
console.log(location);
map.target.panTo(new L.LatLng(latitude, longitude))
var marker = L.marker([latitude, longitude], {icon: L.icon({
iconUrl: pin,
iconSize: [24, 38],
iconAnchor: [12.5, 40],
popupAnchor: [0, -50]
})} ).addTo(map.target);
marker.bindPopup("Your current location")
marker.openPopup()
});
} else {
console.log("Ik kom erin bro wtf")
let latitude = localStorage.getItem('latitude') ?? 51.505
let longitude = localStorage.getItem('longitude') ?? -0.09
map.target.panTo(new L.LatLng(latitude, longitude))
}
map.target.on("drag", function (e) {
self.setState({center: map.target.getCenter()})
});
map.target.on("zoom", function (e) {
self.setState({center: map.target.getCenter()})
})
}}
>
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
></TileLayer>
{this.state.markers.map((position, idx) =>
<Marker key={`marker-${idx}`} icon={this.fence} position={position}>
<Popup>
<span>Title<br/></span>
</Popup>
</Marker>
)}
</MapContainer>
</div>
);
}
}
export default MapView;
//Navbar.js
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import {
Link
} from "react-router-dom";
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
bar: {
height: '7.5vh',
}
}));
function Navbar() {
const classes = useStyles();
return (
<AppBar position="static" className={classes.bar}>
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
Work in progress
</Typography>
<Link color="inherit" to="/new">Report construction</Link>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
);
}
export default Navbar;
我对 Leaflet 了解不多,因为这是我用它制作的第一个应用程序,所以如果我混淆了这背后的一些理论,请考虑到这一点。有谁知道我的代码、我的思维方式是否有问题,或者这背后是否有我遗漏的传单理论?我期待听到任何答案。
这是因为您将地图缩放设置为20,而上限为19。您可以在此处找到更多原因
您所要做的就是在 TileLayer
组件上设置 maxZoom
和 maxNativeZoom
props
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
maxNativeZoom={19}
maxZoom={22}
/>
您可能想在 whenReady() 内平移到您的位置之前尝试设置延迟。函数启动时地图可能没有完全渲染,这可能会解决问题
setTimeout(() => { this.goToLocation() }, 1000);