Leafletjs 学习
最近做的项目很大部分的需求都是和室内地图相关的,学习一下。
gif
图片加载偏慢,再吐槽一下,做个生成目录就那么难吗?
0. 其它
链接:vue移动端商城实战项目
链接:百度地图--点聚合 + 弹窗事件
链接:Leafletjs 官网
参考:Leafletjs参考学习的文章(4星半)
参考:leaflet 自定义 Marker(4星)
1. 关于地图控件
百度地图、高德地图等在室内地图方面都不是很友好,这也是绝大部分地图控件的问题,着重的问题是没有办法让使用系统的用户自己添加自己的地图,可能有其它的技术,但是我不知道啊~;
关于室内地图,
3D
效果的地图是比较好的,但是我也还没有接触到,而且好像也没有比较好的学习路子,找到的所有能做室内3D
地图的都是收费的,这里重点指的是所有。想要自己做的话,可能要用canvas
+D3js
+Treejs
之类的,比较麻烦啊~Leafletjs
是完全免费的,重点是完全免费,功能上面可能有些不足但是人家免费啊,而且插件比较多,还有缺点就是差不多都是英文的,查文档比较难。
2. 结合项目点、线、区域的效果
这里的点、线、区域都是提前绘制,把相应的坐标点存入数据库,最后在这个页面统一获取显示;
这里的需求是,点==物资和人员,线==安全路线,区域==监测的范围,所有点、线、区域都要绑定地图与绑定报警事件,一旦事件触发,则显示相应的点、线、区域。
3. 布置地图
所有的操作都是建立在地图上的
// 最主要的是这一步,下面请求操作是根据业务需求添加
var maplet = L.map('map', {
crs: L.CRS.Simple,
minZoom: -2,
zoomControl: false
});
var bounds = [
[0, 0],
[1021.5, 1023]
];
var imageObj = new Image();
var image = L.imageOverlay("", bounds).addTo(maplet);
// 请求数据,拿到地图的 URL,这里的地图数据在地图管理模块添加完成
mymap(mapid)
function mymap(mapid) {
$.ajax({
url: localStorage.baseUrl + `/Map/GetMapByMapId?TOKEN=${localStorage.token}&MAP_ID=${mapid}`,
async: true,
type: 'GET',
dataType: "json",
success: function (data) {
console.log(data)
var url = localStorage.temp + data.rows[0].URL;
imageObj.src = url;
init(url)
}
})
}
// 布置地图
function init(url) {
imageObj.onload = function () {
x = imageObj.width;
y = imageObj.height;
image.setUrl(imageObj.src).setBounds([[0, 0], [y, x]])
console.log(x, y)
maplet.setView([y / 2, x / 2], 0);
}
}
4. 点操作(自定义Marker
)
严格来说整个控件是没有绘制点的操作的,可以绘制圆,但是这里并不是圆,用绘制Marker点来显示
- 首先定义一个图标(
icon
)对象
// 最后是根据坐标点来用图标显示,图标的属性可以自定义
var CustomerIcon = L.Icon.extend({
options: {
// 图标图片的地址
iconUrl: '../../images/new/xiaofangdiliweizhi.svg',
// 图标阴影的地址
shadowUrl: '../../images/new/xiaofangdiliweizhi.svg',
// 图标大小
iconSize: [38, 95],
// 图标偏离的位置
shadowSize: [50, 64],
// 图标阴影的大小
iconAnchor: [20, 65]
}
});
- 通过点击事件创建
Marker
,获取点坐标
// 创建地图时的 maplet ,添加点击事件
maplet.on('click', (ev) => {
console.log(ev)
// 创建 marker
let marker = new L.Marker(ev.latlng, {
// 图标
icon: new CustomerIcon()
}).addTo(maplet)
// 打印点的横纵坐标
console.log(ev.latlng.lat,ev.latlng.lng)
// 根据需求,横纵坐标点 push 进数组
var mark = []
mark.push(ev.latlng.lat)
mark.push(ev.latlng.lng)
// 保存到数据库的函数
layop(mark)
})
-
效果
5. 绘制线
绘制线与绘制点的本质相同,最终的目的都是获取点坐标数组
- 绘制线例子
// 动态绘线主要涉及到三个事件:click,dbclick,mousemove。
// click确定线的折点,dbclick确定线的终点,mousemove绘制鼠标移动过程中图形的变化。
var points=[]
var lines=new L.polyline(points)
var tempLines=new L.polyline([])
map.on('click', onClick); //点击地图
map.on('dblclick',onDoubleClick);
//map.off(....) 关闭该事件
function onClick(e)
{
points.push([e.latlng.lat,e.latlng.lng])
lines.addLatLng(e.latlng)
map.addLayer(lines)
map.addLayer(L.circle(e.latlng,{color:'#ff0000',fillColor:'ff0000',fillOpacity:1}))
map.on('mousemove',onMove)//双击地图
}
function onMove(e) {
if(points.length>0) {
ls=[points[points.length-1],[e.latlng.lat,e.latlng.lng]]
tempLines.setLatLngs(ls)
map.addLayer(tempLines)
}
}
function onDoubleClick(e)
{
L.polyline(points).addTo(map)
points=[]
lines=new L.polyline(points)
map.off('mousemove')
}
- 结合项目添加事件
//绘制线路---start--
// 点击事件,点击后可以绘制
$("#overlayCompany").on("click", function () {
mapopen = true;
})
var linesline = new L.polyline([])
var tempLines = new L.polyline([], {
dashArray: 10
})
maplet.on('click', onClick); //点击地图
maplet.on('dblclick', onDoubleClick);
maplet.on('mousemove', onMove);//双击地图
function onClick(e) {
if (mapopen) {
pointsline.push([e.latlng.lat, e.latlng.lng])
linesline.addLatLng(e.latlng)
maplet.addLayer(linesline)
maplet.addLayer(L.circle(e.latlng, {
color: '#ff0000', fillColor: 'ff0000', fillOpacity: 1
}))
maplet.on('mousemove', onMove)
}
}
function onMove(e) {
if (mapopen) {
if (pointsline.length > 0) {
lsline = [pointsline[pointsline.length - 1], [e.latlng.lat, e.latlng.lng]]
tempLines.setLatLngs(lsline)
maplet.addLayer(tempLines)
}
}
}
// 鼠标双击事件(双击绘制线结束)
function onDoubleClick(e) {
if (mapopen) {
var polygon = L.polyline(pointsline).addTo(maplet)
ploverlays.push({polygon})
overlays = pointsline.slice(0, pointsline.length - 1);
// 坐标点数组,主要的就是获取这个坐标点数组,下面的操作根据需求进行
pointsline = []
linesline.remove()
tempLines.setLatLngs([]);
linesline = new L.polyline(pointsline)
mapopen = false;
// 根据需求处理坐标点形式
var polygon2 = "";
overlays.forEach(function (item, index) {
polygon2 += item[0] + "-" + item[1] + ",";
})
polygon2 = polygon2.split(",");
var polygonnew = polygon2.slice(0, polygon2.length - 1).join(",")
console.log(polygonnew)
// 添加函数等需求
optiontype = "add";
$("#subregion").text("提交");
initmodal()
$("#editregion").modal({
backdrop: 'static',
keyboard: false
});
$("#mapid").val(''+mapfloor+'');
$("#region").val(''+polygonnew+'');
}
}
-
效果
6. 绘制面(多边形)
绘制面与绘制线本质也是相同的,主要也是获得坐标点
- 绘制多边形的例子
var points=[]
var lines=new L.polyline([])
var tempLines=new L.polyline([],{dashArray:5})
map.on('click', onClick); //点击地图
map.on('dblclick',onDoubleClick);
map.on('mousemove',onMove)//双击地图
//map.off(....) 关闭该事件
function onClick(e)
{
points.push([e.latlng.lat,e.latlng.lng])
lines.addLatLng(e.latlng)
map.addLayer(tempLines)
map.addLayer(lines)
map.addLayer(L.circle(e.latlng,{color:'#ff0000',fillColor:'ff0000',fillOpacity:1}))
}
function onMove(e) {
if(points.length>0) {
ls=[points[points.length-1],[e.latlng.lat,e.latlng.lng],points[0]]
tempLines.setLatLngs(ls)
// map.addLayer(tempLines)
}
}
function onDoubleClick(e)
{
L.polygon(points).addTo(map)
points=[]
//map.removeLayer(tempLines)
//tempLines.remove()
lines.remove()
tempLines.remove()
lines=new L.polyline([])
}
-
效果
7. 总结
上面的绘制操作是得到坐标点存入数据库,而最终需要取用坐标点来展示
- 获得点展示
// 上面异步获取数据 pointdata ,里面包含坐标点信息
for (let i = 0; i < pointdata.length; i++) {
// 坐标点
let matpoint = pointdata[i].POSITION ? pointdata[i].POSITION.split(",") : [];
console.log(matpoint)
let maticon = pointdata[i].ICON
// 图标
var myicon = '' + maticon + ''
var iconmat = new L.Icon({
iconUrl: '../../images/new/' + myicon + '.svg',
shadowUrl: '../../images/new/' + myicon + '.svg',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
})
var markermat = null;
markermat = L.marker(matpoint, {
icon: iconmat
});
// 显示名字
markermat.bindTooltip(pointdata[i].ITEM_NAME ? pointdata[i].ITEM_NAME : pointdata[i].LABEL_ID).openTooltip();
// 显示弹窗
var popupmat = L.popup({
maxWidth: 700,
maxHeight: 600
}).setLatLng(matpoint)
buildings.addLayer(markermat);
}
buildings.addTo(maplet)
- 获得线展示
流动线效果(动态线渲染),需要添加插件
leaflet-ant-path.js
// 异步获取到相应数据后,执行函数 line()
function line(longLatList) {
if (path) {
maplet.removeLayer(path);
}
// 流动线效果(动态线渲染),需要添加插件 ‘leaflet-ant-path.js’
var antPath = L.polyline.antPath;
var path = antPath(longLatList, {
"paused": false, //暂停 初始化状态
"reverse": false, //方向反转
"delay": 150, //延迟,数值越大效果越缓慢
"dashArray": [20, 35], //间隔样式
"weight": 10, //线宽
"opacity": 0.5, //透明度
"color": "red", //颜色
"pulseColor": "#FFFFFF" //块颜色
});
path.addTo(maplet).bindPopup("green to red");
// 缩放地图到折线所在区域
maplet.fitBounds(path.getBounds());
}
- 获得多边形展示
polArr 为点的数组,可以是多维数组,以
[ [[a1 ], [ a2]], [[b1 ], [ b2]],...... ]
形式都可以
// polArr 为点的数组,可以是多维数组,以 [ [[a1 ], [ a2]], [[b1 ], [ b2]],...... ] 形式都可以
function getRegion(polArr) {
// console.log(polArr)
var polygon = L.polygon(polArr, {
color: '#000eff',
fillColor: '#0000ed',
weight: 0.2
}).addTo(maplet);
}
上述是结合个人的项目来整理的,官网的例子要清楚很多!