前提: 需要注册高德开放平台,之后创建应用并且开通
Web端(JS API)
平台,然后拿到securityJsCode
和key
1. 基础抽取(还原示例)
1.1 组件代码
代码说明:
- 需要修改
securityJsCode
和key
为自己的allowCollision
为标注是否避让marker,默认为false不避让markers
为地图上的标记数组layer
为一个标注层,可以理解为一个图层- 流程其实就是将
markers
装载到layer
再将layer
装载到map就可以实现了this.map.setFitView(null, false, [100, 150, 10,10]);
- 根据地图上添加的覆盖物分布情况,自动缩放地图到合适的视野级别,参数均可缺省。
overlayList
为覆盖物数组,缺省时为当前地图上添加的所有覆盖物图层,immediately
代表是否需要动画过程,avoid
代表上下左右的像素避让宽度,maxZoom
代表fitView之后的最大级- 参数说明:
setFitView(overlays, immediately, avoid, maxZoom)
- overlays
(Array<Overlay>)
覆盖物- immediately
(Boolean = false)
是否立即过渡- avoid
(Array<Number> = [60,60,60,60])
四周边距,上、下、左、右- maxZoom
(Number = zooms[1])
最大 zoom 级别allowCollisionFunc
和notAllowCollisionFunc
方法我没有使用,主要作用是控制标注避让marker
- 如果需要这个功能新建两个按钮,点击事件绑定这个两个方法即可;
toggleBtn
方法是修改控制标注避让按钮的是否使用(disable)
- 如果需要vue实现这个功能只需要将对应的按钮的disable绑定为
allowCollision
即可;
<template><div id="container"></div>
</template><script>//这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)//例如: import 《组件名称》 from '《组件路径》 ';import AMapLoader from "@amap/amap-jsapi-loader";import moment from "moment";import {getTrackList} from '@/services/attendance/statistics.js'// 设置安全密钥window._AMapSecurityConfig = {securityJsCode: 'xxxx你的securityJsCodexxxx',}export default {name: 'PositionContainer',//import 引入的组件需要注入到对象中才能使用components: {},props: {},data() {//这里存放数据return {AMap: null,//此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。map: null,mouseTool: null,marker: null,allowCollision: false,//标注避让markermarkers: [],layer: null,};},//计算属性 类似于 data 概念computed: {},//监控 data 中的数据变化watch: {},//方法集合methods: {allowCollisionFunc () {this.allowCollision = true;this.layer.setAllowCollision(true);this.toggleBtn();},notAllowCollisionFunc () {this.allowCollision = false;this.layer.setAllowCollision(false);this.toggleBtn();},toggleBtn (){var allowCollisionBtn = document.getElementById('allowCollision');var notAllowCollisionBtn = document.getElementById('notAllowCollision');var disableClass = 'disable';if(this.allowCollision){allowCollisionBtn.classList.add(disableClass);notAllowCollisionBtn.classList.remove(disableClass);}else {allowCollisionBtn.classList.remove(disableClass);notAllowCollisionBtn.classList.add(disableClass);}},initMarkers(AMap) {// 设置一个图标对象var icon = {// 图标类型,现阶段只支持 image 类型type: 'image',// 图片 urlimage: 'https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png',// 图片尺寸size: [64, 30],// 图片相对 position 的锚点,默认为 bottom-centeranchor: 'center',};var textStyle = {fontSize: 12,fontWeight: 'normal',fillColor: '#22886f',strokeColor: '#fff',strokeWidth: 2,fold: true,padding: '2, 5',};var LabelsData = [{name: '自提点1',position: [116.461009, 39.991443],zooms: [10, 20],opacity: 1,zIndex: 10,fold: true,icon,text: {// 要展示的文字内容content: '中邮速递易',// 文字方向,有 icon 时为围绕文字的方向,没有 icon 时,则为相对 position 的位置direction: 'right',// 在 direction 基础上的偏移量offset: [-20, -5],// 文字样式style: {// 字体大小fontSize: 12,// 字体颜色fillColor: '#22886f',//strokeColor: '#fff',strokeWidth: 2,fold: true,padding: '2, 5',}}},{name: '自提点2',position: [116.466994, 39.984904],zooms: [10, 20],opacity: 1,zIndex: 16,icon,text: {content: '丰巢快递柜-花家地北里',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点3',position: [116.472914, 39.987093],zooms: [10, 20],opacity: 1,zIndex: 8,icon,text: {content: '丰巢快递柜-中环南路11号院',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点4',position: [116.471814, 39.995856],zooms: [10, 20],opacity: 1,zIndex: 23,icon,text: {content: '丰巢快递柜-合生麒麟社',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点5',position: [116.469639, 39.986889],zooms: [10, 20],opacity: 1,zIndex: 6,icon,text: {content: '速递易快递柜-望京大厦',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点6',position: [116.467361, 39.996361],zooms: [10, 20],opacity: 1,zIndex: 5,icon,text: {content: 'E栈快递柜-夏都家园',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点7',position: [116.462327, 39.996071],zooms: [10, 20],opacity: 1,zIndex: 4,icon,text: {content: '丰巢自提柜-圣馨大地家园',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点8',position: [116.462349, 39.996067],zooms: [10, 20],opacity: 1,zIndex: 3,icon,text: {content: '丰巢快递-圣馨大地家园',direction: 'right',offset: [-20, -5],style: textStyle}},{name: '自提点9',position: [116.456474, 39.991563],zooms: [10, 20],zIndex: 2,opacity: 1,icon,text: {content: 'E栈快递柜-南湖渠西里',direction: 'right',offset: [-20, -5],style: textStyle}}];this.layer = new AMap.LabelsLayer({zooms: [3, 20],zIndex: 1000,// collision: false,// 设置 allowCollision:true,可以让标注避让用户的标注allowCollision: this.allowCollision,});this.layer.add(this.markers);// 图层添加到地图this.map.add(this.layer);// 初始化 labelMarkerfor (var i = 0; i < LabelsData.length; i++) {var curData = LabelsData[i];curData.extData = {index: i};var labelMarker = new AMap.LabelMarker(curData);this.markers.push(labelMarker);}// 将 marker 添加到图层this.layer.add(this.markers);this.map.setFitView(null, false, [100, 150, 10, 10]);this.toggleBtn()},initMap() {AMapLoader.load({key: "xxxx你的keyCodexxxx", // 申请好的Web端开发者Key,首次调用 load 时必填version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15"plugins": ["AMap.Scale","AMap.HawkEye","AMap.ToolBar","AMap.AutoComplete","AMap.PlaceSearch","AMap.ControlBar","AMap.MouseTool","AMap.DragRoute","AMap.MoveAnimation"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等}).then((AMap) => {this.AMap=AMapthis.map = new AMap.Map("container", { //设置地图容器idzoom: 15.8, // 初始化地图级别center: [116.469881, 39.993599], //中心点坐标 成都 104.065735, 30.659462showIndoorMap: false,});this.initMarkers(AMap);}).catch(e => {console.log(e);})},},//生命周期 - 创建完成(可以访问当前 this 实例)created() {// this.getLineArr(this.equipmentId,moment().valueOf())},//生命周期 - 挂载完成(可以访问 DOM 元素)mounted() {this.initMap();},//生命周期 - 创建之前beforeCreate() {},//生命周期 - 挂载之前beforeMount() {},//生命周期 - 更新之前beforeUpdate() {},//生命周期 - 更新之后updated() {},//生命周期 - 销毁之前beforeDestroy() {},//生命周期 - 销毁完成destroyed() {},//如果页面有 keep-alive 缓存功能, 这个函数会触发activated() {},}
</script><style scoped>#container {padding: 0px;margin: 0px;width: 100%;height: 800px;}.input-item {height: 2.2rem;}.input-card {display: flex;flex-direction: column;min-width: 0;word-wrap: break-word;background-color: #fff;background-clip: border-box;border-radius: .25rem;width: 10rem;border-width: 0;border-radius: 0.4rem;box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);position: fixed;bottom: 12rem;right: 2rem;-ms-flex: 1 1 auto;flex: 1 1 auto;padding: 0.75rem 1.25rem;}
</style>
1.2 使用示例
引入组件即可
<template><PositionContainer></PositionContainer>
</template><script>//这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)//例如: import 《组件名称》 from '《组件路径》 ';import PositionContainer from '@/pages/components/map/PositionContainer';export default {name: 'Position',//import 引入的组件需要注入到对象中才能使用components: {PositionContainer},props: {},data() {//这里存放数据return {};},//计算属性 类似于 data 概念computed: {},//监控 data 中的数据变化watch: {},//方法集合methods: {},//生命周期 - 创建完成(可以访问当前 this 实例)created() {},//生命周期 - 挂载完成(可以访问 DOM 元素)mounted() {},//生命周期 - 创建之前beforeCreate() {},//生命周期 - 挂载之前beforeMount() {},//生命周期 - 更新之前beforeUpdate() {},//生命周期 - 更新之后updated() {},//生命周期 - 销毁之前beforeDestroy() {},//生命周期 - 销毁完成destroyed() {},//如果页面有 keep-alive 缓存功能, 这个函数会触发activated() {},}
</script><style scoped></style>
1.3 实现效果
2. 进阶抽取(自定义点位+每个点位不同图标+每个点位不同标注)
这里的点位数据为后端返回数据,有需要的可以自己模拟数据
后端返回数据结构类似于如下
[{"sys_time": 1674206183000,"user_name": "名称1","jingdu": 104.751846,"weidu": 31.767537,"sendTime": "2023-01-20 17:16:23"},{"sys_time": 1677735439000,"user_name": "名称2","jingdu": 104.7560758,"weidu": 31.767168,"sendTime": "2023-01-20 17:16:23"} ]
2.1组件代码
代码说明:
getNewestPositions
方法是调用后端接口返回数据- 然后将后端的list遍历组装为我们需要的数组
LabelsData
content: item.user_name+'-'+item.sendTime
设置我们展示lable,image: 'https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png',
设置我们点位的图标,后续用户有图标后可以从后端取数据,这里我就先写死- 将后端数据的第一个数据设置为地图中心center
<template><div id="container"></div>
</template><script>//这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)//例如: import 《组件名称》 from '《组件路径》 ';import AMapLoader from "@amap/amap-jsapi-loader";import {getNewestPositions} from '@/services/attendance/position.js'// 设置安全密钥window._AMapSecurityConfig = {securityJsCode: 'xxxx你的securityJsCodexxxx',}export default {name: 'PositionContainer',//import 引入的组件需要注入到对象中才能使用components: {},props: {},data() {//这里存放数据return {AMap: null,//此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。map: null,mouseTool: null,marker: null,allowCollision: false,//标注避让markermarkers: [],layer: null,LabelsData:[],center: [104.065735, 30.659462],};},//计算属性 类似于 data 概念computed: {},//监控 data 中的数据变化watch: {},//方法集合methods: {newestPositions () {getNewestPositions().then(res => {if (res.data.code==0){var postions = res.data.dataconsole.log(res.data.data)this.LabelsData =res.data.data.map(item=>{var labelsData = {name: item.user_name,position: [item.jingdu, item.weidu],zooms: [10, 20],opacity: 1,zIndex: 10,fold: true,icon: {// 图标类型,现阶段只支持 image 类型type: 'image',// 图片 urlimage: 'https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png',// 图片尺寸size: [64, 30],// 图片相对 position 的锚点,默认为 bottom-centeranchor: 'center',},text: {// 要展示的文字内容content: item.user_name+'-'+item.sendTime,// 文字方向,有 icon 时为围绕文字的方向,没有 icon 时,则为相对 position 的位置direction: 'right',// 在 direction 基础上的偏移量offset: [-20, -5],// 文字样式style: {// 字体大小fontSize: 12,// 字体颜色fillColor: '#22886f',//strokeColor: '#fff',strokeWidth: 2,fold: false,padding: '2, 5',}}}return labelsData})this.center=[postions[0].jingdu, postions[0].weidu]this.initMap()}else {this.$message.error(res.data.msg)}})},initMarkers(AMap) {this.layer = new AMap.LabelsLayer({zooms: [3, 20],zIndex: 1000,// collision: false,// 设置 allowCollision:true,可以让标注避让用户的标注allowCollision: this.allowCollision,});this.layer.add(this.markers);// 图层添加到地图this.map.add(this.layer);// 初始化 labelMarkerfor (var i = 0; i < this.LabelsData.length; i++) {var curData = this.LabelsData[i];curData.extData = {index: i};var labelMarker = new AMap.LabelMarker(curData);this.markers.push(labelMarker);}// 将 marker 添加到图层this.layer.add(this.markers);this.map.setFitView(null, false, [100, 150, 10, 10]);// this.toggleBtn()},initMap() {AMapLoader.load({key: "xxxx你的keyxxxx", // 申请好的Web端开发者Key,首次调用 load 时必填version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15"plugins": ["AMap.Scale","AMap.HawkEye","AMap.ToolBar","AMap.AutoComplete","AMap.PlaceSearch","AMap.ControlBar","AMap.MouseTool","AMap.DragRoute","AMap.MoveAnimation"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等}).then((AMap) => {this.AMap=AMapthis.map = new AMap.Map("container", { //设置地图容器idzoom: 15.8, // 初始化地图级别center: this.center, //中心点坐标 成都 104.065735, 30.659462showIndoorMap: false,});this.initMarkers(AMap);}).catch(e => {console.log(e);})},},//生命周期 - 创建完成(可以访问当前 this 实例)created() {this.newestPositions()},//生命周期 - 挂载完成(可以访问 DOM 元素)mounted() {this.initMap();},//生命周期 - 创建之前beforeCreate() {},//生命周期 - 挂载之前beforeMount() {},//生命周期 - 更新之前beforeUpdate() {},//生命周期 - 更新之后updated() {},//生命周期 - 销毁之前beforeDestroy() {},//生命周期 - 销毁完成destroyed() {},//如果页面有 keep-alive 缓存功能, 这个函数会触发activated() {},}
</script><style scoped>#container {padding: 0px;margin: 0px;width: 100%;height: 800px;}.input-item {height: 2.2rem;}.input-card {display: flex;flex-direction: column;min-width: 0;word-wrap: break-word;background-color: #fff;background-clip: border-box;border-radius: .25rem;width: 10rem;border-width: 0;border-radius: 0.4rem;box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);position: fixed;bottom: 12rem;right: 2rem;-ms-flex: 1 1 auto;flex: 1 1 auto;padding: 0.75rem 1.25rem;}
</style>
2.2 使用示例
参照1.2 ,没有任何改变
2.3 抽取效果
放大地图后
3.最终抽取(定时刷新点位)
3.1 组件代码
代码说明:
- 使用定时器来做定时任务
this.timer = setInterval(this.newestPositionsWithoutInitMap, 120 * 1000);
- 切记
beforeDestroy()
的时候要clearInterval(this.timer);
this.map.setFitView(null, false, [100, 150, 10, 10]);
地图缩放到合适的位置
- 就会导致我们每次刷新都会地图缩放到最大,就是因为这个
- 核心思路就是通过定时器来定时请求后端接口,然后渲染地图标记即可
<template><div id="container"></div>
</template><script>//这里可以导入其他文件(比如: 组件, 工具 js, 第三方插件 js, json文件, 图片文件等等)//例如: import 《组件名称》 from '《组件路径》 ';import AMapLoader from "@amap/amap-jsapi-loader";import {getNewestPositions} from '@/services/attendance/position.js'// 设置安全密钥window._AMapSecurityConfig = {securityJsCode: 'xxxx你的securityJsCodexxxx',}export default {name: 'PositionContainer',//import 引入的组件需要注入到对象中才能使用components: {},props: {},data() {//这里存放数据return {AMap: null,//此处不声明 map 对象,可以直接使用 this.map赋值或者采用非响应式的普通对象来存储。map: null,mouseTool: null,marker: null,allowCollision: false,//标注避让markermarkers: [],layer: null,LabelsData:[],center: [104.065735, 30.659462],timer: '',zoom: '',};},//计算属性 类似于 data 概念computed: {},//监控 data 中的数据变化watch: {},//方法集合methods: {createLable: function (res) {var postions = res.data.datathis.LabelsData = res.data.data.map(item => {var labelsData = {name: item.user_name,position: [item.jingdu, item.weidu],zooms: [10, 20],opacity: 1,zIndex: 10,fold: true,icon: {// 图标类型,现阶段只支持 image 类型type: 'image',// 图片 urlimage: 'https://a.amap.com/jsapi_demos/static/demo-center/marker/express2.png',// 图片尺寸size: [64, 30],// 图片相对 position 的锚点,默认为 bottom-centeranchor: 'center',},text: {// 要展示的文字内容content: item.user_name + '-' + item.sendTime,// 文字方向,有 icon 时为围绕文字的方向,没有 icon 时,则为相对 position 的位置direction: 'right',// 在 direction 基础上的偏移量offset: [-20, -5],// 文字样式style: {// 字体大小fontSize: 12,// 字体颜色fillColor: '#22886f',//strokeColor: '#fff',strokeWidth: 2,fold: false,padding: '2, 5',}}}return labelsData})this.center = [postions[0].jingdu, postions[0].weidu]},newestPositions () {getNewestPositions().then(res => {if (res.data.code==0){this.createLable(res);this.initMap()}else {this.$message.error(res.data.msg)}})},newestPositionsWithoutInitMap () {getNewestPositions().then(res => {if (res.data.code==0){this.createLable(res);this.initMarkers(this.AMap)}else {this.$message.error(res.data.msg)}})},initMarkers(AMap) {this.markers=[]this.layer = new AMap.LabelsLayer({zooms: [3, 20],zIndex: 1000,// collision: false,// 设置 allowCollision:true,可以让标注避让用户的标注allowCollision: this.allowCollision,});this.layer.add(this.markers);// 图层添加到地图this.map.clearMap()this.map.add(this.layer);// 初始化 labelMarkerfor (var i = 0; i < this.LabelsData.length; i++) {var curData = this.LabelsData[i];curData.extData = {index: i};var labelMarker = new AMap.LabelMarker(curData);this.markers.push(labelMarker);}// 将 marker 添加到图层this.layer.add(this.markers);// this.map.setFitView(null, false, [100, 150, 10, 10]); //地图缩放到合适的位置,开启每次都会缩放到最大状态// this.toggleBtn()},initMap() {AMapLoader.load({key: "xxxx你的keyxxxx", // 申请好的Web端开发者Key,首次调用 load 时必填version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15"plugins": ["AMap.Scale","AMap.HawkEye","AMap.ToolBar","AMap.AutoComplete","AMap.PlaceSearch","AMap.ControlBar","AMap.MouseTool","AMap.DragRoute","AMap.MoveAnimation"], // 需要使用的的插件列表,如比例尺'AMap.Scale'等}).then((AMap) => {this.AMap=AMapthis.map = new AMap.Map("container", { //设置地图容器idzoom: 15.8, // 初始化地图级别center: this.center, //中心点坐标 成都 104.065735, 30.659462showIndoorMap: false,});this.initMarkers(AMap);// this.map.on('zoomend', function (e) {// this.zoom =this.map.getZoom();// console.log(this.zoom)//// }.bind(this));}).catch(e => {console.log(e);})},},//生命周期 - 创建完成(可以访问当前 this 实例)created() {this.newestPositions()},//生命周期 - 挂载完成(可以访问 DOM 元素)mounted() {this.timer = setInterval(this.newestPositionsWithoutInitMap, 120 * 1000);this.initMap();},//生命周期 - 创建之前beforeCreate() {},//生命周期 - 挂载之前beforeMount() {},//生命周期 - 更新之前beforeUpdate() {},//生命周期 - 更新之后updated() {},//生命周期 - 销毁之前beforeDestroy() {clearInterval(this.timer);},//生命周期 - 销毁完成destroyed() {},//如果页面有 keep-alive 缓存功能, 这个函数会触发activated() {},}
</script><style scoped>#container {padding: 0px;margin: 0px;width: 100%;height: 800px;}.input-item {height: 2.2rem;}.input-card {display: flex;flex-direction: column;min-width: 0;word-wrap: break-word;background-color: #fff;background-clip: border-box;border-radius: .25rem;width: 10rem;border-width: 0;border-radius: 0.4rem;box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);position: fixed;bottom: 12rem;right: 2rem;-ms-flex: 1 1 auto;flex: 1 1 auto;padding: 0.75rem 1.25rem;}
</style>
3.2 使用示例
参照1.2 ,没有任何改变
3.3 抽取效果
在2.3的效果基础上每2分钟刷新一次位置