第八节:使用自定义地图工具实现任意点预报
有了上一节的铺垫,我们这一节开始实现任意点预报功能。
功能分析
任意点预报的流程较为清晰:

如果我们直接在切换地图工具的方法里面编写这个逻辑,那么后续其他地图工具的逻辑就会都在一起,这样代码会比较乱,因此我们采用QE中规范的地图工具来进行实现。
使用标准地图工具,完善切换逻辑
QE默认提供了绘制工具,虽然也支持点的绘制,但是这里我们为了演示自定义绘制工具的使用,将上面这个简单的逻辑封装为一个标准的地图工具。
既然使用标准地图工具,那么我们可以先完善switchTool方法的逻辑来支持不同地图工具之之间的切换:
public switchTool(value: string) {
if (!defined(value) || value === "pan") {
map.toolService.getCurrent()?.clear();
map.toolService.setCurrent(null);
return;
}
let mapTool: IMapTool;
if (value === "forecast") {
} else if (value === "draw_poly") {
} else if (value === "distance") {
} else {
message.warn("未能获取到对应的地图工具!");
return;
}
map.toolService.setCurrent(mapTool ?? null);
}
创建自定义地图工具
我们通过自定义地图工具来实现上面规划的功能。
实现地图工具接口
QE中的地图工具使用IMapTool接口定义,因此我们创建一个PointForecastMapTool类来实现该接口:
class PointForecastMapTool extends Evented implements IMapTool {
protected map: LMap;
public begin(properties?: any) {
}
public end() {
this.clear();
}
public clear() {
}
public setMap(map: any) {
this.map = map;
}
}
以上就是一个空地图工具,当调用map.toolService.setCurrent时,传入的工具会被激活,首先是setMap方法被调用,框架将绑定的地图传递给工具,然后是begin被调用,说明这个工具进入激活状态。
在工具被激活时监听地图点击事件
在begin方法中进行监听,然后设置一个函数进行响应:
protected handleMapClick(args: L.LeafletMouseEvent) {
}
public begin(properties?: any) {
this.map.on("click", this.handleMapClick, this);
}
根据点击信息获取预报信息显示
在这里,我们需要在用户点击的地方显示一个marker,然后开始请求数据,最后将请求的结果以popup形式呈现。
显示marker
我们首先在工具内部定义一个私有的marker对象,这样第一次使用的时候创建,后续只要更新marker的位置即可,当然也可以每次都先删除之前的marker后重新创建,没有太大的区别。
private _marker: L.Marker;
更新handleMapClick
方法:
if (!this._marker) {
this._marker = L.marker(args.latlng).addTo(this.map);
} else {
this._marker.setLatLng(args.latlng);
}
到目前为止,我们已经实现了点击后能在地图上显示一个marker,现在我们把这个工具真正的关联到业务逻辑中,更新工具管理器的switchTool
方法:
public switchTool(value: string) {
...
let mapTool: IMapTool;
if (value === "forecast") {
mapTool = new PointForecastMapTool();
}
...
}
指定Leaflet默认图片资源的方式如下:
L.Icon.Default.imagePath = "https://unpkg.com/leaflet@1.7.1/dist/images/";
这时候,如果点击任意点预报,我们就可以在地图上画点了:
获取预报数显示
在本节中,我们使用晴天钟提供免费的任意点预报数据接口,由于仅用来演示,我们直接使用了能够直接获取图片的接口,这样拿回来的图片我们可以直接显示。
接口访问地址如下:
https://www.7timer.info/bin/civillight.php?lon=${args.latlng.lng}&lat=${args.latlng.lat}&lang=zh-CN&output=internal&tzshift=0
其中经纬度由用户传入,返回的是一张如下的图片:
我们将响应点击事件的方法进行更新,以便能够根据点击的位置请求接口,然后把获取到的图片在popup中显示:
protected handleMapClick(args: L.LeafletMouseEvent) {
if (!this._marker) {
this._marker = L.marker(args.latlng).addTo(this.map);
} else {
this._marker.setLatLng(args.latlng);
}
const imgUrl = `https://www.7timer.info/bin/civillight.php?lon=${args.latlng.lng}&lat=${args.latlng.lat}&lang=zh-CN&output=internal&tzshift=0`;
const currentId = uid();
this._loadingId = currentId;
message.info({ duration: 10000, content: "数据请求中..." });
const img = new Image();
img.onload = () => {
if (this._loadingId !== currentId) {
//已经有二次点击
return;
}
map.openPopup(img, args.latlng, { maxWidth: img.width });
message.destroy();
};
img.onerror = () => {
message.error("该点暂无数据!");
message.destroy();
};
img.src = imgUrl;
}
清理地图绘制内容
当我们切换到其他地图工具时,我们需要清理当前地图上绘制的内容(如希望保留,也可以不清理),这可以通过在end方法中调用clear方法实现,clear方法是地图工具的标准方法,清理的代码应该写在此,但是默认工具被取消激活时并不会调用clear方法,所以如有需要,可以在end方法中主动调用:
public end() {
this.map.off("click", this.handleMapClick, this);
this.clear();
}
public clear() {
this._marker && this._marker.remove();
this._marker = undefined;
this.map.closePopup();
}
现在点击地图,就可以出现任意点预报结果了,切换到其他工具,当前的内容也会及时清除,至此,我们的任意点预报功能就完整的实现了!
总结
本节主要介绍了自定义地图工具的创建,然后结合免费的任意点预报接口实现了任意点预报的显示,现在您可以根据自己的需要定制其他地图交互工具了,下一节我们将会介绍QE内置的一个功能丰富的矢量绘制工具!
No Comments