1.说明:
- 该实例是可以用到地图的常用功能,对付一般和类似的业务场景都绰绰有余,在图层的选择上还是建议选择天地图的在线地地图,选择4326--84坐标系,地图上没有偏差。
- 所有的功能都在一个demo下展示了,就涉及到功能的切换时定时器的关闭和开启,一般情况下,这些功能都是在单独的页面的,所有demo中的定时器的关闭和开启,有需要的朋友可以看看。
- 下面的效果只是部分gif展示,因为上传不了很大GIF动图。
2.效果展示:
2.1单点追踪:
2.2实时监控:
2.3历史轨迹:
2.4地图绘制:
3.代码:
3.1要知道:
- 以前一直没有用过ol,一直觉得ol是个很神奇的东西,以前全部的业务逻辑都是用高德,百度,谷歌。这次借着公司的前端di地图改变,学习了下ol,其实ol没有那么难。
- 用高德或者百度的说法:我们最常用的功能就是往地图上打一个marker,OK!在OL这里全部都是有层的概念,数据容器的概念。名字是我自己起的就是便于理解。加上合理的代码抒写方式,便于我们管理很多层的数据,无论是怎么样的业务需求。
- 因为OL用的是大量的面向对象的写法,很多地方需要大量的对象实例化,因为我们要本着有些实例可以共用,就实例化一次的原则写代码,这样内存的压力会少很多。我的个人推荐写法就是提前把共用的实例配置到全局,用的时候,调用下实例就可以。
3.2 追踪模式:
me.all_obj = {
// =======================追踪
monitor: {
//
layer: null,
// 数据层
data_c: null,
// marker
p_data: null,
// 定时器标识
timer: null,
// 刷新标识
key: true,
},
};
- 选择nav项的单点追踪,走下面的函数,具体可以看代码。
- 初始化函数 1:设置下进入该功能的一些参数设置;2:构建下层对象和数据容器对象。(我自己的习惯)
_monitor: function() {
// 初始化参数
me._monitor_set();
// 层构建
me._monitor_layer();
// 打点
me._monitor_p();
// 开始移动
me._monitor_init();
},
// 层数据
_monitor_layer: function() {
// 层
me.all_obj.monitor.layer = new ol.layer.Vector();
// 数据容器
me.all_obj.monitor.data_c = new ol.source.Vector();
// 注入层
me.all_obj.monitor.layer.setSource(me.all_obj.monitor.data_c);
// 打到地图上
me.map.addLayer(me.all_obj.monitor.layer);
},
- 3:进行数据打点渲染,看下面的代码是全部过程。在前端模拟数据的时候,把模拟的走过的路线数据注入我们设置的数据层,就渲染到地图上了。
// 层数据
_monitor_layer: function() {
// 层
me.all_obj.monitor.layer = new ol.layer.Vector();
// 数据容器
me.all_obj.monitor.data_c = new ol.source.Vector();
// 注入层
me.all_obj.monitor.layer.setSource(me.all_obj.monitor.data_c);
// 打到地图上
me.map.addLayer(me.all_obj.monitor.layer);
},
// 点
_monitor_p: function() {
// console.log(mk_data_c);
// 创建一个活动图标需要的Feature,并设置位置
var p_data = new ol.Feature({
// 就一个参数啊,定义坐标
geometry: new ol.geom.Point(me.conf.monitor.p)
});
p_data.setStyle(new ol.style.Style({
// 设置一个标识
image: new ol.style.Icon({
src: './img/user.png',
// 这个是相当于是进行切图了
// size: [50,50],
// 注意这个,竟然是比例 左上[0,0] 左下[0,1] 右下[1,1]
anchor: [0.5, 0.5],
// 这个直接就可以控制大小了
scale: 0.5
}),
text: new ol.style.Text({
// 对其方式
textAlign: 'center',
// 基准线
textBaseline: 'middle',
offsetY: -30,
// 文字样式
font: 'normal 16px 黑体',
// 文本内容
text: "name:admin",
// 文本填充样式
fill: new ol.style.Fill({
color: 'rgba(255,255,255,1)'
}),
padding: [5, 5, 5, 5],
backgroundFill: new ol.style.Fill({
color: 'rgba(0,0,255,0.6)'
}),
})
}));
// 数据层收集marker
me.all_obj.monitor.data_c.addFeature(p_data);
// 最优一次
// 最优一次
me._map_fit(me.all_obj.monitor.data_c);
// 拿到全局
me.all_obj.monitor.p_data = p_data;
},
// 开始追踪
_monitor_init: function() {
// 追踪
var old_p = null;
var new_p = [0, 0];
me.all_obj.monitor.timer = setTimeout(function() {
// 得到旧的点
old_p = me.all_obj.monitor.p_data.getGeometry().flatCoordinates;
// ***********************************模拟数据
if (Math.random() > 0.5) {
new_p[0] = old_p[0] + Math.random() * me.conf.monitor.set_num;
} else {
new_p[0] = old_p[0] - Math.random() * me.conf.monitor.set_num;
}
if (Math.random() > 0.5) {
new_p[1] = old_p[1] + Math.random() * me.conf.monitor.set_num;
} else {
new_p[1] = old_p[1] - Math.random() * me.conf.monitor.set_num;
}
// *******************************************
if (me.all_obj.monitor.key) {
// 移动点--改变这个数据就行了
me.all_obj.monitor.p_data.setGeometry(new ol.geom.Point(new_p));
// 线的数据
me._monitor_init_line(new_p, old_p);
//
me._monitor_init();
console.log('monitor');
}
}, me.conf.monitor.time);
},
- 注意这里在渲染走过的路线的数据的样式,就是我前面说到的全局配置好的样式。me.conf.monitor.line_style
// 初始化线
_monitor_init_line: function(new_p, old_p) {
var line_data = new ol.Feature({
geometry: new ol.geom.LineString([old_p, new_p])
});
line_data.setStyle(me.conf.monitor.line_style);
// 注入容器
me.all_obj.monitor.data_c.addFeature(line_data);
},
me.conf = {
// 追踪模式
monitor: {
// 起点坐标
p: [116.06, 39.67],
// 波动系数
set_num: 0.05,
// 线的样式
line_style: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 3,
color: [255, 0, 0, 1],
lineDash: [10, 10],
})
}),
// 刷新时间
time: 1000,
},
};
3.3 实时监控:
- 实时监控和单点追踪这个业务场景大同小异。适用于实时ji监控某些点的状态(例如:报警状态,实时位置,实时推送的信息)。该demo的实时监控就是监控了一些点的报警状态,我这里简单的做了两个状态,红色为报警,绿色为正常。
- 这里没有优化的地方,也是我目前想不出怎么优化的地方就是,因为每个点的名字都不一样,所以我每个点只能实例化一个样式对象,然后分别注入到数据中。在下次数据过来时,可以找每个点的对象的样式对象,修改点的状态的图片。
- 该次demo没有尝试上面的优化方法,有已经尝试的同学可以留言讨论。这里我用的OL v5.0的版本,比3.0的版本在样式上存在很多优化,还是建议同学们用最新的API和版本。
- 代码实现的风格都是统一的:(前面设置可以配置的参数和监控的对象体,全部监控的函数内部仍然是:初始化参数,构建层和数据容器,开启数据渲染)
// 实时监控所有
_all_monitor: function() {
// 参数设置
me._all_monitor_set();
// 设置层
me._all_monitor_layer();
// 初始化
me._all_monitor_init(ps_arr);
// 最优一次
me._map_fit(me.all_obj.all_monitor.data_c);
},
3.4 历史轨迹:
- OL是没有高德和百度那么丰富的API的,所以历史轨迹的还的自己实现。历史轨迹业务的实现思想就是 定时器加递归,在每次到达下一个点的时候,等待一秒移动到下一个点。移动到终点的时候,可以做个友好提示:
// 开始运动
_history_start: function(index) {
// 开始运动
setTimeout(function() {
index++;
if (index == lines_arr.length) {
// 运动完毕
me.conf.history.move_key = false;
layer.msg('运动完毕');
$('#his_s').show();
return;
}
//
else {
console.log('moving---')
me.all_obj.history.p_data.setGeometry(new ol.geom.Point(lines_arr[index]));
me._history_start(index);
}
}, me.conf.history.time);
},
- 历史轨迹就比较简单了,点的样式和线的样式因为只有一次渲染,可以配置到全局,也可以在用的时候实例化,个人建议把这些UI性的东西配置到全局,以防你的产品经理~~~嘿嘿嘿~~
3.5 地图绘制:
- 地图绘制其实API不难,难是业务的屡清楚。
- 下面是我自己屡的一些功能节点,不合理的地方请留言。
- 进入地图绘制功能后,先和后台请求数据,把原来已经画好的数据先打在地图上。现在是进入选择绘画模式,这个模式下你可以进行 【选择样式】、选择后绘画完成后的【绘画完成】,对当前已经画的数据【进入编辑】,下面有全部清除数据的【清除画布】,和对当前层的数据进行【保存画布】。
// 围栏事件的模式选择
_fence_ev_mode: function() {
// me._fence_sel();
// 有数据--可以清除画布 可以编辑画布
if (me.conf.fence.mode == 1) {
$('#tool')
.show()
.html(`
开启编辑
编辑完成
退出编辑
`)
.off()
// 开启编辑
.on('click', '#f_edit_ing', function() {
me._fence_edit_ing();
})
// 编辑完成
.on('click', '#f_edit_done', function() {
me._fence_edit_done();
})
.on('click', '#f_edit_out', function() {
me._fence_edit_out();
});
// 编辑完成先影藏
$('#f_edit_ing').show();
$('#f_edit_done').hide();
}
// 没有数据--选择样式/绘画完成
else if (me.conf.fence.mode == 2) {
$('#tool')
.show()
.html(`
选择样式
绘画完成
进入编辑
**
清除画布
保存画布
`)
.off()
// 选择样式
.on('click', '#f_sel', function() {
me._fence_sel();
})
// 绘制完成
.on('click', '#f_draw_done', function() {
me._fence_draw_done();
})
// 进入编辑
.on('click', '#f_in_edit', function() {
me._fence_in_edit();
})
// 清除
.on('click', '#f_clear', function() {
me._fence_clear();
})
// 保存数据
.on('click', '#f_save', function() {
me._fence_save();
});
}
},
- 【选择样式】进行绘制,我这里把我img文件夹下面所有的图片都作为一个样式可以进行绘制:
- 提供的样式有 5中,图标、点、线 、圆、多边形。需要注意的是,图片的样式需要每次实例化,点、线 、圆、多边形的样式都可以提前设置。写博客的时候发现还可以对图标的样式代码进行优化,就是每次用图标的样式先判断有没有,没有的话就实例化一个,配置到我们的全局,有的话也是上次实例化的直接用就可以。
- 还需要注意的就是在初始化图片的时候,就把图片代表的类型作为属性付过去,再绘制完成要把这些属性挂载到数据上,以便在提交的数据的时候,我们知道我们提交的是什么类型的数据,分别要数据内容的哪些参数。
// ==========================绘画模式
// 绘制选择
_fence_sel: function() {
layer.open({
type: 1,
title: false,
area: ['520px', '600px'],
skin: 'cc_layer',
anim: 1,
shade: 0.6,
closeBtn: 0,
btn: false,
content: `
`,
success: function(layero, index) {
// 取消事件
me._fence_sel_cancel(index);
// 加载图片
me._fence_sel_img();
// 绘画初始化
me._fence_sel_init(index);
},
});
},
// 取消事件
_fence_sel_cancel: function(index) {
// 取消
$('#cancel')
.off()
.on('click', function() {
layer.close(index);
});
},
// 开始绘制的加载图片
_fence_sel_img: function() {
var str = '';
// 加载图标
for (var name in me.conf.fence.icon) {
str += `
${name}
`;
}
$('#sel_box').html(str);
var key = null;
$('#sel_box')
.off()
.on('click', '.box', function(e) {
key = $(e.currentTarget).hasClass('ac');
// 点击其他项目
if (!key) {
$('#sel_box .box').removeClass('ac');
$(e.currentTarget).addClass('ac');
// 全局拿到绘制的样式的ID
me.conf.fence.type = $(e.currentTarget).attr('type');
me.conf.fence.type_id = $(e.currentTarget).attr('type_id');
}
});
},
// 开始绘制初始化
_fence_sel_init: function(index) {
$('#save')
.off()
.on('click', function() {
// 初始化工具
me._fence_sel_tool_drawing();
// 关闭图层
layer.close(index);
});
},
// 初始化绘画工具绘画中
_fence_sel_tool_drawing: function() {
// 清除工具
if (me.all_obj.fence.draw_tool != null) {
me.map.removeInteraction(me.all_obj.fence.draw_tool);
}
// 不是icon
if (me.conf.fence.type != 'icon') {
// 工具
me.all_obj.fence.draw_tool = new ol.interaction.Draw({
type: me.conf.fence.type,
// 注意设置source,这样绘制好的线,就会添加到这个source里
source: me.all_obj.fence.data_c,
// 设置绘制时的样式
style: me.conf.fence.style[me.conf.fence.type],
});
}
// icon
else {
// 设置样式
me.conf.fence.style[me.conf.fence.type] = new ol.style.Style({
// 绘制的那个标记
image: new ol.style.Icon({
src: me.conf.fence.icon[me.conf.fence.type_id].src,
// 注意这个,竟然是比例 左上[0,0] 左下[0,1] 右下[1,1]
anchor: [0.5, 0.5],
// 这个直接就可以控制大小了
scale: 0.5
}),
});
// 工具
me.all_obj.fence.draw_tool = new ol.interaction.Draw({
type: "Point",
// 注意设置source,这样绘制好的线,就会添加到这个source里
source: me.all_obj.fence.data_c,
// 设置绘制时的样式
style: me.conf.fence.style[me.conf.fence.type],
});
}
// 添加工具
me.map.addInteraction(me.all_obj.fence.draw_tool);
// 每次绘制完成
me.all_obj.fence.draw_tool
.on('drawend', function(event) {
// event.feature 就是当前绘制完成的线的Feature
event.feature.setStyle(me.conf.fence.style[me.conf.fence.type]);
// 挂载属性
event.feature.type = me.conf.fence.type;
event.feature.type_id = me.conf.fence.type_id;
// console.log(me.conf.fence.type,me.conf.fence.type_id)
});
},
- 源码: 源码(谢谢star)
- 线上地址:http://ol.armincc.com