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

354 lines
9.6 KiB
JavaScript
Raw 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, Select, Spin } from "antd";
import { useEffect, useRef, useState } from "react";
import { dynamicLoadCss, dynamicLoadJs } from "../../utils";
import CesiumMap from "./CesiumMap";
import "./index.less";
/**
* 定位组件弹窗
*/
const MapSelector = (props) => {
const {
visible,
onClose,
longitude,
latitude,
onConfirm,
area = "",
showArea = false,
disable = false,
type = "baidu",
} = props;
const mapContainerRef = useRef(null);
const mapInstanceRef = useRef(null);
const local = useRef(null);
const [loading, setLoading] = useState(false);
const [currentLongitude, setCurrentLongitude] = useState(longitude || "");
const [currentLatitude, setCurrentLatitude] = useState(latitude || "");
const [localSearch, setLocalSearch] = useState("");
const [currentArea, setCurrentArea] = useState("");
// 当外部经纬度变化时,更新内部状态
useEffect(() => {
setCurrentLongitude(longitude || "");
setCurrentLatitude(latitude || "");
setCurrentArea(area || "");
}, [longitude, latitude, area]);
// 百度地图初始化
const initBaiDuMap = () => {
if (!window?.BMapGL?.Map) {
setTimeout(() => {
initBaiDuMap();
}, 50);
return;
}
const map = new window.BMapGL.Map(mapContainerRef.current);
mapInstanceRef.current = map;
map.centerAndZoom(
new window.BMapGL.Point(
longitude || window.mapLongitude,
latitude || window.mapLatitude,
),
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);
}
// 添加点击事件
if (!disable) {
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);
});
}
};
// Cesium地图初始化
const initCesiumMap = () => {
const { init, flyTo, addMarkPoint, getLongitudeAndLatitude } = new CesiumMap();
const { viewer } = init();
mapInstanceRef.current = viewer;
flyTo({ longitude: longitude || window.mapLongitude, latitude: latitude || window.mapLatitude, height: 900000 });
if (longitude && latitude) {
addMarkPoint({ longitude, latitude });
}
getLongitudeAndLatitude((error, coords) => {
if (error)
return;
const { longitude, latitude } = coords;
setCurrentLatitude(latitude);
setCurrentLongitude(longitude);
});
};
// 初始化地图
const initMap = () => {
setLoading(true);
if (mapContainerRef.current) {
// 只有在没有地图实例时才创建新地图
if (!mapInstanceRef.current) {
if (type === "baidu") {
initBaiDuMap();
return;
}
if (type === "cesium") {
initCesiumMap();
}
}
setLoading(false);
}
};
// 加载百度地图资源
const loadBaiDuMap = async () => {
if (!window.BMapGL) {
if (window?.base?.loadDynamicResource) {
await window.base.loadDynamicResource({
url: "https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr&callback=initialize",
type: "script",
attr: { type: "text/javascript" },
});
initMap();
}
else {
await dynamicLoadJs("https://api.map.baidu.com/api?v=1.0&type=webgl&ak=OElqFYoKiAH8KFtph8ftLKF5NlNrbCUr&callback=initialize");
initMap();
}
}
else {
initMap();
}
};
// 加载Cesium地图资源
const loadCesiumMap = async () => {
if (!window.Cesium) {
if (window?.base?.loadDynamicResource) {
await window.base.loadDynamicResource({
url: "https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Cesium.js",
type: "script",
attr: { type: "text/javascript" },
});
await window.base.loadDynamicResource({
url: "https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Widgets/widgets.css",
type: "link",
attr: { rel: "stylesheet", type: "text/css" },
});
initMap();
}
else {
await dynamicLoadJs("https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Cesium.js");
await dynamicLoadCss("https://cesium.com/downloads/cesiumjs/releases/1.91/Build/Cesium/Widgets/widgets.css");
initMap();
}
}
else {
initMap();
}
};
// 加载地图资源
const loadMap = () => {
if (!window.mapLongitude && !window.mapLatitude) {
console.error("请在window设置变量 mapLongitude 和 mapLatitude以供地图初始化坐标使用");
return;
}
if (type === "baidu") {
loadBaiDuMap();
return;
}
if (type === "cesium") {
loadCesiumMap();
}
};
// 搜索功能
const handleLocalSearch = () => {
if (localSearch && mapInstanceRef.current) {
local.current = new window.BMapGL.LocalSearch(mapInstanceRef.current, {
renderOptions: { map: mapInstanceRef.current },
});
local.current.search(localSearch);
}
};
// 清空
const handleLocalClear = () => {
setLocalSearch("");
if (mapInstanceRef.current) {
local.current.search("");
}
};
// 关闭弹窗
const handleClose = () => {
setLocalSearch("");
if (mapInstanceRef.current) {
mapInstanceRef.current.destroy();
mapInstanceRef.current = null;
}
if (onClose)
onClose();
};
// 确认选择
const handleConfirm = () => {
if (onConfirm) {
onConfirm(currentLongitude, currentLatitude, { area: currentArea });
}
handleClose();
};
// 监听visible变化
useEffect(() => {
let initTimer;
if (visible) {
// 延迟初始化地图确保DOM完全渲染
initTimer = setTimeout(() => {
loadMap();
}, 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}
width={1000}
destroyOnHidden={false}
maskClosable={false}
afterClose={handleAfterClose}
footer={[
<Button key="back" onClick={handleClose}>
取消
</Button>,
!disable && (
<Button key="submit" type="primary" onClick={handleConfirm}>
确定
</Button>
),
]}
>
<Form labelAlign="right" labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}>
{
showArea && (
<Row gutter={24}>
<Col span={12}>
<Form.Item label="所属区域">
<Select value={currentArea} onChange={e => setCurrentArea(e)} allowClear>
<Select.Option value="1">东港区</Select.Option>
<Select.Option value="2">西港区</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
)
}
{
(!disable && type === "baidu") && (
<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} style={{ textAlign: "right" }}>
<Button type="primary" onClick={handleLocalSearch}>
搜索
</Button>
<Button onClick={handleLocalClear} style={{ marginLeft: 8 }}>
重置
</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}
id="map_container"
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>
);
};
MapSelector.displayName = "MapSelector";
export default MapSelector;