- 主题:关于百度地图应用技术分享
- 背景:做项目过程中遇到的新需求与优化,具体体现在作战地图、轨迹分析模块。
- 大纲:百度地图GL版、turf.js、离线版GL、GraphHopper
- 内容:
1.项目中的轨迹分析优化(通过GraphHopper服务 优化轨迹路线)
- 优化前:
- 优化后:
路线根据道路将站点之间路线,丰富成汽车导航规划路线。道路点数量约为优化前的10倍。
2.项目中作战地图
(1)多城市多边形轮廓覆盖物
通过在
datav.aliyun.com/tools/atlas… 网址将8个市区的轮廓数据下载转坐标后存入项目中,然后用BMapGL.Polygon生成多个多边形。
new BMapGL.Polygon(xinxiangArea, {
strokeWeight: 0.01, //边框宽度
fillColor: "#DDE4F0", //填充颜色
fillOpacity: 0.5, enableMassClear: false
}); //建
this.map.addOverlay(xinxiang)
this.polygonDistrict.push(xinxiang)
(2)菏泽市轮廓线
通过在datav.aliyun.com/tools/atlas… 网址下载轮廓点坐标,在其中找到两个点划分出两条线段存入项目,然后用 BMapGL.Polyline生成加载到地图中
// 画边界线
paintingHeZeLine () {
this.paintingHeZeLineRightData = new BMapGL.Polyline(pointsFormLineString(lineRight), { strokeWeight: 2, strokeColor: "#7ABB4F", enableMassClear: false });
this.paintingHeZeLineData = new BMapGL.Polyline(pointsFormLineString(lineLeft), { strokeWeight: 2, strokeColor: "#00CCFF", enableMassClear: false });
this.map.addOverlay(this.paintingHeZeLineData); //添加覆盖物
this.map.addOverlay(this.paintingHeZeLineRightData); //添加覆盖物
},
(3)省际线5km线、10km线
这里用到了turf.js的辐射区功能(为给定半径的Feature计算一个缓冲区。支持的单位是英里、公里和度数),他可以支持多个maker点,通过他生成一个菏泽市往内5km或10km的一个轮廓数据(一堆marker点)。然后同菏泽市轮廓线逻辑找到两个点截通过用BMapGL.Polyline加载,然后与边界线轮廓形成多边形用BMapGL.Polygon加载。
// 画5公里覆盖物
paintingFivePolygon () {
// 菏泽边界线+5公里边界线+菏泽线的第一个坐标
this.paintingFiveLine = new BMapGL.Polyline(pointsFormLineString(fiveLeft), { strokeWeight: 1, strokeColor: "#FF2A2A", enableMassClear: false });
this.paintingFivePolygonData = new BMapGL.Polygon(pointsFormLineString(fiveArea), { strokeWeight: 1, strokeColor: "#FF2A2A", fillColor: "red", fillOpacity: 0.1, enableMassClear: false });
this.map.addOverlay(this.paintingFiveLine);
this.map.addOverlay(this.paintingFivePolygonData);
// this.paintingFivePolygonHide();
},
//5公里覆盖物展示
paintingFivePolygonShow () {
this.paintingFiveLine.show()
this.paintingFivePolygonData.show()
},
//5公里覆盖物隐藏
paintingFivePolygonHide () {
this.paintingFiveLine.hide()
this.paintingFivePolygonData.hide()
},
(4)多maker点渲染机制
在这个项目中maker点多达3万多。在项目中验证过地图渲染点超过1万的已经很卡了。在这里做了一个优化,逻辑跟百度地图的使用罗一样,通过放大的层级与展示的区域,来筛选展示的maker点,在1-10层只展示大概的60个,13、14层只展示大概的120个,15、16层只展示大概的210个,在17、18、19层全部展示。为了数据展示更合理,根据每种的比例来渲染个数,个数较少的则全部展示,有数据的至少展示一个。
//获取选中种类,maker占比
getProportion (arr, keys, maxNum) {
let p = {
"8": 0,
"13": 0,
"14": 0,
"15": 0,
"17": 0,
"18": 0,
"19": 0,
'all': 0
}
arr.map(item => {
if (keys.includes(8) && item.type == 'ordinary') {
p['8']++
p['all']++
}
if (keys.includes(13) && item.partyMember == '1') {
p['13']++
p['all']++
}
if (keys.includes(14) && item.groupLeader == '1') {
p['14']++
p['all']++
}
if (keys.includes(15) && item.information == '1') {
p['15']++
p['all']++
}
if (keys.includes(17) && item.illegal == '1') {
p['17']++
p['all']++
}
if (keys.includes(18) && item.sensitive == '1') {
p['18']++
p['all']++
}
if (keys.includes(19) && item.outflow == '1') {
p['19']++
p['all']++
}
})
if (p['all'] > maxNum) {
return {
"8": Math.ceil(p['8'] / p['all'] * maxNum),
"13": Math.ceil(p['13'] / p['all'] * maxNum),
"14": Math.ceil(p['14'] / p['all'] * maxNum),
"15": Math.ceil(p['15'] / p['all'] * maxNum),
"17": Math.ceil(p['17'] / p['all'] * maxNum),
"18": Math.ceil(p['18'] / p['all'] * maxNum),
"19": Math.ceil(p['19'] / p['all'] * maxNum),
'all': p['all']
}
} else {
return p
}
},
// 合理分配点位
getBuisnessType (number) {
var selectKeys = this.$refs.tree.getCheckedKeys(true);
var businessList = this.getMarker.businessList || []
// console.log("this.getMarker.businessList", this.getMarker.businessList)
var bs = this.map.getBounds();
var topSelect = this.checkListBusiness[0]
var arr = []
if (topSelect == 1) {
arr = businessList.filter(item => {
return (item.marginal == 1) && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
})
} else if (topSelect == 2) {
arr = businessList.filter(item => {
return (item.marginal == 0) && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
})
} else if (topSelect == 3) {
arr = businessList.filter(item => {
return (item.marketType == "town") && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
})
} else if (topSelect == 4) {
arr = businessList.filter(item => {
return (item.marketType == "countryside") && bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
})
} else {
arr = businessList.filter(item => {
return bs.containsPoint(new BMapGL.Point(item.lng, item.lat))
})
}
var list = []
var jisun1 = 0
var jisun2 = 0
var jisun3 = 0
var jisun4 = 0
var jisun5 = 0
var jisun6 = 0
var jisun7 = 0
var otherArr = []
var allNOSelect = true
var keys = [8, 13, 14, 15, 17, 18, 19]
var selectsright = selectKeys.filter(item => {
return keys.includes(item)
})
let proportion = this.getProportion(arr, selectsright, number)
// console.log('proportion:' + JSON.stringify(proportion))
for (var i = 0; i < arr.length; i++) {
var item = arr[i]
if (selectsright.length == 0 || selectsright.length == 7) {
var loop = parseInt(number / 7)
if (item.partyMember == '1') {
if (jisun1++ < loop) {
list.push(item)
}
} else if (item.groupLeader == '1') {
if (jisun2++ < loop) {
list.push(item)
}
} else if (item.information == '1') {
if (jisun3++ < loop) {
list.push(item)
}
} else if (item.illegal == '1') {
if (jisun4++ < loop) {
list.push(item)
}
} else if (item.sensitive == '1') {
if (jisun5++ < loop) {
list.push(item)
}
} else if (item.outflow == '1') {
if (jisun6++ < loop) {
list.push(item)
}
} else if (item.type == 'ordinary') {
if (jisun7++ < loop) {
list.push(item)
}
}
if (list.length > number) {
return list
}
} else {
// var loop = parseInt(number / selectsright.length)
let loop = 0
if (selectKeys.includes(8)) {
if (item.type == 'ordinary') {
loop = proportion['8']
if (jisun1++ < parseInt(loop)) {
list.push(item)
}
}
}
if (selectKeys.includes(13)) {
if (item.partyMember == '1') {
loop = proportion['13']
if (jisun2++ < parseInt(loop)) {
list.push(item)
}
}
}
if (selectKeys.includes(14)) {
if (item.groupLeader == '1') {
loop = proportion['14']
if (jisun3++ < parseInt(loop)) {
list.push(item)
}
}
}
if (selectKeys.includes(15)) {
if (item.information == '1') {
loop = proportion['15']
if (jisun4++ < parseInt(loop)) {
list.push(item)
}
}
}
if (selectKeys.includes(17)) {
if (item.illegal == '1') {
loop = proportion['17']
if (jisun5++ < loop) {
list.push(item)
}
}
}
if (selectKeys.includes(18)) {
if (item.sensitive == '1') {
loop = proportion['18']
if (jisun6++ < loop) {
list.push(item)
}
}
}
if (selectKeys.includes(19)) {
if (item.outflow == '1') {
loop = proportion['19']
if (jisun7++ < loop) {
list.push(item)
}
}
}
if (list.length > number) {
return list
}
}
}
if (selectsright.length == 0 || selectsright.length == 7) {
if (list.length < number) {
//补齐点
for (var i = 0; i < arr.length; i++) {
// debugger
var item = arr[arr.length - 1 - i]
if (list.length < number) {
if (item.type == 'ordinary') {
list.push(item)
}
}
}
}
}
return list
},
(5)高危路线
数据通过后端接口计算,然后用 BMapGL.Polyline生成加载到地图中
// 获取高危路线
getHighRiskRoute () {
var that = this
for (var i = 0; i < this.getMarker.highRiskRouteList.length; i++) {
var highLine = new BMapGL.Polyline(pointsFormLineString(this.getMarker.highRiskRouteList[i]), { strokeWeight: 6, strokeColor: that.highLineColor[i] })
// that.map.addOverlay(highLine);
that.highRiskRouteData.push(highLine);
// highLine.hide();
highLine.addEventListener("click", function (type) {
if (that.lushuPageShow) {
return
}
that.lushuLine = new BMapGL.Polyline(type.currentTarget.getPath(), { strokeWeight: 6, strokeColor: type.currentTarget.getStrokeColor() })
that.map.addOverlay(that.lushuLine);
// that.highRiskRouteData.push(highLine);
// that.map.addOverlay(type.currentTarget)
that.map.setViewport(that.lushuLine.getPath());
that.saveOverlay()
that.lushuStop();
that.lushuPageShow = true;
that.lushu = new BMapGLLib.LuShu(that.map, that.lushuLine.getPath(), {
autoCenter: true,
icon: new BMapGL.Icon(require('../../assets/images/mapIndex/car.png'), new BMapGL.Size(34, 16)),
speed: 10000,
enableRotation: true
});
})
}
},
(6)刻画路线
地图添加两个监听是事件分别是“click”、“dblclick”。每次触发click添加一个maker,并与刻画一下这条线,有两个点之后就通过setPath修改这条线。dblclick:结束监听,并添加可清除轨迹maker的小叉号。
// 打开轨迹刻画
paintingBeginLine () {
this.paintingBlock = !this.paintingBlock;
if (this.paintingBlock) {
this.paintingBegin()
}
},
// 地图上描点
paintingBegin () {
if (this.paintingBeginData != true) {
this.paintingBeginData = true;
this.paintingBeginNum += 1;
this.paintingPolyline.push({ line: null, marker: [], deleteMarker: null, });
this.paintingBeginlisten();
}
},
// 监听折线绘画
paintingBeginlisten () {
var that = this;
this.map.addEventListener("click", function ({ latlng }) { //当鼠标单击时
if (that.paintingBeginData) { //判断是否绘制曲线完毕
//创建marker点
var marker = new BMapGL.Marker(latlng, { icon: new BMapGL.Icon(require('../../assets/images/mapIndex/LineMarker.png'), new BMapGL.Size(16, 18), { anchor: new BMapGL.Size(7, 20) }) });
// var marker = new BMapGL.Marker(new BMapGL.Point(e1.point.lng, e1.point.lat));
that.map.addOverlay(marker);
that.paintingPolyline[that.paintingBeginNum].marker.push(marker);
that.startPainting = latlng
// 划线
that.pLine.push(latlng) //存储曲线上每个点的经纬度
if (that.pLine.length < 2) { return; } //当折线上的点只有一个时,不绘制
if (that.paintingPolyline[that.paintingBeginNum].line) {
that.paintingPolyline[that.paintingBeginNum].line.setPath(that.pLine)
} else {
that.paintingPolyline[that.paintingBeginNum].line = new BMapGL.Polyline(that.pLine, { strokeColor: "#589EFF", strokeWeight: 3, strokeOpacity: 1, });
that.map.addOverlay(that.paintingPolyline[that.paintingBeginNum].line); //绘制曲线
}
}
});
this.map.addEventListener("dblclick", function ({ latlng }) { //当鼠标双击时:结束绘制,并可以编辑曲线
if (that.paintingBeginData) {
that.paintingBeginData = false;//停止监听
that.startPainting = null;//把最终开始点去掉
// 线清空,为下一次刻画准备
that.pLine = [];
var marker = new BMapGL.Marker(latlng, { icon: new BMapGL.Icon(require('../../assets/images/mapIndex/LineDelete.png'), new BMapGL.Size(12, 12)) });
marker.setOffset(new BMapGL.Size(10, 10));
that.paintingPolyline[that.paintingBeginNum].deleteMarker = marker;
that.map.addOverlay(marker);
that.paintingPolyline[that.paintingBeginNum].line.disableEditing();//停止绘画
for (var i = 0; i < that.paintingPolyline.length; i++) {
that.paintingPolyline[i].deleteMarker.addEventListener("click", function (type) {
for (var j = 0; j < that.paintingPolyline.length; j++) {
if (type.currentTarget == that.paintingPolyline[j].deleteMarker) {
that.map.removeOverlay(that.paintingPolyline[j].line);
that.map.removeOverlay(that.paintingPolyline[j].deleteMarker);
for (var k = 0; k < that.paintingPolyline[j].marker.length; k++) {
that.map.removeOverlay(that.paintingPolyline[j].marker[k]);
}
}
}
})
}
}
})
},