leaflet室内地图\平面图点线面绘制

需求:

用户自定义上传一张平面图,然后可以在平面图内标点、绘制面、并且能够弹出相对应点、面的信息,信息可编辑,类似下图:

相关实现技术:leaflet

中文网:Leaflet - 一个交互式地图 JavaScript 库 (leafletjs.cn)

官方网:Leaflet - a JavaScript library for interactive maps (leafletjs.com)

官网相关示例:Overlays - Leaflet - 一个交互式地图 JavaScript 库 (leafletjs.cn) 

相关js跟css资源可在npm中下载:leaflet - npm (npmjs.com) 

开始编码demo

实现功能如下:加载平面图并默认生成一个点跟面、新增绘制点,面功能、编辑点,面弹出消息功能、删除点面功能、以及设置绘制面的颜色。全部代码如下:

<html>

<head>
    <link rel="stylesheet" href="./leaflet.css" />
    <script type="text/javascript" src="./jquery.min.js"></script>
    <script src="./leaflet.js"> </script>
    <script src="./leaflet-src.js"> </script>
    <script src="./leaflet-src.esm.js"> </script>
    <style>
        #image-map {
            min-width: 60vw;
            height: 80vh;
            border: 1px solid #ccc;
            margin-bottom: 10px;
        }

        #buttons {
            margin: 10px;
        }

        .activeBtn {
            color: white;
            background-color: #7070ff;
        }

        .btn {
            margin-right: 10px;
            padding: 10px;
            border: none;
            cursor: pointer;
        }

        .btnCol {
            margin-right: 10px;
            padding: 10px;
            border: none;
            cursor: pointer;
        }

        .delete-button {
            position: absolute;
            right: 0;
        }

        #markers-list,
        #polygons-list {
            flex: 1;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        #markers-list>div,
        #polygons-list>div {
            position: relative;
        }

        #markers-list .childDiv,
        #polygons-list .childDiv {
            cursor: pointer;
            margin: 10px;
            width: 150px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            border: 1px solid #eaeaea;
            border-radius: 50px;
            padding: 10px;
        }

        .allBox {
            display: flex;
            justify-content: space-between;
        }

        /* .leaflet-important {
            transform: translate3d(0px, 0px, 0px) !important;
        } */
        .leaflet-container {
            background-color: white;
        }

        .leaflet-bottom {
            display: none;
        }
    </style>
</head>

