Leafletjs 學習
最近做的項目很大部分的需求都是和室內地圖相關的,學習一下。
gif
圖片加載偏慢,再吐槽一下簡書,做個生成目錄就那么難嗎?
0. 其它
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);
}
上述是結合個人的項目來整理的,官網的例子要清楚很多!