OpenLayers 撤销绘制

关注我,带你一起学GIS ^

注:当前使用的是 ol [9.2.4] 版本,天地图使用的key请到天地图官网申请,并替换为自己的key

前言

图形绘制是指在地图上绘制点、线、面、圆、矩形等图形,可以通过鼠标单机绘制,也可以键盘按键配合进行绘制。对于绘制的几何图形可以进行样式调整,也可以对绘制状态进行修改,本篇文章主要介绍如何进行撤销操作。

1. 构建HTML结构

在页面中添加撤销按钮并将调整清除按钮位置,然后添加相应CSS

.draw-action {
    position: absolute;
    padding: 5px;
    top: 60px;
    left: 400px;
    background-color: #ffcc00ad;
    border-radius: 2.5px;
}

.draw-action-btn {
    padding: 5px;
    margin: 0 5px;
    min-width: 50px;
    background-color: azure;
    background: #cae4cf82;
    transition: background-color 10s ease-in-out 10s;
    text-align: center;
    border-radius: 2.5px;
    transition: color ease-in-out 0.25s;
    border: none;
}

.draw-action-btn:hover {
    cursor: pointer;
    color: #fff;
    filter: brightness(120%);
    background: linear-gradient(135deg, #c850c0, #4158d0);
}

<div class="draw-action">
    <button class="draw-action-btn draw-action-undo">撤销</button>
    <button class="draw-action-btn" id="clearDraw">清除</button>
</div>

2. 撤销绘制

Draw控件中有一个方法removeLastPoint,使用此方法会移除绘制图形最后一个点。

// 撤销操作
document.querySelector(".draw-action-undo").addEventListener('click', evt => {
    if (drawInteraction) {
        drawInteraction.removeLastPoint()
    }
})

3. 清除绘制

创建清除结果方法,在点击清除按钮时移除绘制图形和交互控件,然后移除激活样式。

// 清除绘制
function clearResult() {
    removeInteraction()
    // 清除图形
    vectorSource.clear()
    removeAllActiveClass(".draw-ul""active")
    return
}
document.getElementById("clearDraw").addEventListener("click", evt => {
    clearResult()
})

4. 完整代码

其中libs文件夹下的包需要更换为自己下载的本地包或者引用在线资源。

<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>OpenLayers 撤销绘制</title>
    <meta charset="utf-8" />

    <link rel="stylesheet" href="../../libs/css/ol9.2.4.css">
    <link rel="stylesheet" href="../../libs/layui/css/layui.css">

    <script src="../../js/config.js"></script>
    <script src="../../js/util.js"></script>
    <script src="../../libs/js/ol9.2.4.js"></script>
    <script src="../../libs/layui/layui.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
            font-size: 14px;
            font-family: '微软雅黑';
        }

        html,
        body {
            width: 100%;
            height: 100%;
        }

        #map {
            position: absolute;
            top: 50px;
            bottom: 0;
            width: 100%;
        }

        #top-content {
            position: absolute;
            width: 100%;
            height: 50px;
            line-height: 50px;
            background: linear-gradient(135deg, #ff00cc, #ffcc00, #00ffcc, #ff0066);
            color: #fff;
            text-align: center;
            font-size: 32px;
        }

        #top-content span {
            font-size: 32px;
        }

        .draw-shape {
            position: absolute;
            padding: 5px;
            top: 60px;
            left: 100px;
            background-color: #ffcc00ad;
            border-radius: 2.5px;
        }

        .draw-ul {
            list-style-type: none;
        }

        .draw-ul::after {
            display: block;
            clear: both;
            content: "";
        }

        .draw-li {
            float: left;
            padding: 5px;
            margin: 0 5px;
            min-width: 50px;
            background-color: azure;
            background: #cae4cf82;
            transition: background-color 10s ease-in-out 10s;
            text-align: center;
            border-radius: 2.5px;
            transition: color ease-in-out 0.25s;
        }

        .draw-li:hover {
            cursor: pointer;
            color: #fff;
            filter: brightness(120%);
            background: linear-gradient(135deg, #c850c0, #4158d0);
        }

        .active {
            color: #fff;
            background: linear-gradient(135deg, #c850c0, #4158d0);
        }

        .stroke-style {
            position: absolute;
            padding: 10px;
            top: 120px;
            left: 100px;
            background-color: #c19b03ab;
            border-radius: 2.5px;
        }

        .stroke-line-style {
            display: flex;
        }

        .line-style {
            margin-top: 15px;
            width: 80%;
        }

        .draw-action {
            position: absolute;
            padding: 5px;
            top: 60px;
            left: 400px;
            background-color: #ffcc00ad;
            border-radius: 2.5px;
        }

        .draw-action-btn {
            padding: 5px;
            margin: 0 5px;
            min-width: 50px;
            background-color: azure;
            background: #cae4cf82;
            transition: background-color 10s ease-in-out 10s;
            text-align: center;
            border-radius: 2.5px;
            transition: color ease-in-out 0.25s;
            border: none;
        }

        .draw-action-btn:hover {
            cursor: pointer;
            color: #fff;
            filter: brightness(120%);
            background: linear-gradient(135deg, #c850c0, #4158d0);
        }
    </style>
</head>

<body>
    <div id="top-content">
        <span>OpenLayers 撤销绘制</span>
    </div>
    <div id="map" title="地图显示"></div>
    <div class="draw-shape">
        <ul class="draw-ul">
            <li class="draw-li" data-type="LineString">线</li>
            <li class="draw-li" data-type="Polygon">多边形</li>
            <li class="draw-li" data-type="Square">正方形</li>
            <li class="draw-li" data-type="Box">矩形</li>
        </ul>
    </div>
    <div class="draw-action">
        <button class="draw-action-btn draw-action-undo">撤销</button>
        <button class="draw-action-btn" id="clearDraw">清除</button>
    </div>
    <div class="stroke-style">
        <div class="layui-form">
            <div class="layui-form-item">
                <label class="layui-form-label">端点样式</label>
                <div class="layui-input-block">
                    <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="butt" title="butt">
                    <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="round" title="round"
                        checked>
                    <input type="radio" name="lineCap" lay-filter="cap-radio-filter" value="square" title="square">
                </div>
            </div>
            <div class="layui-form-item">
                <label class="layui-form-label">拐点样式</label>
                <div class="layui-input-block">
                    <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="bevel" title="bevel">
                    <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="round" title="round"
                        checked>
                    <input type="radio" name="lineJoin" lay-filter="join-radio-filter" value="miter" title="miter">
                </div>
            </div>
            <div class="layui-form-item stroke-line-style">
                <label class="layui-form-label">线宽(pixel)</label>
                <div id="stroke-width-value" class="line-style"></div>
            </div>
            <div class="layui-form-item stroke-line-style">
                <label class="layui-form-label">虚线样式</label>
                <div id="line-dash-value" class="line-style"></div>
            </div>
            <div class="layui-form-item stroke-line-style">
                <label class="layui-form-label">虚线偏移</label>
                <div id="line-dash-offset" class="line-style"></div>
            </div>
        </div>
    </div>
</body>

</html>

<script>
    //地图投影坐标系
    const projection = ol.proj.get('EPSG:3857');
    //==============================================================================//
    //============================天地图服务参数简单介绍==============================//
    //================================vec:矢量图层==================================//
    //================================img:影像图层==================================//
    //================================cva:注记图层==================================//
    //======================其中:_c表示经纬度投影,_w表示球面墨卡托投影================//
    //==============================================================================//
    const TDTImgLayer = new ol.layer.Tile({
        title: "天地图影像图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=" + TDTTOKEN,
            attibutions: "天地图影像描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })
    const TDTImgCvaLayer = new ol.layer.Tile({
        title: "天地图影像注记图层",
        source: new ol.source.XYZ({
            url: "http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=" + TDTTOKEN,
            attibutions: "天地图注记描述",
            crossOrigin: "anoymous",
            wrapX: false
        })
    })
    const map = new ol.Map({
        target: "map",
        loadTilesWhileInteracting: true,
        view: new ol.View({
            center: [102.845864, 25.421639],
            zoom: 5,
            worldsWrap: false,
            minZoom: 1,
            maxZoom: 20,
            projection: 'EPSG:4326',
        }),
        layers: [TDTImgLayer]
    })

    const style = new ol.style.Style({
        fill: new ol.style.Fill({
            color: "#9b65ff30"
        }),
        stroke: new ol.style.Stroke({
            color: "yellow",
            width: 5,
            lineCap: 'round',
            lineJoin: 'round',
            // lineDash: [20, 30, 40, 50],
            lineDashOffset: 0
        }),
        image: new ol.style.Circle({
            fill: new ol.style.Fill({
                color: "#fff"
            }),
            radius: 5,
            stroke: new ol.style.Stroke({
                color: "blue",
                width: 1,
            })
        })
    })
    const vectorSource = new ol.source.Vector({ wrapX: false })
    let vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style
    })
    map.addLayer(vectorLayer)
    let drawInteraction = null
    /**
     * 根据几何类型绘制几何对象
     */
    function drawShape(type) {
        clearResult()
        let geometryFunction = null
        switch (type) {
            case "Square":
                type = "Circle"
                geometryFunction = ol.interaction.Draw.createRegularPolygon(4)
                break
            case "Box":
                type = "Circle"
                geometryFunction = ol.interaction.Draw.createBox()
                break
        }
        drawInteraction = new ol.interaction.Draw({
            source: vectorSource,
            type,
            geometryFunction,
            style,
            // freehand: true // 是否开启自由绘制模式
        })
        map.addInteraction(drawInteraction)
    }

    // 事件委托
    const targetEle = document.querySelector(".draw-ul")
    targetEle.addEventListener('click', evt => {
        removeInteraction()
        const targetEle = evt.target
        const geomType = targetEle.dataset.type
        if (geomType !== "None") {
            toogleAciveClass(targetEle, ".draw-ul")
        }
        if (geomType) {
            drawShape(geomType)
        }
    })

    let lineWidth = 2.5
    let lineDash = [30, 40, 50, 60]
    layui.use(function () {
        const slider = layui.slider;
        // 线条宽度
        slider.render({
            elem: '#stroke-width-value',
            value: 5, //初始值
            change: function (value) {
                lineWidth = value
                const styleObj = {
                    width: lineWidth
                }
                setStyle(styleObj)
            }
        });
        // 虚线间隔
        slider.render({
            elem: '#line-dash-value',
            value: 0, //初始值
            change: function (value) {
                lineDash = [value, 40, 50, 60]
                const styleObj = {
                    lineDash: lineDash
                }
                setStyle(styleObj)
            }
        });
        // 偏移值
        slider.render({
            elem: '#line-dash-offset',
            value: 0, //初始值
            change: function (value) {
                const styleObj = {
                    lineDashOffset: value
                }
                setStyle(styleObj)
            }
        });
    });

    layui.use(function () {
        const form = layui.form;
        const layer = layui.layer;
        // radio 事件
        form.on('radio(cap-radio-filter)'function (data) {
            const elem = data.elem; // 获得 radio 原始 DOM 对象
            const checked = elem.checked; // 获得 radio 选中状态
            const value = elem.value; // 获得 radio 值
            const styleObj = {
                lineCap: value
            }
            setStyle(styleObj)
        })

        form.on('radio(join-radio-filter)'function (data) {
            const elem = data.elem; // 获得 radio 原始 DOM 对象
            const checked = elem.checked; // 获得 radio 选中状态
            const value = elem.value; // 获得 radio 值
            const styleObj = {
                lineJoin: value
            }
            setStyle(styleObj)
        })
    });

    function setStyle(styleObj) {
        const { width, lineCap, lineJoin, lineDash, lineDashOffset } = styleObj
        map.removeLayer(vectorLayer)
        const style = new ol.style.Style({
            fill: new ol.style.Fill({
                color: "#9b65ff30"
            }),
            stroke: new ol.style.Stroke({
                color: "yellow",
                width: width || lineWidth,
                lineCap: lineCap || 'round',
                lineJoin: lineJoin || 'round',
                lineDash: lineDash || lineDash,
                lineDashOffset: lineDashOffset || 0
            })
        })
        vectorLayer = new ol.layer.Vector({
            source: vectorSource,
            style: style
        })
        map.addLayer(vectorLayer)
    }
    // 移除绘制控件
    function removeInteraction() {
        if (drawInteraction) {
            map.removeInteraction(drawInteraction)
        }
    }

    // 清除绘制
    function clearResult() {
        removeInteraction()
        // 清除图形
        vectorSource.clear()
        removeAllActiveClass(".draw-ul""active")
        return
    }
    document.getElementById("clearDraw").addEventListener("click", evt => {
        clearResult()
    })

    // 撤销操作
    document.querySelector(".draw-action-undo").addEventListener('click', evt => {
        if (drawInteraction) {
            drawInteraction.removeLastPoint()
        }
    })
</script>

OpenLayers示例数据下载,请在公众号后台回复:ol数据

全国信息化工程师-GIS 应用水平考试资料,请在公众号后台回复:GIS考试

GIS之路公众号已经接入了智能助手,欢迎大家前来提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏+关注 

本号不定时更新有关 GIS开发  相关内容,欢迎关注 

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部