<body>

    <div id="buttons">
        <button id="add-marker-button" class="btn">新增标记点</button>
        <button id="draw-area-button" class="btn">绘制区域</button>
        <button id="red" class="btnCol">红色</button>
        <button id="green" class="btnCol activeBtn">绿色</button>
        <button id="orange" class="btnCol">橙色</button>
    </div>
    <div class="allBox">
        <div id="markers-list"></div>
        <div id="image-map"></div>
        <div id="polygons-list"></div>
    </div>


    <script>
        $(document).ready(function () {
            // 切换颜色按钮
            var DBXcolor = 'green';
            $("#red").click(function () {
                DBXcolor = 'red'
                $(".btnCol.activeBtn").removeClass("activeBtn");
                $(this).addClass('activeBtn')
            })
            $("#green").click(function () {
                DBXcolor = 'green'
                $(".btnCol.activeBtn").removeClass("activeBtn");
                $(this).addClass('activeBtn')
            })
            $("#orange").click(function () {
                DBXcolor = 'orange'
                $(".btnCol.activeBtn").removeClass("activeBtn");
                $(this).addClass('activeBtn')
            })

            // 创建一个Leaflet地图实例
            var map = L.map('image-map', {
                minZoom: 1,        // 设置地图的最小缩放级别
                maxZoom: 4,        // 设置地图的最大缩放级别
                crs: L.CRS.Simple  // 使用简单的坐标参考系统,适用于平面图片的映射
            });

            // 定义图片的宽度和高度,以及图片的路径
            let w = 3200,
                h = 2600,
                url = './base.png';

            // 将像素坐标转换为经纬度坐标,并定义图片的边界(西南和东北角)
            var southWest = map.unproject([0, h], map.getMaxZoom() - 1);    // 西南角像素坐标映射为经纬度坐标
            var northEast = map.unproject([w, 0], map.getMaxZoom() - 1);    // 东北角像素坐标映射为经纬度坐标
            var bounds = new L.LatLngBounds(southWest, northEast);          // 创建边界范围

            // 在地图上添加图片覆盖层,并指定图片的边界范围以及位置
            L.imageOverlay(url, bounds).addTo(map);
            map.fitBounds(bounds);


            // 在地图上添加标记,并绑定弹出窗口,默认情况下弹出窗口是打开的
            let newMarkerId1 = generateUniqueId('marker');
            let customIcon = L.icon({
                iconUrl: 'one.gif',
                iconSize: [64, 52], // 设置图标大小
                iconAnchor: [32, 32], // 设置图标的中心点
                popupAnchor: [0, -32] // 设置弹出窗口的位置
            });
            let divStr = `
            <div>
        <div style="display: flex;">
            <div>相机名称:</div>
            <div>xxx</div>
        </div>
        <div style="display: flex;">
            <div>报警地址:</div>
            <div>xxx</div>
        </div>
        <div style="display: flex;">
            <div>报警类型:</div>
            <div>xxx</div>
        </div>
        <div style="display: flex;">
            <div>报警次数:</div>
            <div>xxx</div>
        </div>
    </div>`
            let marker = L.marker([-180, 200], { icon: customIcon, id: newMarkerId1 }).addTo(map).bindPopup(divStr).openPopup();
            // 添加mouseover事件
            marker.on('mouseover', function (e) {
                this.openPopup();
            });

            // 添加mouseout事件
            marker.on('mouseout', function (e) {
                this.closePopup();
            });

            // 在地图上添加一个多边形,并绑定弹出窗口
            let newPolygonId = generateUniqueId('polygon');
            L.polygon([
                [-200, 80],
                [-250, 80],
                [-120, 150],
                [-140, 100]
            ], { id: newPolygonId, color: 'green' }).addTo(map).bindPopup("多边形");

            function generateUniqueId(prefix) {
                return prefix + '_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
            }

            // 获取当前地图上所有的 marker 和 polygon 信息
            function getMapLayersInfo() {
                let markers = [];
                let polygons = [];
                map.eachLayer(function (layer) {
                    if (layer instanceof L.Marker) {
                        let markerInfo = {
                            id: layer.options.id || null,
                            latlng: layer.getLatLng(),
                            popup: layer.getPopup() ? layer.getPopup().getContent() : null
                        };
                        markers.push(markerInfo);
                    } else if (layer instanceof L.Polygon) {
                        let polygonInfo = {
                            id: layer.options.id || null,
                            latlngs: layer.getLatLngs(),
                            popup: layer.getPopup() ? layer.getPopup().getContent() : null
                        };
                        polygons.push(polygonInfo);
                    }
                });

                // 遍历并添加markers到HTML中
                let markersList = $('#markers-list');
                markersList.empty();
                $.each(markers, function (index, marker) {
                    let markerElementBox = $('<div></div>');
                    let markerElementChild = $('<div></div>').text(`Marker ID: ${marker.id}`).addClass('childDiv');

                    // 创建删除按钮
                    let deleteButton = $('<button>X</button>').addClass('delete-button');
                    deleteButton.on('click', function (event) {
                        event.stopPropagation();
                        handleMarkerDoubleClick(marker.id);
                    });

                    // 将删除按钮添加到 markerElementChild 中
                    markerElementBox.append(deleteButton);
                    markerElementBox.append(markerElementChild);

                    markerElementChild.on('click', function () {
                        handleMarkerClick(marker.id);
                    });

                    markersList.append(markerElementBox);
                });

                // 遍历并添加polygons到HTML中
                let polygonsList = $('#polygons-list');
                polygonsList.empty();
                $.each(polygons, function (index, polygon) {
                    let polygonElementBox = $('<div></div>');
                    let polygonElementChild = $('<div></div>').text(`Polygon ID: ${polygon.id}`).addClass('childDiv');

                    // 创建删除按钮
                    let deleteButton = $('<button>X</button>').addClass('delete-button');
                    deleteButton.on('click', function (event) {
                        event.stopPropagation();
                        handlePolygonDoubleClick(polygon.id);
                    });

                    // 将删除按钮添加到 polygonElementChild 中
                    polygonElementBox.append(deleteButton);
                    polygonElementBox.append(polygonElementChild);

                    polygonElementChild.on('click', function () {
                        handlePolygonClick(polygon.id);
                    });

                    polygonsList.append(polygonElementBox);
                });

                console.log("Markers:", markers);
                console.log("Polygons:", polygons);
            }

            // 处理标注点双击事件
            function handleMarkerDoubleClick(markerId) {
                console.log("Double clicked Marker ID:", markerId);
                // 进行其他操作
                map.eachLayer(function (layer) {
                    // 如果图层是标记且具有与目标ID匹配的自定义ID
                    if (layer instanceof L.Marker && layer.options.id === markerId) {
                        map.removeLayer(layer);
                        getMapLayersInfo()
                    }
                });
            }

            // 处理多边形双击事件
            function handlePolygonDoubleClick(polygonId) {
                console.log("Double clicked Polygon ID:", polygonId);
                // 进行其他操作,如放大多边形或显示相关信息
                map.eachLayer(function (layer) {
                    // 如果图层是标记且具有与目标ID匹配的自定义ID
                    if (layer instanceof L.Polygon && layer.options.id === polygonId) {
                        map.removeLayer(layer);
                        getMapLayersInfo()
                    }
                });
            }

            // 处理点击标记的事件
            function handleMarkerClick(markerId) {
                console.log("Clicked Marker ID:", markerId);
                // 进行其他操作,如高亮标记或显示相关信息
                // 通过 ID 获取对应的标记对象
                // 遍历地图上的每个图层
                map.eachLayer(function (layer) {
                    // 如果图层是标记且具有与目标ID匹配的自定义ID
                    if (layer instanceof L.Marker && layer.options.id === markerId) {
                        let currentPopupContent = layer.getPopup() ? layer.getPopup().getContent() : '';
                        // 修改标记的 bindPopup 值
                        console.log(currentPopupContent);
                        let newPopupContent = prompt(currentPopupContent);
                        if (newPopupContent !== null) {
                            layer.bindPopup(newPopupContent).openPopup();
                        }
                    }
                });
            }


            // 处理点击多边形的事件
            function handlePolygonClick(polygonId) {
                console.log("Clicked Polygon ID:", polygonId);
                // 进行其他操作,如高亮多边形或显示相关信息
                map.eachLayer(function (layer) {
                    // 如果图层是标记且具有与目标ID匹配的自定义ID
                    if (layer instanceof L.Polygon && layer.options.id === polygonId) {
                        let currentPopupContent = layer.getPopup() ? layer.getPopup().getContent() : '';
                        // 修改标记的 bindPopup 值
                        let newPopupContent = prompt(currentPopupContent);
                        if (newPopupContent !== null) {
                            layer.bindPopup(newPopupContent).openPopup();
                        }
                    }
                });
            }

            // 示例调用获取地图上所有的 marker 和 polygon 信息
            getMapLayersInfo();

            // 新增标记点功能
            let addMarkerMode = false;  // 标记是否处于新增标记模式
            let drawAreaMode = false;   // 标记是否处于绘制区域模式
            let polygon;                // 保存当前绘制的多边形
            let latlngs = [];           // 保存多边形顶点的数组

            $('#add-marker-button').on('click', function () {
                addMarkerMode = !addMarkerMode;  // 切换模式
                if (addMarkerMode) {
                    $(this).text("取消新增标记点").addClass('activeBtn');
                    // 确保绘制区域模式关闭
                    drawAreaMode = false;
                    $('#draw-area-button').text("绘制区域");
                    map.on('click', onMapClick);
                } else {
                    $(this).text("新增标记点").removeClass('activeBtn');
                    map.off('click', onMapClick);
                    getMapLayersInfo();
                }
            });

            $('#draw-area-button').on('click', function () {
                drawAreaMode = !drawAreaMode;  // 切换模式
                if (drawAreaMode) {
                    $(this).text("完成绘制区域").addClass('activeBtn');
                    // 确保新增标记模式关闭
                    addMarkerMode = false;
                    $('#add-marker-button').text("新增标记点");
                    map.on('click', onDrawAreaClick);
                } else {
                    $(this).text("绘制区域").removeClass('activeBtn');
                    map.off('click', onDrawAreaClick);
                    if (latlngs.length > 2) {
                        let popupContent = prompt("请输入区域的弹出内容:");
                        if (popupContent) {
                            map.removeLayer(polygon);
                            let newPolygonId = generateUniqueId('polygon');
                            L.polygon(latlngs, { id: newPolygonId, color: DBXcolor }).addTo(map).bindPopup(popupContent).openPopup();
                            getMapLayersInfo();
                        } else {
                            map.removeLayer(polygon); // 移除多边形
                        }
                        latlngs = []; // 重置顶点数组
                    } else {
                        alert('不足三个点');
                    }
                }
            });

            function onMapClick(e) {
                let popupContent = prompt("请输入标记点的弹出内容:");
                if (popupContent) {
                    let newMarkerId = generateUniqueId('marker');
                    L.marker(e.latlng, { icon: customIcon, id: newMarkerId }).addTo(map).bindPopup(popupContent).openPopup();
                }
            }

            function onDrawAreaClick(e) {
                latlngs.push(e.latlng);  // 添加顶点到数组
                if (polygon) {
                    map.removeLayer(polygon);  // 移除之前的临时多边形
                }
                polygon = L.polygon(latlngs, { color: DBXcolor }).addTo(map);  // 创建临时多边形
            }
        });


    </script>

</body>

</html>

文件夹如下:

效果图如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来自湖南的阿晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值