前景介绍
在项目实施过程中需要根据无人机飞行过程中产生的飞行点位在地图上实时显示无人机的飞行轨迹以供查看当前飞行轨迹,故沿用系统中依赖包@arcgis/core,具体安装使用详情烦请移步至前篇文章ArcGIS Maps SDK for JavaScript线轨迹回放融合解决方法中查看。
数据添加
此模块将分为多个无人机相关信息添加至同一数组,后根据数组内容循环查询无人机位置坐标,创建线轨迹图层并创建定时器,间隔三秒钟获取一次无人机位置并添加至线图层的线要素中。
清除定时器
在初始化创建添加图层之前需要调用方法清除定时器。
intervalClear() {
if (this.rtIntervalFlag) {
clearInterval(this.rtIntervalFlag);
this.rtIntervalFlag = undefined;
}
}
创建空图层
清除定时器后,在地图中查找指定图层,若指定图层不存在则创建图层,反之则直接在指定图层进行添加要素操作。
const existRouteLayer = window.global.map2D.map.allLayers.items.find(
(layer) => layer.title === this.routeTitle && layer.type === "graphics"
);
if (!existRouteLayer) {
let { routeLayer, droneLayer } = createEmptyLayer(this.routeTitle);
window.global.map2D.map.add(routeLayer);
window.global.map2D.map.reorder(routeLayer, 20);
}
export const createEmptyLayer = (routeTitle) => {
// 创建空的实时轨迹图层
const routeLayer = new GraphicsLayer();
routeLayer.title = routeTitle;
return { routeLayer};
};
创建定时器
在前一步中判断地图控件中是否存在指定图层后创建定时器进行无人机坐标获取以及添加坐标至线图层
this.loopDealLocation();
this.setIntervalFlag = setInterval(() => {
this.loopDealLocation();
}, 3000);
获取坐标
遍历无人机信息数组并调用接口传递参数后获取无人机实时坐标信息。
let currentMap = window.global.map2D.map;//地图控件
let locationInfo = [];
//droneList-无人机数组
this.droneList.forEach((item) => {
let droneSn = item.droneSn;
let params = {
droneSn: droneSn,
pointCount: 2,//获取无人机当前点位和前一个点位
};
getDroneLocation(params).then((res) => {
if (res.code == 0 && res.data.length > 0) {
locationInfo = res.data.map((item) => {
return {
lat: item.latitude,
lng: item.longitude,
};
});
this.dealRealTrack(droneSn, currentMap, locationInfo);
} else {
return;
}
});
});
处理坐标
获取坐标后,根据序列码判断图层中否存在此图形数据,若存在则对当前图形数据的几何线内容进行更新,反之则根据当前坐标创建图形并添加至指定图层中。
dealRealTrack(droneSn, map, locationInfo) {
let { isExist, graphicToUpdate } = isGraphicExist({
map: map,
layerTitle: this.routeTitle,
droneSn: droneSn,
});//判断图形并返回图形
let coordinate = [locationInfo[0].lng, locationInfo[0].lat];//最新点坐标
if (isExist) {
let trackGraphic = graphicToUpdate[0];
let geometry = trackGraphic.geometry;
let newGeometry = updateCurrentGeometry({ geometry: geometry, coordinate: coordinate });//更新当前几何线
let angle = computeAngle(locationInfo);//根据前后两点计算角度,用于无人机点飞行,当前未用到暂不考虑
this.updateLayer({
type: "drone-line",
geometry: newGeometry,
angle: angle,
droneSn: droneSn,
});//更新图层
} else {
let routeGraphic = getCustomGraphic({
sn: droneSn,
pathPoints: [coordinate],
});//创建图形
this.addGraphic({ type: "drone-line", trackGraphic: routeGraphic });//添加图形
}
this.setExtentView();//缩放至当前范围
}
方法集合
以上处理坐标判断、添加以及更新图形方法如下,根据方法名对照添加即可:
//判断图层中图形是否存在
export const isGraphicExist = ({ map, layerTitle, droneSn, attributeName = "droneSn" }) => {
let isExist = false;
let graphicToUpdate = [];
const graphicLayer = map.layers.find(
(layer) => layer.title === layerTitle && layer.type === "graphics"
);
if (!graphicLayer) {
return { isExist };
}
//获取图层所有图形
const graphics = graphicLayer.graphics.items;
graphics.forEach((graphic) => {
if (graphic.getAttribute(attributeName) === droneSn) {
isExist = true;
graphicToUpdate.push(graphic);
}
});
return { isExist, graphicToUpdate };
};
//更新图形长度
export const updateCurrentGeometry = ({ type = "drone-line", geometry, coordinate }) => {
let updatedGeo = geometry.clone();
let path = geometry.paths[0];
let pointIndex = path.length - 1;
let insertPoint = new Point({
x: coordinate[0],
y: coordinate[1],
});
let newUpdatedGeo = updatedGeo.insertPoint(0, pointIndex, insertPoint);
return newUpdatedGeo;
};
//计算角度
export function computeAngle(locationInfo) {
let points = locationInfo.map((item) => [item.lng, item.lat]);
const startPoint = points[0];
const endPoint = points[1];
if (endPoint[0] !== startPoint[0] || endPoint[1] !== startPoint[1]) {
let returnedAngle =
(Math.atan2(endPoint[0] - startPoint[0], endPoint[1] - startPoint[1]) * 180) / Math.PI;
return returnedAngle;
}
}
//更新图层
updateLayer({ type = "drone-line", geometry, angle = 0, droneSn }) {
let graphics = null;
const existRouteLayer = window.global.map2D.map.allLayers.items.find(
(layer) => layer.title === this.routeTitle && layer.type === "graphics"
);
//获取图层所有图形
graphics = existRouteLayer.graphics.items;
graphics.forEach((graphic) => {
if (graphic.getAttribute(this.attributeName) === droneSn) {
graphic.geometry = geometry;
if (angle && angle != 0) {
graphic.symbol.angle = angle;
}
}
});
}
// 创建自定义图形
export const getCustomGraphic = ({
type = "ctl", //type:ctl:实时线轨迹图标;ctd:无人机图标;
sn, //sn:设备序列号
color = " #0078FF", //线符号颜色 [0, 120, 255, 0.85]
pathPoints,
}) => {
if (type === "ctl") {
// 定义线图层符号
const routeSymbol = new SimpleLineSymbol({
color: [0, 120, 255, 0.85], //蓝色//new Color(color),
width: 4,
style: "solid",
});
// 创建轨迹线
const polyline = new Polyline({
// paths: [pathPoints.map((p) => [p[0], p[1], p[2]])],
paths: [pathPoints.map((p) => [p[0], p[1]])],
});
// 添加轨迹图层
const routeGraphic = new Graphic({
geometry: polyline,
symbol: routeSymbol,
attributes: {
droneSn: sn,
},
});
return routeGraphic;
}
};
//添加图形
addGraphic({ type, trackGraphic, labelGraphic, droneGraphic }) {
if (type == "drone-line") {
const routeLayer = window.global.map2D.map.allLayers.items.find(
(layer) => layer.title === this.routeTitle && layer.type === "graphics"
);
routeLayer.add(trackGraphic);
}
}
//缩放至当前几何范围
setExtentView() {
const existRouteLayer = window.global.map2D.map.allLayers.items.find(
(layer) => layer.title === this.routeTitle && layer.type === "graphics"
);
if (!existRouteLayer) {
return;
}
const extent = existRouteLayer.graphics.items[0].geometry.extent;
if (!extent) {
return;
}
window.global.map2D.mapview.goTo(extent);
}
总结
综上,即可完成动态实时添加线图层轨迹并在地图上显示查看;若用户想在查看后将指定图层删除也可调用地图的移除事件将指定图层进行移除,或者调用图层的移除事件移除指定属性的图形。