使用Vue3+TS玩转高德地图
不知道大家在开发的时候,是否遇到过需要利用地图去展示一些地理位置信息,而又不知道从哪里下手,下面我将使用高德地图带大家完成地图相关内容的开发
内容主要有:
地图的初始化,
地图内置插件的使用(鹰眼,图层切换,放大缩小,比例尺,视图位置),
地点搜索(自定义,不使用内置组件,不方便),
搜索中心地点方圆公里内容并展示内容(可配置:1公里,2公里,n公里),
地图打点(自定义打点内容),
获取个人当前位置坐标,
自定义弹窗信息展示,
行驶路径的轨迹回放(包括开始,结束,暂停,继续)
1.地图的初始化(需要去高德地图申请开发者的秘钥,然后再进行开发,这里默认已经拥有了开发者秘钥)
//下包
npm i amap/amap-jsapi-loader
2.初始化地图(plugins其实就是和webpack一样的插件,我们引入可以实现多种不同的功能)
<template>
<div id="Map"></div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
// 挂载秘钥
window._AMapSecurityConfig = {
securityJsCode: "xxxxx",
};
const initMap = async () => {
const AMap = await AMapLoader.load({
key: "xxxxxx", //申请好的 Web 端开发者 Key,首次调用 load 时必填
version: "2.0", //指定要加载的 JS API 的版本,缺省时默认为 1.4.15
plugins: [
"AMap.Scale",
"AMap.ToolBar",
"AMap.ControlBar",
"AMap.HawkEye",
"AMap.MapType",
"AMap.PlaceSearch",
"AMap.AutoComplete",
"AMap.Geolocation",
"AMap.CitySearch",
"AMap.MarkerCluster",
"AMap.MoveAnimation",
], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['AMap.Scale','...','...']
});
map = new AMap.Map("Map", {
zoom: 17, //地图放大程度
resizeEnable: true,
viewMode: "3D", //设置地图模式
center: [116.397428, 39.90923], // 初始化地图中心点位置
});
};
onMounted(() => {
initMap();
});
</script>
<style scoped lang="less">
#Map {
width: 100%;
height: 100%;
}
</style>
此时就可以看到一个地图在页面上显示了
下面可以进行深度开发,实现我描述的功能(这里直接贴全部代码,粘贴即用,这里我就不进行详细解析了,后续会在B站出一个视频,大家可以结合在这里慢慢看)
<template>
<div id="Map"></div>
<div class="control">
<a-checkbox-group direction="vertical" @change="change" v-model="control">
<a-checkbox value="1">比例尺</a-checkbox>
<a-checkbox value="2">工具条</a-checkbox>
<a-checkbox value="3">工具条方向盘</a-checkbox>
<a-checkbox value="4">鹰眼</a-checkbox>
<a-button type="primary" @click="getMyAddress"> 获取当前地址 </a-button>
<div class="circleSize">
<a-button type="primary" @click="updateRadius(1000)"> 1000 </a-button>
<a-button type="primary" @click="updateRadius(2000)"> 2000 </a-button>
<a-button type="primary" @click="updateRadius(3000)"> 3000 </a-button>
</div>
<div class="circleSize">
<a-button type="primary" @click="beginTrace"> 开始轨迹 </a-button>
<a-button type="primary" @click="pauseAnimation"> 暂停轨迹 </a-button>
<a-button type="primary" @click="resumeAnimation"> 继续轨迹 </a-button>
<a-button type="primary" @click="stopAnimation"> 停止轨迹 </a-button>
</div>
</a-checkbox-group>
</div>
<div class="search">
<a-select v-model="location" @search="getAddressInfo" allow-search>
<a-option
v-for="item in addressinfo"
:value="item.id"
@click="goAddress(item)"
>
<img :src="item?.photos[0]?.url" alt="" class="imgs" />
{{ `${item.cityname}-${item.address}-${item.name}` }}
</a-option>
</a-select>
</div>
<!-- <div id="panel"></div> -->
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { Message } from "@arco-design/web-vue";
import AMapLoader from "@amap/amap-jsapi-loader";
// 挂载秘钥
window._AMapSecurityConfig = {
securityJsCode: "xxxxx",
};
const control = ref(["1", "2", "3", "4"]);
const location = ref("");
const addressinfo = ref<any>([]);
const change = (val: any) => {
control.value = val;
toggle();
};
const toggle = () => {
const controls: any = {
scale: { instance: scale.value, identifier: "1" },
toolbar: { instance: toolbar.value, identifier: "2" },
controlBar: { instance: controlBar.value, identifier: "3" },
hawEye: { instance: hawEye.value, identifier: "4" },
};
for (const key in controls) {
const controlInstance = controls[key].instance;
const identifier = controls[key].identifier;
if (control.value.includes(identifier)) {
controlInstance.show();
} else {
controlInstance.hide();
}
}
};
// 自动聚集往中心点
const updateCenter = (newLocation) => {
const lnglat = new AMapOutside.LngLat(newLocation.lng, newLocation.lat);
map.setCenter(lnglat);
};
const addressCenter = ref<any>([]);
// 去往当前gps点位
const goAddress = (item) => {
map.clearMap();
const { photos, cityname, address, name, location } = item;
addressCenter.value = [location.lng, location.lat];
const markerContent = `<div class='casemark''>
案发点位
<img src="${photos[0]?.url}" style='width: 50px;
height: 50px;'>
<div>
<div>${cityname}</div>
<div>${address}</div>
<div>${name}</div>
</div>
</div>`;
const position = new AMapOutside.LngLat(location.lng, location.lat); //Marker 经纬度
const marker = new AMapOutside.Marker({
position: position,
content: markerContent, //将 html 传给 content
offset: new AMapOutside.Pixel(-13, -30), //以 icon 的 [center bottom] 为原点
});
map.add(marker);
getCaseAddress();
setCircle(1000);
updateCenter(location);
};
// 获取周边信息
const getCaseAddress = () => {
// const point = []
addressinfo.value.forEach((item, index) => {
const { photos, cityname, address, name, location } = item;
const position = new AMapOutside.LngLat(location.lng, location.lat); //Marker 经纬度
// 证据点位
// point.push({weight: 8, lnglat: [location.lng, location.lat]})
const marker = new AMapOutside.Marker({
position: position,
icon: "//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png",
anchor: "bottom-center",
offset: new AMapOutside.Pixel(0, 0),
});
marker.setMap(map);
// 设置鼠标划过点标记显示的文字提示
marker.setTitle("我是marker的title");
// 设置label标签
// label默认蓝框白底左上角显示,样式className为:amap-marker-label
marker.setLabel({
direction: "right",
offset: new AMapOutside.Pixel(10, 0), //设置文本标注偏移量
content: `<div class='info'>证据${index}${cityname}-${address}-${name}</div>`, //设置文本标注内容
});
const markerContent = `<div class="evi"'>
<img src="${photos[0]?.url}">
<div class='eviMarks'>
<div>证据点位</div>
<div>${cityname}</div>
<div>${address}</div>
<div>${name}</div>
</div>
</div>`;
const infoWindow = new AMapOutside.InfoWindow({
position,
content: markerContent,
offset: new AMapOutside.Pixel(16, -45),
});
marker.on("click", () => {
infoWindow.open(map);
});
});
// MarkerCluster.setData(point);
};
// 搜索范围
const Circle = ref();
const updateRadius = (number) => {
Circle.value.setRadius(number);
};
const setCircle = (radius = 20) => {
if (addressCenter.value.length !== 2) {
return;
}
Circle.value = new AMapOutside.Circle({
center: addressCenter.value, //圆心
radius: radius, //半径
strokeColor: "white", //轮廓线颜色
strokeWeight: 2, //轮廓线宽度
strokeOpacity: 0.5, //轮廓线透明度
fillColor: "rgba(0,0,255,1)", //圆点填充颜色
fillOpacity: 0.5, //圆点填充透明度
zIndex: 10, //圆点覆盖物的叠加顺序
cursor: "pointer", //鼠标悬停时的鼠标样式
});
//圆形 Circle 对象添加到 Map
map.add(Circle.value);
map.setFitView();
};
const getAddressInfo = (val) => {
placeSearch.value.search(val, (status, result) => {
if (status !== "error") {
addressinfo.value = result?.poiList?.pois;
}
});
};
const getMyAddress = () => {
geolocation.value.getCurrentPosition(function (status, result) {
Message.success(result);
});
// citySearch.value.getLocalCity(function (status, result) {
// if (status === "complete" && result.info === "OK") {
// // 查询成功,result即为当前所在城市信息
// console.log(result);
// Message.success(result.city);
// }
// });
};
// 轨迹回放
const traceMarker = ref();
let lineArr = [
[116.478935, 39.997761],
[116.478939, 39.997825],
[116.478912, 39.998549],
[116.478912, 39.998549],
[116.478998, 39.998555],
[116.478998, 39.998555],
[116.479282, 39.99856],
[116.479658, 39.998528],
[116.480151, 39.998453],
[116.480784, 39.998302],
[116.480784, 39.998302],
[116.481149, 39.998184],
[116.481573, 39.997997],
[116.481863, 39.997846],
[116.482072, 39.997718],
[116.482362, 39.997718],
[116.483633, 39.998935],
[116.48367, 39.998968],
[116.484648, 39.999861],
];
const TOTAL_DURATION = 20 * 1000; // 总播放时间为20秒,转换为毫秒
const SEGMENTS_COUNT = lineArr.length - 1; // 总段数(最后一个点不需要移动)
const beginTrace = () => {
const durationPerSegment = Math.floor(TOTAL_DURATION / SEGMENTS_COUNT); // 每一段的平均时长
traceMarker.value.moveAlong(lineArr, {
duration: durationPerSegment, // 根据总时长和段数计算的时长
autoRotation: true,
});
};
//
const pauseAnimation = () => {
traceMarker.value.pauseMove();
}
const resumeAnimation = () => {
traceMarker.value.resumeMove();
}
const stopAnimation = () => {
traceMarker.value.stopMove();
}
const drawTrace = () => {
traceMarker.value = new AMapOutside.Marker({
map: map,
position: lineArr[0],
icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
offset: new AMapOutside.Pixel(-13, -26),
});
// 绘制轨迹
new AMapOutside.Polyline({
map: map,
path: lineArr,
showDir: true,
strokeColor: "#28F", //线颜色
// strokeOpacity: 1, //线透明度
strokeWeight: 6, //线宽
// strokeStyle: "solid" //线样式
});
// 行走过的颜色和设置
const passedPolyline = new AMapOutside.Polyline({
map: map,
strokeColor: "#AF5", //线颜色
strokeWeight: 6, //线宽
});
traceMarker.value.on("moving", function (e) {
passedPolyline.setPath(e.passedPath);
map.setCenter(e.target.getPosition(), true);
});
map.setFitView();
}
let map: any = null;
let AMapOutside: any = null;
let MarkerCluster: any = null; //点聚合
const toolbar = ref();
const scale = ref();
const controlBar = ref();
const hawEye = ref();
const placeSearch = ref();
const geolocation = ref();
const citySearch = ref();
const initMap = async () => {
const AMap = await AMapLoader.load({
key: "xxxxx", //申请好的 Web 端开发者 Key,首次调用 load 时必填
version: "2.0", //指定要加载的 JS API 的版本,缺省时默认为 1.4.15
plugins: [
"AMap.Scale",
"AMap.ToolBar",
"AMap.ControlBar",
"AMap.HawkEye",
"AMap.MapType",
"AMap.PlaceSearch",
"AMap.AutoComplete",
"AMap.Geolocation",
"AMap.CitySearch",
"AMap.MarkerCluster",
"AMap.MoveAnimation",
], //需要使用的的插件列表,如比例尺'AMap.Scale',支持添加多个如:['AMap.Scale','...','...']
});
AMapOutside = AMap;
map = new AMap.Map("Map", {
zoom: 17,
resizeEnable: true,
viewMode: "3D", //设置地图模式
center: [116.397428, 39.90923], // 初始化地图中心点位置
});
drawTrace()
// 图层切换
const mapType = new AMap.MapType();
map.addControl(mapType); // 图层切换
toolbar.value = new AMap.ToolBar({
position: {
bottom: "110px",
left: "40px",
},
}); //放大缩小插件
map.addControl(toolbar.value);
scale.value = new AMap.Scale(); //比例尺
map.addControl(scale.value);
controlBar.value = new AMap.ControlBar({
position: {
bottom: "110px",
left: "100px",
},
});
map.addControl(controlBar.value); //视图位置
hawEye.value = new AMap.HawkEye({
opened: false,
});
map.addControl(hawEye.value); //鹰眼
geolocation.value = new AMap.Geolocation({
enableHighAccuracy: true, //是否使用高精度定位,默认:true
maximumAge: 0, //定位结果缓存0毫秒,默认:0
convert: true, //自动偏移坐标,偏移后的坐标为高德坐标,默认:true
buttonPosition: "LT", //定位按钮停靠位置,默认:'LB',左下角
buttonOffset: new AMap.Pixel(10, 20), //定位按钮与设置的停靠位置的偏移量,默认:Pixel(10, 20)
showMarker: true, //定位成功后在定位到的位置显示点标记,默认:true
showCircle: true, //定位成功后用圆圈表示定位精度范围,默认:true
panToLocation: true, //定位成功后将定位到的位置作为地图中心点,默认:true
zoomToAccuracy: true, //定位成功后调整地图视野范围使定位位置及精度范围视野内可见,默认:false
});
map.addControl(geolocation.value); // 定位组件
// 不那么精确的定位
citySearch.value = new AMap.CitySearch();
// 地址搜索
placeSearch.value = new AMap.PlaceSearch({
pageSize: 15, // 单页显示结果条数
pageIndex: 1, // 页码
city: "", // 兴趣点城市
citylimit: false, //是否强制限制在设置的城市内搜索
map: map, // 展现结果的地图实例
// panel: "panel", // 结果列表将在此容器中进行展示。
autoFitView: false, // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见
});
MarkerCluster = new AMap.MarkerCluster(map, [], {
gridSize: 20, // 聚合网格大小
maxClusterRadius: 50, // 聚合半径
zoomToClusterThreshold: 12, // 缩放到多少层级时开始聚合
});
};
onMounted(() => {
initMap();
});
</script>
<style scoped lang="less">
#Map {
width: 100%;
height: 100%;
}
.control {
top: 0;
position: absolute;
}
.mapType {
top: 0;
right: 200px;
position: absolute;
}
.search {
top: 10px;
left: 300px;
position: absolute;
width: 500px;
:deep(.arco-select-view-single) {
background-color: #fff;
}
}
:deep(.arco-select-option-content) {
display: flex;
align-items: center;
}
.imgs {
width: 50px;
height: 50px;
}
#panel {
top: 10px;
position: absolute;
right: 50px;
}
</style>