需求:在地图上画出围栏,设置围栏信息后保存,生成围栏列表。全选时,地图视野可看到全部的围栏区域,单独勾选会调整地图视野到当前勾选的围栏。围栏区域的中心点要显示围栏名称。
主要的难点(对于我而言)不在于画,而在于设置地图视野和围栏区域的中心点显示围栏名称,其实也不算难,主要是花比较多时间去看百度地图api,还有动手实践。(所以还是那句老话百度找不到答案就去看api文档,答案都在里面)。
以下主要说一下思路:
1.引入百度地图还有鼠标绘制管理类库DrawingManager
2.以下主要贴部分代码说明:
var electronitFence = {
//此处代码省略...
tableData: {},//保存每次list请求返回的数据
overlayObj: {},//保存图形对象(map)
labelObj: {},//保存label对象(map)
path: '',//当前新增围栏图形path
pointArray: [],//坐标点数组用于调整地图视野范围
styleOptions: {//图形样式
enableClicking: false,
strokeColor: "blue", //边线颜色。
fillColor: "red", //填充颜色。当参数为空时,圆形将没有填充效果。
strokeWeight: 2, //边线的宽度,以像素为单位。
strokeOpacity: 0.6, //边线透明度,取值范围0 - 1。
fillOpacity: 0.5, //填充的透明度,取值范围0 - 1。
strokeStyle: 'solid' //边线的样式,solid或dashed。
},
init: function () {
//此处代码省略...
this.mapInit();
this.bindEvent();
//此处代码省略...
},
bindEvent:function(){
//新增围栏
$('#overlayType li').on('click', function () {
var index = $(this).index();
drawingManager.open();//开启地图的绘制模式
if (index == 0) {
drawingManager.setDrawingMode(BMAP_DRAWING_RECTANGLE);//绘制矩形
} else if (index == 1) {
drawingManager.setDrawingMode(BMAP_DRAWING_CIRCLE);//绘制圆形
} else {
drawingManager.setDrawingMode(BMAP_DRAWING_POLYGON);//绘制多边形
}
});
//全选
$('#checkAll').on('change', function () {
if ($(this).is(":checked")) {//全选
$('#page-list .checkItem').prop("checked", true);
self.pointArray.length = 0;//清空pointArray
self.curPageOverlayAllShow();//显示全部
map.setViewport(self.pointArray); //调整视野
} else {
$('#page-list .checkItem').prop("checked", false);
self.curPageOverlayAllHide();//隐藏全部
}
});
//单选
$('#page-list').on('change', '.checkItem', function () {
if ($(this).is(":checked")) {
if (!$('#checkAll').is(":checked")) {
$('#checkAll').prop("checked", true);
}
self.pointArray.length = 0;//清空pointArray
self.overlayShow(+$(this).val());//显示
map.setViewport(self.pointArray); //调整视野
} else {
self.overlayHide(+$(this).val());//隐藏
if ($('.checkItem:checked').length == 0) {
$('#checkAll').prop("checked", false);
}
}
});
},
/**
* map初始化
*/
mapInit: function () {
var self = electronitFence;
map = new BMap.Map('mapBox', {minZoom: 4, maxZoom: 16});
map.centerAndZoom(new BMap.Point(116.4035, 39.915), 5);
map.enableScrollWheelZoom();
//实例化鼠标绘制工具(我不需要工具栏所以直接注释了)
drawingManager = new BMapLib.DrawingManager(map, {
isOpen: false, //是否开启绘制模式
//enableDrawingTool: false, //是否显示工具栏
//drawingToolOptions: {
//anchor: BMAP_ANCHOR_TOP_RIGHT, //位置
// offset: new BMap.Size(5, 5) //偏离值
//},
circleOptions: self.styleOptions, //圆的样式
polygonOptions: self.styleOptions, //多边形的样式
rectangleOptions: self.styleOptions //矩形的样式
});
//添加鼠标绘制工具监听事件,用于获取绘制结果
drawingManager.addEventListener('overlaycomplete', electronitFence.overlayComplete);
},
overlayComplete: function (e) {
var self = electronitFence;
var path = {};
var bs = e.overlay.getBounds();//覆盖物对象的地理区域范围
if (e.drawingMode == BMAP_DRAWING_CIRCLE) {//圆形
path.radius = e.overlay.getRadius();//半径
path.center = {};//中心点坐标
path.center.lng = e.overlay.getCenter().lng;
path.center.lat = e.overlay.getCenter().lat;
path.path = [bs.getSouthWest(), bs.getNorthEast()];//****这个是重点:用来保存圆形的地理区域范围(Bounds)东北角和西南角坐标,用于地图视野调整
} else {//矩形或多边形
path.data = e.overlay.getPath();
path.center = bs.getCenter();//****这个是重点:用于在图形中心点显示围栏名称
}
self.path = JSON.stringify(path);//这个会传给后端保存,请求回围栏列表数据中会一起返回,用于画出对应的图形
//此处代码省略...
},
//此处代码省略...
/**
* 在地图上新建图形
* @param id
* @param type
* @returns {*}
*/
newOverlay: function (id, type) {
var self = electronitFence;
var overlay = null;
var path = JSON.parse(self.tableData[id].coordinate);//tableData[id]是围栏列表数据,coordinate保存的是上面的path 值
if (type == 2) {//圆形
var mPoint = new BMap.Point(path.center.lng, path.center.lat);
overlay = new BMap.Circle(mPoint, path.radius, style);
self.pointArray = self.pointArray.concat(path.path);
} else {//矩形或四边形
overlay = new BMap.Polygon(path.data, style);
self.pointArray = self.pointArray.concat(path.data);
}
self.overlayObj[id] = {};
self.overlayObj[id].overlay = overlay;//添加到overlayObj
map.addOverlay(overlay);
//创建label,显示围栏名称
var opts = {position: path.center};
var label = new BMap.Label(self.tableData[id].fenceName, opts);
label.setStyle(self.labelStyle);
label.addEventListener('click', function () {
var carPath = JSON.parse(self.tableData[id].coordinate);//坐标点
self.pointArray.length = 0;
if (type == 2) {//圆
self.pointArray = carPath.path;
} else {
self.pointArray = carPath.data;
}
map.setViewport(self.pointArray); //调整视野
});
self.labelObj[id] = {};
self.labelObj[id].label = label;
map.addOverlay(label);
},
/**
* 图形显示
* @param id
*/
overlayShow: function (id) {
var self = electronitFence;
var type = self.tableData[id].coordinateType;//图形类型
var path = JSON.parse(self.tableData[id].coordinate);//坐标点
if (self.overlayObj[id]) {//如果overlayObj中有就show
self.overlayObj[id].overlay.show();
self.labelObj[id].label.setContent(self.tableData[id].fenceName);
self.labelObj[id].label.show();
if (type != 2) {//圆
self.pointArray = self.pointArray.concat(path.data);
} else {
self.pointArray = self.pointArray.concat(path.path);
}
} else {//如果overlayObj中无就new一个
self.newOverlay(id, type);
}
},
/**
* 图形隐藏
* @param id
*/
overlayHide: function (id) {
electronitFence.overlayObj[id].overlay.hide();
electronitFence.labelObj[id].label.hide();
},
/**
* 显示当前页所有图形
*/
curPageOverlayAllShow: function () {
$('.checkItem').each(function () {
electronitFence.overlayShow(+$(this).val());
})
},
/**
* 隐藏当前页所有图形
*/
curPageOverlayAllHide: function () {
var self = electronitFence;
$('.checkItem').each(function () {
var id = +$(this).val();
if (self.overlayObj[id]) {
self.overlayHide(id);
}
})
},
//此处代码省略...
}
$(function () {
electronitFence.init();
});
总结:可能有人会问为什么不在newOverlay的时候getSouthWest(),getNorthEast(),getCenter()。一开始我也这么做但是根据返回的数据坐标点新建overlay生成的overlay.getBounds()执行报错。目前还不知道原因。。。隐藏overlay,很多人可能都喜欢用map.removeOverlay()的方法直接删掉overlay,下次显示再new。我发现如果overlay很多的时候会new得很慢,如果每次new的时候保存在一个对象里面,直接通过overlay.show(),overlay.hide()显示隐藏会快很多。