Leafletjs--点、线、多边形的绘制

Leafletjs 学习

最近做的项目很大部分的需求都是和室内地图相关的,学习一下。

gif 图片加载偏慢,再吐槽一下简书,做个生成目录就那么难吗?

0. 其它

1. 关于地图控件

  • 百度地图、高德地图等在室内地图方面都不是很友好,这也是绝大部分地图控件的问题,着重的问题是没有办法让使用系统的用户自己添加自己的地图,可能有其它的技术,但是我不知道啊~;

  • 关于室内地图,3D效果的地图是比较好的,但是我也还没有接触到,而且好像也没有比较好的学习路子,找到的所有能做室内3D地图的都是收费的,这里重点指的是所有。想要自己做的话,可能要用canvas+D3js+Treejs之类的,比较麻烦啊~

  • Leafletjs 是完全免费的,重点是完全免费,功能上面可能有些不足但是人家免费啊,而且插件比较多,还有缺点就是差不多都是英文的,查文档比较难。

2. 结合项目点、线、区域的效果

  • 这里的点、线、区域都是提前绘制,把相应的坐标点存入数据库,最后在这个页面统一获取显示;

  • 这里的需求是,点==物资和人员线==安全路线区域==监测的范围,所有点、线、区域都要绑定地图与绑定报警事件,一旦事件触发,则显示相应的点、线、区域。

效果.gif
效果图.png

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)
        })
  • 效果


    点坐标.gif

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+'');
            }
        }
  • 效果


    绘制线.gif

    线坐标.png

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([])
    }
  • 效果


    区域效果展示.gif

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);
        }

上述是结合个人的项目来整理的,官网的例子要清楚很多!

点个赞呗!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342