import React, { useEffect, useRef, useState, CSSProperties } from 'react'
import { Select } from 'antd'
const { Option } = Select;
const AMAP_KEY = "cc9fb7d123185499909bf80c4c778535"
const queryBykeyword = async (params: object) => {
let url = 'https://restapi.amap.com/v3/place/text'
const config = {
output: 'JSON',
key: AMAP_KEY,
extensions: 'all'
}
let newParams = "?"
for (const [key, value] of Object.entries({ ...config, ...params })) {
newParams = newParams[newParams.length - 1] === "&" ? newParams : newParams + "&"
newParams = newParams + key + "=" + value;
}
url = url + newParams
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open("get", url)
xhr.send()
// xhr.responseType
xhr.addEventListener('load', () => {
const status = xhr.status;
if ((status >= 200 && status < 300) || status === 304) {
const result = JSON.parse(xhr.response)
resolve(result)
} else {
reject(xhr)
}
});
})
}
const styleSearch: CSSProperties = {
width: "60%",
background: 'transparent',
position: 'absolute',
right: 12,
top: 20,
zIndex: 2,
}
const styleHandle: CSSProperties = {
cursor: ' pointer',
pointerEvents: 'all',
zIndex: 3,
position: 'absolute',
right: 8,
top: 0,
transform: 'translateY(50%)'
}
const styleTip: CSSProperties = {
pointerEvents: 'none',
zIndex: 3,
position: 'absolute',
right: 0,
top: 20,
// transform: 'translateX(50%) translateY(calc(-50% - 10px ))',
fontSize: 12,
transition: 'all 0.4s ease 0s'
}
interface PropsT {
sendLnglat: (lnglat: any[]) => void
initLnglat?: any[]
}
const Amap = (props: PropsT) => {
const { sendLnglat,initLnglat } = props
const refMap = useRef(null)
// const [geoCenter, setGeoCenter] = useState<any[]>()
const [keywords, setSeywords] = useState('')
const [result, setResult] = useState<any[]>([])
const [myMap, setMyMap] = useState<any>()
// const [currentItem, setCurrentItem] = useState<any>({})
const [hoverItemPos, setHoverItemPos] = useState<any>({})
const [hoverItem, setHoverItem] = useState<any>({})
useEffect(() => {
if (!window.AMap) {
// console.log('start loadMapScript');
loadMapScript()
} else {
initMap()
}
}, [])
const loadMapScript = () => {
window.initMap = () => {
// console.log('AMap script is ready!!');
initMap();
};
const script = document.createElement('script');
script.type = 'text/javascript';
script.src =
`https://webapi.amap.com/maps?v=1.4.15&key=${AMAP_KEY}&callback=initMap`;
document.body.appendChild(script);
};
const initMap = () => {
if (!window.AMap) {
// console.error('AMap script is not ready!!');
return;
}
// console.log('start initMap');
const map = new window.AMap.Map(refMap.current, {
zoom: 12, // 级别
center: initLnglat,// 中心点坐标
resizeEnable: true,
dragEnable: true,
// showIndoorMap: false,
// showLabel: false,
// mapStyle: 'amap://styles/whitesmoke',
// features: ['bg', 'road', 'building'],
});
map.plugin('AMap.ToolBar', () => { // 添加地图控件
const toolbar = new window.AMap.ToolBar();
map.addControl(toolbar)
})
map.on('click', (ev: any) => {// 绑定全局事点击件获取坐标
// 触发事件的对象
// var target = ev.target;
// 触发事件的地理坐标,AMap.LngLat 类型
const lnglat = ev.lnglat;
// 触发事件的像素坐标,AMap.Pixel 类型
// var pixel = ev.pixel;
// 触发事件类型
// var type = ev.type;
// console.log("ev==", ev);
const { lng, lat } = lnglat
sendLnglat([lng, lat])
});
map.on('dragstart', () => { // 绑定全局拖拽事件,重置活跃项及其坐标
setHoverItemPos({})
setHoverItem({})
});
setMyMap(map) // 保存当前地图实例
};
const handleChange = (_val: any, opt: any) => {
const { item } = opt.props
// console.log("val opt", val, opt);
// setCurrentItem(item)
if (!window.AMap || !myMap) {
return
}
setHoverItemPos({})
setHoverItem({})
const lnglat = item.location?.split(',').map((i: any) => +i) || []
myMap.setCenter(lnglat) // 定位到选中项
myMap.setZoom(17)
}
const handleSearch = (val: any) => {
const words = val.trim()
// console.log("words==", words);
setSeywords(words)
search({ keywords: words })
}
const search = (prms = {}) => {
const params = {
// keywords: keywords,
// city: 'beijing',
offset: 25,
page: 1,
...prms
}
queryBykeyword(params).then((data: any) => {
if (data?.status == 1 && data.pois.length) {
setResult(data.pois)
const item = data.pois?.[0] // 默认取搜索结果第一项为活跃项
if (!window.AMap || !myMap) {
return
}
const lnglat = item.location?.split(',').map((i: any) => +i) || []
myMap.setCenter(lnglat)
markResult(data.pois) // 将搜索结果 Mark 到地图上
} else {
setResult([])
}
})
}
const markResult = (resultList: any[]) => {
if (!window.AMap || !myMap) {
return
}
setHoverItemPos({})
setHoverItem({})
const markers = resultList?.map(item => {
const lnglatn = item.location?.split(',').map((i: any) => +i) || []
const marker = new window.AMap.Marker({
icon: "https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png",
position: lnglatn,
offset: new window.AMap.Pixel(-10, -30),
extData: { // marker 的额外数据
...item
},
});
marker.on('click', (e: any) => { // 单独给 marker 绑定事件
// console.log("ev click", e);
const { target = {}, } = e
const { w = {} } = target
const { extData = {} } = w
// const { lng, lat } = lnglat
// myMap.setCenter([lng, lat])
// setCurrentItem(extData)
const { location = '' } = extData
sendLnglat(location.split(',')) // 获取点击项坐标
});
marker.on('mousemove', (e: any) => {
// console.log("ev mousemove", e);
const { target = {}, pixel } = e
const { w = {} } = target
const { extData = {} } = w
setHoverItemPos(pixel) // 获取 hover 项坐标等信息以显示
setHoverItem(extData)
})
// marker.on('mouseout', (e: any) => {
// console.log("ev mouseout", e);
// })
return marker
})
myMap.clearMap(); // mark 前先 clear
myMap.add(markers)
}
const Options = result.map((item: any) => <Option key={item.id} value={item.id} item={item} >{item.name}</Option>)
return (
<div style={{ width: '100%', height: 300, position: 'relative' }}>
<div ref={refMap} style={{ width: '100%', height: "100%" }} > </div>
<div style={{
...styleTip,
right: hoverItemPos.x ? `calc(100% - ${hoverItemPos.x}px` : undefined,
top: hoverItemPos.y,
transform: `${hoverItemPos.x ? 'scale(1)' : 'scale(0.001)'} translateX(50%) translateY(calc(-50% - 10px ))`
}}
>{hoverItem.name}</div>
<div style={{ ...styleSearch }} >
<Select
className="amap-search"
showSearch
// value={"Homepp"}
size="large"
placeholder={"请输入"}
defaultActiveFirstOption={false}
showArrow={false}
filterOption
onSearch={handleSearch}
onChange={handleChange}
notFoundContent={null}
optionFilterProp="children"
// style={{ pointerEvents: 'all' }}
dropdownStyle={{ backgroundColor: 'rgba(225,225,225,0.8)' }}
listHeight={220}
>
{Options}
</Select>
<span style={{ ...styleHandle }} onClick={() => { search({ keywords }) }}>搜索</span>
</div>
</div >)
}
export default Amap