响应式设计中的传单坐标到lat lng
Leaflet coordinate to lat lng in responsive design
我有一个 Leaflet 响应式地图,我在 React 中使用它。我的地图是一个自定义的平面图,它是 svg 格式的。我已经使用“ImageOverlay”设置了地图,一切正常。现在我的问题只发生在我使用点 (x, y) 坐标并将其转换为 lat, lng
时。 lat, lng
会根据屏幕尺寸发生变化。我需要一个固定的 lat, lng
相应的屏幕尺寸,以便我可以显示标记。目前,如果我根据屏幕尺寸显示标记,则标记位置会显示在不同的地方。 所以我的问题是如何获得 lat, lng
而不管屏幕尺寸? 这是我的代码:
L.CRS.Simple = L.extend({}, L.CRS, {
projection: L.Projection.LonLat,
transformation: new L.Transformation(1, 0, 1, 0)
});
const mapHeight = 400;
const mapWidth = 100;
const svgImageWidth = 2245;
const svgImageHeight = 1587;
const initState = {
mapBounds: [[0, 0], [1000, 1000]],
mapMarkerPosition: [40.751, -74.17],
mapZoom: 4,
mapCenter: [40.74400563300867, -74.1680145263672],
xCoordinate: "",
yCoordinate: "",
coordinates: { x: 292, y: 89 }
};
export default function App() {
const mapRef = useRef(null);
const [state, setState] = useState(initState);
function getBoundsUnproject(map) {
const southWest = map.unproject([0, svgImageHeight], 6);
const northEast = map.unproject([svgImageWidth, 0], 6);
const bounds = new L.LatLngBounds(southWest, northEast);
map.setMaxBounds(bounds);
return { bounds };
}
React.useEffect(() => {
const map = mapRef.current.leafletElement;
if (map) {
const { bounds } = getBoundsUnproject(map);
console.log("bounds", bounds);
map.fitBounds(bounds);
const centerLatLng = map.getCenter();
console.log("center", centerLatLng);
const customCoordinates = state.coordinates;
// console.log("customCoordinates", customCoordinates);
const point = L.point(customCoordinates.x, customCoordinates.y);
const customCoordinatesLatLng = map.containerPointToLatLng(point);
console.log("customCoordinatesLatLng", customCoordinatesLatLng);
setState(prevState => ({
...prevState,
mapBounds: [
[bounds._northEast.lat, bounds._northEast.lng],
[bounds._southWest.lat, bounds._southWest.lng]
],
mapMarkerPosition: [
customCoordinatesLatLng.lat,
customCoordinatesLatLng.lng
]
}));
}
}, [state.coordinates]);
function handleChange(event) {
const name = event.target.name;
const value = event.target.value;
if (isNaN(value)) {
return;
}
setState(prevState => ({
...prevState,
[name]: value
}));
}
function handleClick() {
setState(prevState => ({
...prevState,
coordinates: { x: state.xCoordinate, y: state.yCoordinate }
}));
}
return (
<div className="container-fluid">
<div className="row justify-content-center mt-5">
<div className="col-md-6">
<div className="row justify-content-center">
<div className="col-md-4">
<input
style={{ width: "100%" }}
type="text"
value={state.xCoordinate}
onChange={handleChange}
name="xCoordinate"
placeholder="x coordinate (default: 292)"
/>
</div>
<div className="col-md-4">
<input
style={{ width: "100%" }}
type="text"
value={state.yCoordinate}
onChange={handleChange}
name="yCoordinate"
placeholder="y coordinate (default: 89)"
/>
</div>
<div className="col-md-2">
<button onClick={handleClick}>Submit</button>
</div>
</div>
</div>
</div>
<div className="row justify-content-center mt-5 mb-5">
<div className="col-6">
<LeafletMap
ref={mapRef}
crs={L.CRS.Simple}
center={state.mapCenter}
zoom={state.mapZoom}
minZoom={state.mapZoom}
style={{ height: `${mapHeight}px`, width: `${mapWidth}%` }}
>
<ImageOverlay
bounds={state.mapBounds}
url={"image-url"}
>
<Marker
position={state.mapMarkerPosition}
icon={customMarkerIcon}
/>
</ImageOverlay>
</LeafletMap>
</div>
</div>
</div>
);
}
如果有人指出我做错了什么会很有帮助。
谢谢。
问题是 map.containerPointToLatLng()
,顾名思义,假设您给它的点是相对于地图的容器坐标,即它的左上角。
但由于我们通常通过其 center(和缩放)指定地图视图,左上角的容器可能会根据其大小显示不同的经纬度位置。由于您将其大小(宽度)设置为其父元素的 100%,因此如果您采用响应式设计,则此大小可能会随屏幕大小/方向而变化。
并且当容器左上角显示不同的经纬度位置时,map.containerPointToLatLng也会不同。
一个可能的解决方案是保持计算转化次数的一致性。您很可能实际上希望您的标记相对于您的 SVG 平面图而不是地图容器定位。在这种情况下,只需按照与平面图边界相同的方式计算标记坐标,即 map.unproject()
我有一个 Leaflet 响应式地图,我在 React 中使用它。我的地图是一个自定义的平面图,它是 svg 格式的。我已经使用“ImageOverlay”设置了地图,一切正常。现在我的问题只发生在我使用点 (x, y) 坐标并将其转换为 lat, lng
时。 lat, lng
会根据屏幕尺寸发生变化。我需要一个固定的 lat, lng
相应的屏幕尺寸,以便我可以显示标记。目前,如果我根据屏幕尺寸显示标记,则标记位置会显示在不同的地方。 所以我的问题是如何获得 lat, lng
而不管屏幕尺寸? 这是我的代码:
L.CRS.Simple = L.extend({}, L.CRS, {
projection: L.Projection.LonLat,
transformation: new L.Transformation(1, 0, 1, 0)
});
const mapHeight = 400;
const mapWidth = 100;
const svgImageWidth = 2245;
const svgImageHeight = 1587;
const initState = {
mapBounds: [[0, 0], [1000, 1000]],
mapMarkerPosition: [40.751, -74.17],
mapZoom: 4,
mapCenter: [40.74400563300867, -74.1680145263672],
xCoordinate: "",
yCoordinate: "",
coordinates: { x: 292, y: 89 }
};
export default function App() {
const mapRef = useRef(null);
const [state, setState] = useState(initState);
function getBoundsUnproject(map) {
const southWest = map.unproject([0, svgImageHeight], 6);
const northEast = map.unproject([svgImageWidth, 0], 6);
const bounds = new L.LatLngBounds(southWest, northEast);
map.setMaxBounds(bounds);
return { bounds };
}
React.useEffect(() => {
const map = mapRef.current.leafletElement;
if (map) {
const { bounds } = getBoundsUnproject(map);
console.log("bounds", bounds);
map.fitBounds(bounds);
const centerLatLng = map.getCenter();
console.log("center", centerLatLng);
const customCoordinates = state.coordinates;
// console.log("customCoordinates", customCoordinates);
const point = L.point(customCoordinates.x, customCoordinates.y);
const customCoordinatesLatLng = map.containerPointToLatLng(point);
console.log("customCoordinatesLatLng", customCoordinatesLatLng);
setState(prevState => ({
...prevState,
mapBounds: [
[bounds._northEast.lat, bounds._northEast.lng],
[bounds._southWest.lat, bounds._southWest.lng]
],
mapMarkerPosition: [
customCoordinatesLatLng.lat,
customCoordinatesLatLng.lng
]
}));
}
}, [state.coordinates]);
function handleChange(event) {
const name = event.target.name;
const value = event.target.value;
if (isNaN(value)) {
return;
}
setState(prevState => ({
...prevState,
[name]: value
}));
}
function handleClick() {
setState(prevState => ({
...prevState,
coordinates: { x: state.xCoordinate, y: state.yCoordinate }
}));
}
return (
<div className="container-fluid">
<div className="row justify-content-center mt-5">
<div className="col-md-6">
<div className="row justify-content-center">
<div className="col-md-4">
<input
style={{ width: "100%" }}
type="text"
value={state.xCoordinate}
onChange={handleChange}
name="xCoordinate"
placeholder="x coordinate (default: 292)"
/>
</div>
<div className="col-md-4">
<input
style={{ width: "100%" }}
type="text"
value={state.yCoordinate}
onChange={handleChange}
name="yCoordinate"
placeholder="y coordinate (default: 89)"
/>
</div>
<div className="col-md-2">
<button onClick={handleClick}>Submit</button>
</div>
</div>
</div>
</div>
<div className="row justify-content-center mt-5 mb-5">
<div className="col-6">
<LeafletMap
ref={mapRef}
crs={L.CRS.Simple}
center={state.mapCenter}
zoom={state.mapZoom}
minZoom={state.mapZoom}
style={{ height: `${mapHeight}px`, width: `${mapWidth}%` }}
>
<ImageOverlay
bounds={state.mapBounds}
url={"image-url"}
>
<Marker
position={state.mapMarkerPosition}
icon={customMarkerIcon}
/>
</ImageOverlay>
</LeafletMap>
</div>
</div>
</div>
);
}
如果有人指出我做错了什么会很有帮助。
谢谢。
问题是 map.containerPointToLatLng()
,顾名思义,假设您给它的点是相对于地图的容器坐标,即它的左上角。
但由于我们通常通过其 center(和缩放)指定地图视图,左上角的容器可能会根据其大小显示不同的经纬度位置。由于您将其大小(宽度)设置为其父元素的 100%,因此如果您采用响应式设计,则此大小可能会随屏幕大小/方向而变化。
并且当容器左上角显示不同的经纬度位置时,map.containerPointToLatLng也会不同。
一个可能的解决方案是保持计算转化次数的一致性。您很可能实际上希望您的标记相对于您的 SVG 平面图而不是地图容器定位。在这种情况下,只需按照与平面图边界相同的方式计算标记坐标,即 map.unproject()