目录
一. 需求介绍
地图加载后,需要自动定位到,尽量包裹所有点位的范围
图例可以展开折叠
需要筛选点位,且每次筛选后,都会重新进行范围确认
点击点位后,可以在屏幕下方弹出弹框,显示点位详细信息
点击地图的其他位置,弹框可以隐藏
二. 实现过程
2.1 初始化地图
新建地图页面:ionic g page map
引入封装好的 地图组件 以及 地图服务
在新建的地图页面中,修改 .html 文件,调用 地图加载完毕 的方法
该方法主要用于:实例化地图对象,并在拥有对象的基础上,进行诸如 打点 的其他操作
<!-- 引入地图组件 -->
<div style="width: 100%; height: 100%">
<ths-map (onMapLoaded)="onMapLoaded($event)" style="width: 100%; height: 100%"> </ths-map>
</div>
/**
* 地图加载完毕
* @param map 事件对象
*/
onMapLoaded(map: any): void {
this.mapView = map; // 地图对象
...
}
2.2 实现图例展开折叠及复选功能
2.2.1 图例展开折叠
通过调整 legendUp 属性,决定图例的 展开/收起 图标,每次点击后,都会让 legend 切换
通过调整 legendUp 属性,决定图例的 具体列表 是否显示
不给图例列表设置宽度,就能够实现图例展开收起后,图例标题宽度自适应收起来
2.2.2 图例复选框
复选框绑定了,图层列表的显示状态:[(ngModel)]="isShowList.dlLayer
监听复选框改变事件 (ionChange),根据图层列表的展示状态,决定是 添加图层,还是清除图层
2.2.3 源码
<!-- 图例 -->
<ion-list class="legend" lines="full">
<!-- 图例标题 -->
<ion-item class="bg-title" lines="none">
<ion-label class="title-center">图例</ion-label>
<ion-icon name="arrow-dropdown" color="medium" *ngIf="legendUp" (click)="changeLegned()"></ion-icon>
<ion-icon name="arrow-dropup" color="medium" *ngIf="!legendUp" (click)="changeLegned()"></ion-icon>
</ion-item>
<!-- 具体图例组 -->
<ion-item-group *ngIf="legendUp">
<ion-item lines="none">
<!-- 复选按钮 -->
<ion-checkbox slot="start" [(ngModel)]="isShowList.dlLayer"
(ionChange)="isShowList.dlLayer?addDLLayerPoint():clearLayer('dlLayer')"
></ion-checkbox>
<!-- 图例图片 -->
<ion-thumbnail slot="start">
<ion-img src="assets/images/source_3.png"></ion-img>
</ion-thumbnail>
<ion-label>道路</ion-label>
</ion-item>
...
</ion-item-group>
// 图例展开折叠状态
public legendUp: boolean = true;
/**
* 图例展开折叠状态切换事件
*/
changeLegned(): void {
this.legendUp = !this.legendUp;
}
// 图层列表展示状态
public isShowList: { [propName: string]: boolean } = {
dlLayer: true,
jzgdLayer: true,
dcmtLayer: true,
jbcLayer: true,
};
2.3 初始化图层、显示弹框、打点、清除打点
2.3.1 初始化图层
初始化图层,必须在拥有地图对象之后才能进行
也就是在 onMapLoaded() 方法中,声明地图对象之后,执行初始化图层操作
初始化图层:this.thsMapService.addGraphicsLayer()
2.3.2 实现弹框展示隐藏
初始化图层中,接受三个参数,其中第三个是 点击事件回调函数
点击事件回调函数中的 event,用于存储图层的全部信息,并且可以将这个图层全部信息传出
比如,点击某个点位出现弹框,我想获取这个点位的全部信息,就是通过此回调函数,接受具体信息,并进行格式化输出的
我个人觉得,这个回调函数,就是在初始化图层,并执行打点操作后,再调用的,用于接受打点之后的图层信息,然后再将这些信息进行展示
<!-- 弹框 -->
<ion-list class="pop" lines="full" *ngIf="isPopShow">
<ion-item>
<ion-label class="title">{{popInfo.POINT_NAME || "--"}}</ion-label>
</ion-item>
<img src="assets/images/da-icon.png" *ngIf="popInfo.DUST_LEVEL === '好'" />
<img src="assets/images/yu-icon.png" *ngIf="popInfo.DUST_LEVEL === '差'" />
</ion-list>
2.3.3 实现点位筛选(分类)
实现点位筛选的本质:将点位进行分类,打在不同的图层上
初始化图层方法,返回的是 promise对象,可以赋值给 图层对象 this.dlLayer = res;
根据图层展示状态:(ionChange)="isShowList.dcmtLayer?addDCMTLayerPoint():clearLayer('dcmtLayer')"
- 如果是展示的(图例选中),就在图层上进行打点操作
- 如果是不展示的(图例未选中),就在图层上清除已有的图层信息
2.3.4 打点
需要先获取所需要的点位信息,依次执行 addPoint(),将点位添加到图层
值得注意的是,每次这个方法只能添加一个点,可以通过 for循环 多次执行该打点操作 Number(res.data[i].LONGITUDE),
打点结束后,应该根据打点位置,重新确定显示范围:this.thsMapService.setExtent(this.mapView, minX, minY, maxX, maxY);
2.3.5 移除地图中的所有图层(清除打点)
调用方法清除打点,结束之后,记得更改图层当前的显示状态
2.3.6 地图整体点击事件
比如点击点位后,出现弹框,点击地图的其他部分应该隐藏弹框,这时候就需要地图整体点击事件
除了点位之外,地图其他部分被点,就会触发这个事件
地图整体点击事件传回来一个对象 e,包含了地图的全部信息
其中有一项 e.graphic如果是 undefined,就意味着没有点击点位,可以根据这个,来判定弹框是否隐藏
注意,这个事件也需要在 onMapLoaded() 方法中,声明地图对象之后执行
2.3.7 源码
// 不同的图层对象
private dlLayer: any;
// 不同的图层对象
private jzgdLayer: any;
...
// 初始化道路图层
this.thsMapService
.addGraphicsLayer(this.mapView, 'dlLayer', (event) => {
this.addPopInfo(event);
})
.then((res) => {
this.dlLayer = res;
if (this.isShowList.dlLayer) {
// 添加道路图层点位
this.addDLLayerPoint();
}
});
// 地图整体点击事件
this.mapView.on('click', (e) => {
this.mapClick(e);
});
/**
* 移除图层中的所有图形
* @param layerName 图层名称
*/
clearLayer(layerName: string): void {
// 调用服务,清除对应图层信息
this.thsMapService.clearLayer(this.mapView, layerName);
// 更改显示状态
this.isShowList[layerName] = false;
}
/**
* 添加图层点位
* @param params 添加点位的请求参数
* @param layer 添加点位的图层
* @param imgSrc 添加点位的图片地址
*/
addPoint(params: object, layer: object, imgSrc: string): void {
// 请求点位
this.tabEnvService.getDutsListData(params, false, (res) => {
// 初始化范围
let minX = 0;
let maxX = 0;
let minY = 0;
let maxY = 0;
// 进行道路打点(每次只能打一个,所以要通过 for循环)
for (let i = 0; i < res.data.length; i++) {
// 每次打点前 进行地图区域范围更新
if (minX === 0 || res.data[i].LONGITUDE < minX) {
minX = Number(res.data[i].LONGITUDE);
}
if (maxX === 0 || res.data[i].LONGITUDE > maxX) {
maxX = Number(res.data[i].LONGITUDE);
}
if (minY === 0 || res.data[i].LATITUDE < minY) {
minY = Number(res.data[i].LATITUDE);
}
if (maxY === 0 || res.data[i].LATITUDE > maxY) {
maxY = Number(res.data[i].LATITUDE);
}
this.thsMapService.addMarker(
// 经度
Number(res.data[i].LONGITUDE),
// 纬度
Number(res.data[i].LATITUDE),
layer,
imgSrc,
20,
20,
0,
0,
4326,
res.data[i]
);
}
// console.log(minX, minY, maxX, maxY);
// 根据地图点位 确定大致地图范围
this.thsMapService.setExtent(this.mapView, minX, minY, maxX, maxY);
});
}
/**
* 添加道路图层点位
*/
addDLLayerPoint(): void {
this.addPoint(this.params[1], this.dlLayer, '/assets/images/source_3.png');
}
/**
* 除了打点位置外,其余位置的地图点击事件
*/
mapClick(e: any): void {
// console.log(e);
// graphic._graphicsLayer
if (e.graphic === undefined) {
this.isPopShow = false;
}
}
2.4 监听地图缩放级别变化,动态设置图例大小
移动端地图使用的是 arcgis js(没有点哦),版本是 3.x
注意: 版本3.x 和 版本4.x 同步更新,他们是两个体系,而不是我原来理解的版本升级,直接搜 arcgis 出现的不是我们需要的 版本3.x,一定要注意搜索正确的版本
zoom-end :缩放执行完毕后,触发的事件
/**
* 注册地图级别发生改变的事件
* @callback cb
*/
mapLevelChanged(cb: () => void) {
this.map.on('zoom-end', cb);
}
/**
* 获取地图当前级别
*/
getMapLevel() {
return this.map.getLevel();
}
// 监听图层级别变化,动态设置点位图标的大小
pageData.mapView.mapLevelChanged(() => {
const currentLevel = pageData.mapView.getMapLevel();
console.log('当前地图缩放级别为:', currentLevel);
if (currentLevel <= 9) {
setMapPointClickStyle(pageData.mapLayer.companyLayer.value, null, 1);
} else if (currentLevel > 9 && currentLevel <= 10) {
setMapPointClickStyle(pageData.mapLayer.companyLayer.value, null, 10);
} else if (currentLevel > 10 && currentLevel <= 11) {
setMapPointClickStyle(pageData.mapLayer.companyLayer.value, null, 15);
} else if (currentLevel > 11 && currentLevel <= 12) {
setMapPointClickStyle(pageData.mapLayer.companyLayer.value, null, 20);
} else if (currentLevel > 12 && currentLevel <= 13) {
setMapPointClickStyle(pageData.mapLayer.companyLayer.value, null, 30);
} else {
setMapPointClickStyle(pageData.mapLayer.companyLayer.value, null, 35);
}
})