You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

266 lines
11 KiB

import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { forwardRef, useEffect, useImperativeHandle, useRef, useState, } from 'react';
import { compact, isArray, isEmpty } from 'lodash';
import { renderToString } from 'react-dom/server';
import { useReactive } from 'ahooks';
import { getStorage } from '@component/utils';
import { GDMap } from '../map';
import { HeatMapLayer } from '../layer';
import cluster_blue from './cluster_blue.png';
import marker_blue from './marker_blue.png';
import set_cluster from './cluster';
import style from './style.module.css';
export const MapMarker = forwardRef((props, ref) => {
const { data = [], icon = marker_blue, clusterIcon = cluster_blue, options = {}, onMarker, onCluster, district = false, isHeatMap = false, isMapStyle = false, isZoomMap = false, circle = false, distance = 1000, polygonOptions = {}, adcode = null, isCluster = true, loadedCallBack, } = props;
const position = !isEmpty(compact(getStorage('position') ? getStorage('position').split(',') : []))
? compact(getStorage('position').split(','))
: [116.398784, 39.910231];
const mapOptions = Object.assign({ center: position, zoom: 6 }, options);
const infoWindowRef = useRef(null);
const markersEle = useRef([]);
const districtEle = useRef(null);
const polygons = useRef([]);
const mapEle = useRef(null);
const circleRef = useRef(null);
const [styleStatus, setStyleStatus] = useState((options === null || options === void 0 ? void 0 : options.mapStyle) === 'amap://styles/darkblue');
const showHeatMap = useReactive({
show: false,
});
const clearMap = () => {
mapEle.current.clearMap();
};
/**
* marker点击事件
* @param event
*/
const onMarkerClick = (event) => {
const marker = event.target;
const position = marker.getPosition();
const extData = marker.getExtData();
if (mapEle.current && onMarker) {
onMarker(extData);
return;
}
setInfoWindow({
position,
extData,
});
};
function setInfoWindow({ position, extData }) {
var _a, _b, _c;
if (infoWindowRef.current.getIsOpen()) {
(_a = infoWindowRef.current) === null || _a === void 0 ? void 0 : _a.close();
}
(_b = infoWindowRef.current) === null || _b === void 0 ? void 0 : _b.setContent(renderInfoContent(extData));
(_c = infoWindowRef.current) === null || _c === void 0 ? void 0 : _c.open(mapEle.current, position);
mapEle.current.setCenter(position);
}
const createMaker = (item) => {
const marker = new AMap.Marker({
position: [item.lng, item.lat],
icon: item.icon,
clickable: true,
extData: item,
map: !isCluster && mapEle.current,
});
marker.on('click', onMarkerClick);
return marker;
};
const getMarkers = (data) => {
if (!infoWindowRef.current) {
infoWindowRef.current = new AMap.InfoWindow({
offset: new AMap.Pixel(10, -15),
autoMove: true,
});
}
return data.map((item) => createMaker(Object.assign({ icon: icon }, item)));
};
const setClusterEvent = () => {
return [
{
type: 'click',
eventHandle: (context, currentClusterObj) => {
let map = context.getMap();
if (map.getZoom() >= 15) {
let markers = currentClusterObj.markers, filterMarkers = [];
for (let i = markers.length - 1; i >= 0; i--) {
filterMarkers.unshift(markers[i].getExtData());
}
if (onCluster) {
onCluster(filterMarkers, (data) => {
setInfoWindow({
position: currentClusterObj.lnglat,
extData: data,
});
});
return;
}
setInfoWindow({
position: currentClusterObj.lnglat,
extData: filterMarkers,
});
}
},
},
];
};
const setMarkers = (data) => {
markersEle.current = getMarkers(data);
if (isCluster) {
try {
set_cluster(mapEle.current, markersEle.current, setClusterEvent(), clusterIcon, district, circle);
}
catch (e) {
console.log('e', e);
}
}
};
// 缩放地图
const setMapView = (type) => {
if (!mapEle.current) {
return;
}
let zoom = mapEle.current.getZoom();
if (type === 'add') {
zoom++;
zoom = zoom >= 18 ? 18 : zoom;
}
else {
zoom--;
zoom = zoom <= 1 ? 1 : zoom;
}
mapEle.current.setZoom(zoom);
};
//热力图切换
const toggleHeatMap = () => {
var _a, _b;
if (!mapEle.current) {
return;
}
showHeatMap.show = !showHeatMap.show;
(_a = mapEle.current) === null || _a === void 0 ? void 0 : _a.clearInfoWindow();
(_b = mapEle.current) === null || _b === void 0 ? void 0 : _b.cluster.clearMarkers();
if (!showHeatMap.show) {
setMarkers(data);
}
};
const setStyle = () => {
if (!mapEle.current) {
return;
}
const status = !styleStatus;
mapEle.current.setMapStyle('amap://styles/' + (status ? 'darkblue' : 'fresh'));
setStyleStatus(status);
};
/**
* Infowin窗口渲染内容
* @returns {string}
*/
const renderInfoContent = (data) => {
const { renderInfoContent } = props;
const d = isArray(data) ? data : [data];
if (renderInfoContent) {
return renderInfoContent(d);
}
return renderToString(_jsx("ul", Object.assign({ className: style['popup_list'] }, { children: d.map((item, key) => {
return (_jsx("li", Object.assign({ title: item === null || item === void 0 ? void 0 : item.name }, { children: (item === null || item === void 0 ? void 0 : item.url) ? (_jsx("a", Object.assign({ target: "_blank", href: item === null || item === void 0 ? void 0 : item.url }, { children: item === null || item === void 0 ? void 0 : item.name }))) : (item === null || item === void 0 ? void 0 : item.name) }), key));
}) })));
};
/**
* 地图加载完成后的回调
* @param map
*/
const onMapLoaded = (map) => {
init(map, data);
};
const init = (map, data) => {
mapEle.current = map;
if (district) {
drawBounds({
map,
district: districtEle.current,
polygons: polygons.current,
adcode: adcode || getStorage('code'),
polygonOptions: polygonOptions,
});
}
if (!showHeatMap.show) {
setMarkers(data);
}
if (circle) {
circleRef.current = new AMap.Circle({
center: mapOptions.center,
strokeColor: '#00a5e6',
strokeOpacity: 1,
strokeWeight: 2,
fillColor: '#bbd4e3',
fillOpacity: 0.35, //填充透明度
});
setCircle(distance);
}
loadedCallBack && loadedCallBack(map);
};
function setCircle(distance) {
circleRef.current.setRadius(distance);
mapEle.current.add(circleRef.current);
// mapEle.current.setFitView([circleRef.current, ...markersEle.current]);
mapEle.current.setFitView();
}
useEffect(() => {
if (mapEle.current) {
clearMap();
init(mapEle.current, data);
}
}, [mapEle.current, data]);
useImperativeHandle(ref, () => {
return {
setInfoWindow,
clearMap,
};
});
return (_jsxs("div", Object.assign({ className: style['map-container'] }, { children: [_jsx(GDMap, Object.assign({ aMapLoca: true, aMapUI: true, containerClass: style['map-container'], options: mapOptions, loadedCallBack: onMapLoaded }, { children: _jsx(HeatMapLayer, { data: data, open: showHeatMap.show, heatmapOptions: {
zIndex: 11,
radius: 50,
opacity: [0, 0.8],
gradient: {
0.5: 'blue',
0.65: 'rgb(117,211,248)',
0.7: 'rgb(0, 255, 0)',
0.9: '#ffea00',
1.0: 'red',
},
} }) })), _jsxs("ul", Object.assign({ className: style['map_action'] }, { children: [isHeatMap && (_jsx("li", Object.assign({ onClick: toggleHeatMap, className: style['switch_style'], style: { listStyle: 'none' } }, { children: showHeatMap.show ? '点聚合' : '热力图' }))), isMapStyle && (_jsx("li", Object.assign({ onClick: setStyle, className: style['hot_style'], style: { listStyle: 'none' } }, { children: styleStatus ? '标准' : '炫黑' }))), isZoomMap && (_jsxs("li", Object.assign({ className: style['too-bar'] }, { children: [_jsx("p", Object.assign({ onClick: () => setMapView('add') }, { children: "+" })), _jsx("p", Object.assign({ onClick: () => setMapView('sub') }, { children: "-" }))] })))] }))] })));
});
function drawBounds({ map, adcode, district, polygons, polygonOptions }) {
//加载行政区划插件
AMap.plugin('AMap.DistrictSearch', () => {
if (!district) {
//实例化DistrictSearch
district = new AMap.DistrictSearch({
zIndex: 10,
subdistrict: 1,
extensions: 'all',
level: 'district',
showbiz: false, // 最后一级返回街道信息
});
}
//行政区查询
district.search(adcode, function (_status, result) {
map.remove(polygons); //清除上次结果
polygons = [];
if (isEmpty(result)) {
return;
}
const bounds = result.districtList[0].boundaries;
if (bounds) {
for (let i = 0, l = bounds.length; i < l; i++) {
//生成行政区划polygon
const polygon = new AMap.Polygon(Object.assign({ strokeWeight: 1, path: bounds[i], fillOpacity: 0.4, fillColor: '#80d8ff', strokeColor: '#0091ea' }, polygonOptions));
polygons.push(polygon);
}
}
map.add(polygons);
map.setFitView(polygons); //视口自适应
});
});
}