105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import React, { useState } from "react";
|
||
import { useMap } from "../MapComponent";
|
||
import Geolocation from "ol/Geolocation";
|
||
import AddRoundedIcon from "@mui/icons-material/AddRounded";
|
||
import RemoveRoundedIcon from "@mui/icons-material/RemoveRounded";
|
||
import GpsFixedRoundedIcon from "@mui/icons-material/GpsFixedRounded";
|
||
import clsx from "clsx";
|
||
|
||
const INITIAL_ZOOM = 14; // 默认缩放级别
|
||
|
||
const Zoom: React.FC = () => {
|
||
const map = useMap();
|
||
const [locateDisabled, setLocateDisabled] = useState(false);
|
||
|
||
// 放大函数
|
||
const handleZoomIn = () => {
|
||
if (!map) return;
|
||
const view = map.getView();
|
||
view.animate({ zoom: (view.getZoom() ?? 0) + 1, duration: 200 });
|
||
};
|
||
|
||
// 缩小函数
|
||
const handleZoomOut = () => {
|
||
if (!map) return;
|
||
const view = map.getView();
|
||
view.animate({ zoom: (view.getZoom() ?? 0) - 1, duration: 200 });
|
||
};
|
||
|
||
// 定位功能
|
||
const handleLocate = () => {
|
||
if (!map) return;
|
||
|
||
const geolocation = new Geolocation({
|
||
trackingOptions: { enableHighAccuracy: true },
|
||
projection: map.getView().getProjection(),
|
||
});
|
||
|
||
geolocation.once("change:position", () => {
|
||
const coords = geolocation.getPosition();
|
||
if (coords) {
|
||
map
|
||
.getView()
|
||
.animate({ center: coords, zoom: INITIAL_ZOOM, duration: 500 });
|
||
}
|
||
geolocation.setTracking(false);
|
||
});
|
||
|
||
geolocation.setTracking(true);
|
||
};
|
||
|
||
// 包装 handleLocate,点击后禁用按钮一段时间
|
||
const onLocateClick = () => {
|
||
navigator.geolocation.getCurrentPosition(
|
||
() => {
|
||
handleLocate();
|
||
},
|
||
(error) => {
|
||
console.log(error.message);
|
||
setLocateDisabled(true); // 定位失败后禁用按钮
|
||
// alert("定位失败,将使用默认位置。");
|
||
}
|
||
);
|
||
};
|
||
|
||
return (
|
||
<div className="absolute right-4 bottom-8">
|
||
<div className="w-8 h-26 flex flex-col gap-2 items-center">
|
||
<div
|
||
className={clsx(
|
||
"w-8 h-8 bg-gray-50 flex items-center justify-center rounded-xl drop-shadow-xl shadow-black",
|
||
locateDisabled && "text-gray-300"
|
||
)}
|
||
>
|
||
<button
|
||
className="w-6 h-6 flex items-center justify-center rounded-xl hover:bg-white transition-all duration-100"
|
||
onClick={onLocateClick}
|
||
disabled={locateDisabled}
|
||
>
|
||
<GpsFixedRoundedIcon fontSize="small" />
|
||
</button>
|
||
</div>
|
||
<div className="w-8 h-16 flex flex-col items-center justify-center bg-gray-50 rounded-xl drop-shadow-xl shadow-black">
|
||
<button
|
||
className="w-6 h-6 flex items-center justify-center rounded-xl hover:bg-white transition-all duration-100"
|
||
onClick={handleZoomIn}
|
||
aria-label="放大"
|
||
>
|
||
<AddRoundedIcon />
|
||
</button>
|
||
<div className="m-0.5 border-t-1 border-gray-300 w-6"></div>
|
||
<button
|
||
className="w-6 h-6 flex items-center justify-center rounded-xl hover:bg-white transition-all duration-100"
|
||
onClick={handleZoomOut}
|
||
aria-label="缩小"
|
||
>
|
||
<RemoveRoundedIcon />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default Zoom;
|