zy-react-library/components/Map/MapSelector.js

210 lines
5.3 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { Button, Col, Form, Input, Modal, Row, Spin } from "antd";
import { useEffect, useRef, useState } from "react";
/**
* 定位组件弹窗
*/
const MapSelector = (props) => {
const {
visible,
onClose,
longitude,
latitude,
onConfirm,
} = props;
const mapContainerRef = useRef(null);
const mapInstanceRef = useRef(null);
const [loading, setLoading] = useState(false);
const [currentLongitude, setCurrentLongitude] = useState(longitude || "");
const [currentLatitude, setCurrentLatitude] = useState(latitude || "");
const [localSearch, setLocalSearch] = useState("");
// 当外部经纬度变化时,更新内部状态
useEffect(() => {
setCurrentLongitude(longitude || "");
setCurrentLatitude(latitude || "");
}, [longitude, latitude]);
// 初始化地图
const initMap = async () => {
if (!window.BMapGL) {
console.error("BMapGL is not loaded");
return;
}
setLoading(true);
// 确保DOM已经渲染
await new Promise(resolve => setTimeout(resolve, 100));
if (mapContainerRef.current) {
// 只有在没有地图实例时才创建新地图
if (!mapInstanceRef.current) {
const map = new window.BMapGL.Map(mapContainerRef.current);
mapInstanceRef.current = map;
map.centerAndZoom(
new window.BMapGL.Point(
longitude || "119.69457721306945",
latitude || "39.940504336846665",
),
16,
);
map.enableScrollWheelZoom(true);
// 如果有初始坐标,添加标记
if (longitude && latitude) {
const point = new window.BMapGL.Point(longitude, latitude);
const marker = new window.BMapGL.Marker(point);
map.addOverlay(marker);
}
// 添加点击事件
map.addEventListener("click", (event) => {
map.clearOverlays();
const point = new window.BMapGL.Point(event.latlng.lng, event.latlng.lat);
const marker = new window.BMapGL.Marker(point);
map.addOverlay(marker);
setCurrentLatitude(event.latlng.lat);
setCurrentLongitude(event.latlng.lng);
});
}
setLoading(false);
}
};
// 搜索功能
const handleLocalSearch = () => {
if (localSearch && mapInstanceRef.current) {
const local = new window.BMapGL.LocalSearch(mapInstanceRef.current, {
renderOptions: { map: mapInstanceRef.current },
});
local.search(localSearch);
}
};
// 关闭弹窗
const handleClose = () => {
setLocalSearch("");
if (onClose)
onClose();
};
// 确认选择
const handleConfirm = () => {
if (onConfirm) {
onConfirm(currentLongitude, currentLatitude);
}
handleClose();
};
// 监听visible变化
useEffect(() => {
let initTimer;
if (visible) {
// 延迟初始化地图确保DOM完全渲染
initTimer = setTimeout(() => {
initMap();
}, 100);
}
return () => {
if (initTimer) {
clearTimeout(initTimer);
}
};
}, [visible]);
const handleAfterClose = () => {
if (mapInstanceRef.current) {
try {
mapInstanceRef.current.clearOverlays();
mapInstanceRef.current.destroy();
mapInstanceRef.current = null;
}
catch (e) {
console.warn("Error destroying map on unmount:", e);
}
mapInstanceRef.current = null;
}
};
// 组件卸载时清理地图
useEffect(() => {
return () => {
handleAfterClose();
};
}, []);
return (
<Modal
open={visible}
title="坐标"
onCancel={handleClose}
onOk={handleConfirm}
width={800}
destroyOnHidden={false}
afterClose={handleAfterClose}
>
<Form labelAlign="right" labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
<Row gutter={24}>
<Col span={12}>
<Form.Item label="关键字搜索">
<Input
value={localSearch}
onChange={e => setLocalSearch(e.target.value)}
allowClear
/>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label=" " colon={false}>
<Button type="primary" onClick={handleLocalSearch}>
搜索
</Button>
</Form.Item>
</Col>
</Row>
<Row gutter={24}>
<Col span={12}>
<Form.Item label="经度">
<Input disabled value={currentLongitude} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="纬度">
<Input disabled value={currentLatitude} />
</Form.Item>
</Col>
</Row>
</Form>
<div
ref={mapContainerRef}
style={{ width: "100%", height: "500px", position: "relative" }}
>
<Spin size="large" tip="地图正在加载中..." spinning={loading}>
<div style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "rgba(0, 0, 0, 0.5)",
zIndex: 1000,
}}
/>
</Spin>
</div>
</Modal>
);
};
export default MapSelector;