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

210 lines
5.3 KiB
JavaScript
Raw Normal View History

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;