314 lines
12 KiB
TypeScript
314 lines
12 KiB
TypeScript
import AMapLoader from '@amap/amap-jsapi-loader';
|
|
import china from '/@/assets/lngLat/china.ts';
|
|
import chinaInner from '/@/assets/lngLat/chinaInner.ts';
|
|
import { createCircle, createIcon, getCenter, getLonLat, typeToIcon } from '/@/assets/mapUtils/commonFun.ts';
|
|
import { aircraftContent, alarmIcon } from '/@/components/chinaMap/chinaHooks.ts';
|
|
import { isFunction } from '/@/utils/is.ts';
|
|
import { Callback, ExtDataType, InitMap, MarkerOption, ResultType } from '/@/assets/mapUtils/mapFunTypes.ts';
|
|
import { defaultOption, getZoom, mapKey, mapPlugin } from '/@/assets/mapUtils/mapConstant.ts';
|
|
|
|
let AMap = null;
|
|
export const Map = {
|
|
map: null,
|
|
overlayGroup: null, // 地图中marker
|
|
circleGroup: null, //直升机背景圆
|
|
cluster: null, //直升机marker点聚合图层
|
|
airMarkerList: [], //直升机markerList
|
|
placeSearch: null, //地点查询
|
|
marker: null, // 健康终端报警
|
|
infoWindow: null, //地图弹窗
|
|
/**
|
|
* @desc 地图舒适化
|
|
* @param el dom元素 id选择器
|
|
* @param option 地图配置
|
|
*/
|
|
initMap({ el, option }: InitMap) {
|
|
return new Promise((resolve) => {
|
|
AMapLoader.load({
|
|
key: mapKey, // 申请好的Web端开发者Key,首次调用 load 时必填
|
|
version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
|
|
plugins: mapPlugin, // 需要使用的的插件列表,如比例尺'AMap.Scale'等
|
|
}).then((res) => {
|
|
AMap = res;
|
|
const { zoom, center, mapStyle } = { ...defaultOption, ...option };
|
|
//基本地图加载
|
|
this.map = new AMap.Map(el, {
|
|
resizeEnable: true,
|
|
center: center,
|
|
zoom: zoom,
|
|
mapStyle: 'amap://styles/' + mapStyle,
|
|
version: '2.0',
|
|
});
|
|
// 异步同时加载多个插件
|
|
new AMap.plugin(mapPlugin, () => {
|
|
this.drawInnerLine();
|
|
this.drawOutLine();
|
|
});
|
|
resolve();
|
|
});
|
|
});
|
|
} /**
|
|
* @desc 中国外层边界线
|
|
*/,
|
|
drawOutLine() {
|
|
let geoJson = new AMap.GeoJSON({
|
|
geoJSON: china,
|
|
getPolygon: function (geoJson: string, lngLats: any) {
|
|
return new AMap.Polyline({
|
|
path: lngLats[0],
|
|
strokeColor: '#2384dd',
|
|
strokeWeight: 3,
|
|
// lineJoin: 'round', //折线拐点的绘制样式
|
|
isOutline: false,
|
|
// borderWeight: 2,
|
|
// outlineColor: '#6ccffe',
|
|
});
|
|
},
|
|
});
|
|
this.map.add(geoJson);
|
|
} /**
|
|
* @desc 中国内层边界线
|
|
*/,
|
|
drawInnerLine() {
|
|
let geoJson = new AMap.GeoJSON({
|
|
geoJSON: chinaInner,
|
|
getPolygon: function (geoJson: string, lngLats: any) {
|
|
return new AMap.Polyline({
|
|
path: lngLats[0],
|
|
// strokeColor: '#57b2f8',
|
|
// strokeColor: '#2BA5FF',
|
|
// strokeColor: '#3d6eff',
|
|
// strokeWeight: 2,
|
|
// zIndex: 10,
|
|
isOutline: true,
|
|
outlineColor: '#2692fc',
|
|
borderWeight: 1,
|
|
strokeColor: '#88b9f8',
|
|
strokeWeight: 1,
|
|
strokeOpacity: 0.8,
|
|
});
|
|
},
|
|
});
|
|
this.map.add(geoJson);
|
|
},
|
|
/**
|
|
* @desc 设置地图级别与中心点
|
|
* @param center 【lon,lat】
|
|
* @param zoom 地图层级
|
|
* */
|
|
setZoomCenter(center, zoom = 12) {
|
|
this.map && this.map.setZoomAndCenter(zoom, center);
|
|
},
|
|
/**
|
|
* @desc 清空当前地图上除了边界线的覆盖物
|
|
*/
|
|
removeOverlayGroup() {
|
|
this.clearAircraft();
|
|
this.clearOverlay();
|
|
this.clearAirRange();
|
|
this.clearMarker(); //
|
|
if (this.airMarkerList) {
|
|
this.airMarkerList = [];
|
|
}
|
|
this.clearActiveHospital();
|
|
this.clearInfoModal();
|
|
// this.map.remove(this.airMarkerList);
|
|
}, //
|
|
/**
|
|
* @desc 创建覆盖物组,用于批量处理点 (控制显隐,点击事件等)
|
|
* @param result
|
|
* @param extData
|
|
* @param callback
|
|
*/
|
|
createOverlay(result: ResultType[], extData?: ExtDataType, callback?: Callback) {
|
|
this.removeOverlayGroup();
|
|
this.overlayGroup = new AMap.OverlayGroup();
|
|
let list = getLonLat(result);
|
|
let center = getCenter(list);
|
|
let zoom = getZoom(list);
|
|
this.setZoomCenter(center, zoom);
|
|
for (let i = 0; i < result.length; i++) {
|
|
let { type, lon, lat, lng } = result[i];
|
|
if (lng) {
|
|
lon = lng;
|
|
}
|
|
if (!lon || !lat || !type) {
|
|
continue;
|
|
}
|
|
// 创建一个 Icon
|
|
let startIcon = typeToIcon(type);
|
|
// 将 icon 传入 marker
|
|
let startMarker = new AMap.Marker({
|
|
// 点的坐标
|
|
position: [lon, lat], // 指定点的icon,也可以是个url ,但这样就不能对图片进行设置了
|
|
icon: startIcon, //启用点击事件 如果需要点击事件,必须开启
|
|
clickable: true, //点额外携带的数据,用户自定义属性,支持JavaScript API任意数据类型
|
|
offset: [-18, -32],
|
|
maxZoom: 14,
|
|
extData: result[i],
|
|
label: {
|
|
content: isFunction(extData?.content) && extData?.content(result[i]),
|
|
},
|
|
...extData?.extOption,
|
|
});
|
|
// 可以调用setExtData()设置自定义属性
|
|
//将组 挂载到地图上
|
|
this.overlayGroup.setMap(this.map);
|
|
//将需要批量控制的点放到一个组中,通过控制组,就可以操作组内所有所有覆盖物
|
|
this.overlayGroup.addOverlay(startMarker);
|
|
}
|
|
|
|
this.overlayGroup.on('click', function (e) {
|
|
//拿到点中携带的数据
|
|
if (!isFunction(callback)) return;
|
|
callback(e.target.getExtData());
|
|
});
|
|
},
|
|
clearOverlay() {
|
|
if (this.overlayGroup) {
|
|
this.map.remove(this.overlayGroup);
|
|
this.overlayGroup.setMap(null);
|
|
this.overlayGroup = null;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @desc 创建直升机marker
|
|
* @param result
|
|
*/
|
|
createAircraft(result: ResultType[]) {
|
|
this.removeOverlayGroup();
|
|
this.clearActiveHospital();
|
|
// debugger;
|
|
if (!Array.isArray(result) && result.length == 0) return;
|
|
this.createAirRange(result);
|
|
let that = this;
|
|
let arr = result.map((item) => ({ weight: 4, lnglat: [item.lon, item.lat], params: item.name }));
|
|
let count = 4;
|
|
this.cluster = new AMap.MarkerClusterer(
|
|
that.map, // 地图实例
|
|
arr,
|
|
{
|
|
renderMarker: (context) => {
|
|
let factor = Math.pow(context.count / count, 1 / 18);
|
|
let div = document.createElement('div');
|
|
div.className = 'render-air';
|
|
let Hue = 180 - factor * 180;
|
|
let size = Math.round(30 + Math.pow(context.count / count, 1 / 5) * 20);
|
|
div.style.width = div.style.height = size + 'px';
|
|
div.innerHTML = aircraftContent() || context.count;
|
|
div.style.color = '#fff';
|
|
div.style.fontSize = '14px';
|
|
context.marker.setOffset(new AMap.Pixel(-size / 2, -size / 2));
|
|
context.marker.setContent(div);
|
|
// this.airMarkerList.push(context.marker);
|
|
// context.marker.on('click', () => {
|
|
// console.log('data', context);
|
|
// });
|
|
},
|
|
}
|
|
);
|
|
// this.cluster.setMap(this.map);
|
|
},
|
|
clearAircraft() {
|
|
if (this.cluster) {
|
|
this.cluster.setMap(null);
|
|
// this.map.remove(this.cluster);
|
|
// this.cluster = null;
|
|
}
|
|
} /**
|
|
* @desc 飞机范围
|
|
* @param list
|
|
*/,
|
|
createAirRange(list: ResultType[]) {
|
|
this.removeOverlayGroup();
|
|
this.circleGroup = new AMap.OverlayGroup();
|
|
for (let i = 0; i < list.length; i++) {
|
|
let circle = createCircle({ lon: list[i].lon, lat: list[i].lat });
|
|
this.circleGroup.setMap(this.map);
|
|
this.circleGroup.addOverlay(circle);
|
|
}
|
|
},
|
|
clearAirRange() {
|
|
if (this.circleGroup) {
|
|
this.map.remove(this.circleGroup);
|
|
this.circleGroup = null;
|
|
}
|
|
} /**
|
|
* @desc 地方医院医疗点显示
|
|
* @param cityCode 城市code
|
|
* @param keywords 搜索名称
|
|
*/,
|
|
createActiveHospital(cityCode: string, keywords = '医院') {
|
|
this.removeOverlayGroup();
|
|
this.clearActiveHospital();
|
|
if (!cityCode) return;
|
|
if (!this.placeSearch) {
|
|
this.placeSearch = new AMap.PlaceSearch({
|
|
pageSize: 30, // 单页显示结果条数
|
|
pageIndex: 1, // 页码
|
|
city: cityCode, // 兴趣点城市
|
|
citylimit: true, //是否强制限制在设置的城市内搜索
|
|
map: this.map, // 展现结果的地图实例
|
|
// panel: 'map_hospital', // 结果列表将在此容器中进行展示。
|
|
autoFitView: false, // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
|
|
});
|
|
}
|
|
this.placeSearch.setCity(cityCode);
|
|
//关键字查询
|
|
this.placeSearch.search(keywords);
|
|
},
|
|
clearActiveHospital() {
|
|
if (this.placeSearch) {
|
|
this.placeSearch.clear();
|
|
}
|
|
},
|
|
createMarker(option: MarkerOption, callbck?: Callback) {
|
|
this.clearMarker();
|
|
let { lon, lat, zoom = 12 } = option;
|
|
const icon = createIcon({ icon: alarmIcon, iconSize: [36, 42], imageSize: [36, 42] });
|
|
let str = option?.realName && option?.eventType_dictText ? `${option?.realName},${option?.eventType_dictText}` : `${option?.realName}`;
|
|
this.marker = new AMap.Marker({
|
|
position: [lon, lat],
|
|
icon: icon,
|
|
offset: new AMap.Pixel(0, 0), //设置偏移量
|
|
label: {
|
|
content: `<div class="alarm-content" >
|
|
<div>${str}</div>
|
|
</div>`,
|
|
offset: new AMap.Pixel(0, -9),
|
|
direction: 'top',
|
|
},
|
|
});
|
|
this.map.add(this.marker);
|
|
this.map.setZoomAndCenter(zoom, [lon, lat]);
|
|
this.marker.on('click', callbck);
|
|
},
|
|
clearMarker() {
|
|
if (this.marker) {
|
|
this.marker?.setMap(null);
|
|
this.marker = null;
|
|
}
|
|
},
|
|
/**
|
|
* @desc 创建地图详情弹窗
|
|
*
|
|
* */
|
|
createInfoModal({ option, content }) {
|
|
let { lat, lng } = option;
|
|
this.infoWindow = new AMap.InfoWindow({
|
|
position: [lng, lat],
|
|
offset: new AMap.Pixel(-5, -25),
|
|
content: content,
|
|
closeWhenClickMap: true,
|
|
});
|
|
this.infoWindow.open(this.map);
|
|
},
|
|
clearInfoModal() {
|
|
if (this.infoWindow) {
|
|
this.infoWindow?.setMap(null);
|
|
this.infoWindow = null;
|
|
}
|
|
},
|
|
};
|