12 OpenLayers学习笔记-编辑图形

91 阅读13分钟

需求

用户绘制图形确定一定的范围或者位置后,可以进行二次修改。改变范围大小或者移动图形位置。

实现过程

实现非常简单,通过给地图增加一个new ol.interaction.Modify({source}),传入用户绘制的图层资源即可。

知识点

  • ol.interaction.Modify({})condition参数,进行编辑的触发条件,默认点击左键。
  • ol.interaction.Modify({})deleteCondition参数,删除端点的条件,默认是alt+鼠标左键点击端点,端点就被删除了。
  • ol.interaction.Modify({})insertVertexCondition参数,插入端点的条件,就是在直线中间进行编辑,能否拉出来一个新的端点。默认是可以,可设置成组合键,也可以根据业务自行设置,最后返回true或者false即可。
  • ol.interaction.Modify({})style参数,编辑过程中鼠标的样式。
  • ol.interaction.Modify({})的实例可以通过on绑定modifyend事件,此事件在每次编辑结束后触发,事件内通过evt.features可以拿到编辑后的图形。
  • feature.setStyle({})zIndex可调整图形的显示的层级。

代码HTML+CSS+JS

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/ol.min.css" integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <title>编辑图形</title>
    <style>
        * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    html,
    body,
    #app,
    .app-map {
        height: 100%;
        height: 100%;
    }
    .app-btns {
        position: fixed;
        right: 10px;
        top: 10px;
        background-color: #fff;
        box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .5);
        width: 210px;
        padding: 25px;
        text-align: center;
        border-radius: 5px;
        display: flex;
        flex-direction: column;
        z-index: 2;
    }
    .app-btns button {
        font-size: 18px;
        border: none;
        padding: 12px 20px;
        border-radius: 4px;
        color: #fff;
        background-color: #409eff;
        border-color: #409eff;
        cursor: pointer;
        border: 1px solid #dcdfe6;
        margin-bottom: 5px;
    }
    .app-btns button:hover {
        background: #66b1ff;
        border-color: #66b1ff;
    }
    .app-btns button.active {
        background-color: #07c160;
    }
    [v-cloak] {
        display: none;
    }
    </style>
</head>

<body>
    <div id="app" v-cloak>
        <div class="app-map" id="app-map"></div>
        <div class="app-btns">
            <button type='button' :class="{active: item.id === currentId}" v-for='item in drawTypes' @click='handleClickDraw(item)'>{{item.text}}</button>
            <button type='button' @click='handleClickExit' style="background-color: #808080;">退出绘制</button>
            <button type='button' @click='handleClickDelete' style="background-color: #ff0000;">删除所有图形</button>
            <button type='button' @click='verifyMode = !verifyMode' :style="{'background-color': verifyMode ? '#ff0000' : '#409eff'}" title="开启验证问题模式后,先在地图上绘制一个图形,记住图形边或者端点的位置。点击删除图形,鼠标靠近记住的边或者点的位置">验证删除图形问题</button>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/9.2.4/dist/ol.min.js" integrity="sha512-xXS2hdEzrUC2BFO0fIJ+d/bwScOLgN+W7psE4XXq6xULXjKFCskUNe8QOVVUsB7vtYRI5ZS0Ie4EgS4VzJQBkQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.14/vue.global.prod.min.js" integrity="sha512-huEQFMCpBzGkSDSPVAeQFMfvWuQJWs09DslYxQ1xHeaCGQlBiky9KKZuXX7zfb0ytmgvfpTIKKAmlCZT94TAlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script>
    const drawingStyle = 'data:image/png;base64,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';
    const attributions = '<a href="https://ditu.amap.com/" target="_blank">&copy; 地图版权归高德地图所有</a>';
    const { createApp } = Vue;
    const userType = 0;
    let zIndex = 1;
    const vm = createApp({
        data() {
            return {
                map: {}, // 地图实例
                drawSource: {}, // 绘制图形的图层资源
                draw: null, // 绘制实例
                modify: null,
                currentId: -1, // 当前绘制类型id
                features: [], // 绘制的图形数组
                drawTypes: [{
                    type: 'Point',
                    text: '打点',
                    id: 2
                }, {
                    type: 'Circle',
                    text: '画圆',
                    id: 1
                }, {
                    type: 'Polygon',
                    text: '画多边形',
                    id: 3
                }, {
                    type: 'LineString',
                    text: '画折线',
                    id: 5
                }, {
                    type: 'Circle',
                    text: '正方形',
                    geometryFunction: ol.interaction.Draw.createRegularPolygon(4),
                    id: 7
                }, {
                    type: 'Circle',
                    text: '矩形',
                    geometryFunction: ol.interaction.Draw.createBox(),
                    id: 6
                }],
                verifyMode: false
            }
        },
        methods: {
            // 初始化地图
            initMap() {
                // 创建放置用户绘制的feature的图层
                this.drawSource = new ol.source.Vector();
                const layer = new ol.layer.Vector({
                    source: this.drawSource
                });
                // 高德地图瓦片地址
                const mianLayer = new ol.layer.Tile({
                    source: new ol.source.XYZ({
                        attributions: attributions,
                        url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
                    })
                });
                //  初始化地图
                this.map = new ol.Map({
                    target: 'app-map',
                    layers: [mianLayer, layer],
                    view: new ol.View({
                        projection: 'EPSG:3857',
                        center: ol.proj.transform([111.8453154, 32.7383500], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 5
                    }),
                    controls: ol.control.defaults.defaults({
                        attribution: true, // 地图版权信息工具
                        attributionOptions: {
                            collapsed: false, // 默认折叠
                            collapsible: true // 是否可折叠,显示折叠按钮
                        }
                    })
                });
                // 绑定地图事件
                this.bindMapEvt();
                // 创建modify
                this.createModify();
            },
            // 绑定地图事件
            bindMapEvt() {
                // 监听鼠标点击
                this.map.on('click', (evt) => {
                    const coordinate = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
                    console.log('当前点击坐标为 : ' + coordinate[0].toFixed(7) + ',' + coordinate[1].toFixed(7));
                });
            },
            // 创建modify
            createModify(deltetFirst) {
                // 删除feature后,将Modify也删除
                if (deltetFirst) {
                    this.map.removeInteraction(this.modify);
                };
                console.log('重新创建了,Modify');
                // 创建Modify
                this.modify = new ol.interaction.Modify({
                    source: this.drawSource,
                    // 进行编辑的触发条件,默认点击左键。
                    condition: (event) => {
                        // 鼠标左键即可编辑
                        return ol.events.condition.primaryAction(event);
                        // 按住shift键+鼠标左键进行编辑
                        // return ol.events.condition.shiftKeyOnly(event) && ol.events.condition.primaryAction(event);
                    },
                    // 删除端点的条件,默认是alt+鼠标左键点击端点,端点就被删除了
                    deleteCondition: function(event) {
                        // 双击端点,将端点删除
                        return ol.events.condition.doubleClick(event);
                    },
                    // 插入端点的条件,就是在直线中间进行编辑,能否拉出来一个新的端点。默认是可以,可设置成组合键,也可以根据业务自行设置,最后返回true或者false即可
                    insertVertexCondition: function(event) {
                        // 鼠标左键即可插入新的端点
                        return ol.events.condition.primaryAction(event);
                        // 用户类型是0的,可插入新的端点
                        // return userType === 0;
                        // ctrl+鼠标左键可插入新的端点
                        // return ol.events.condition.platformModifierKey(event) && ol.events.condition.primaryAction(event);
                    },
                });
                // 绑定修改结束的事件
                this.modify.on('modifyend', (evt) => {
                    console.log('编辑结束了,modifyend', evt);
                    evt.features.forEach(feature => {
                        this.setFeatureStyle(feature);
                    })
                });
                // 将Modify添加到地图
                this.map.addInteraction(this.modify);
            },
            // 点击绘制各种图形
            handleClickDraw(item) {
                const { type, geometryFunction, id } = item;
                // 同一种类型点击,不处理
                if (this.currentId === id) {
                    return;
                }
                this.currentId = id;
                // 根据 type 创建交互
                this.draw = new ol.interaction.Draw({
                    source: this.drawSource,
                    type: type,
                    geometryFunction: geometryFunction,
                    style: new ol.style.Style({
                        image: new ol.style.Icon({
                            src: drawingStyle,
                            scale: 0.2,
                            // anchor: [0.5, 0.5],
                            rotateWithView: true,
                            rotation: 0,
                            opacity: 1
                        }),
                        stroke: new ol.style.Stroke({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
                        fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 })
                    })
                });
                // 将交互添加到地图
                this.map.addInteraction(this.draw);
                // 监听绘制完成的事件
                this.draw.on('drawend', (event) => {
                    // 存储绘制的feature
                    this.features.push(event.feature);
                    // 设置随机颜色样式
                    this.setFeatureStyle(event.feature);
                    // 结束此次绘制
                    this.map.removeInteraction(this.draw);
                    // 恢复按钮状态
                    this.currentId = -1;
                });
            },
            // 设置feature样式 为随机颜色
            setFeatureStyle(feature) {
                feature.setStyle(new ol.style.Style({
                    stroke: new ol.style.Stroke({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
                    fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8), width: 4 }),
                    image: new ol.style.Circle({
                        radius: 10,
                        fill: new ol.style.Fill({ color: '#' + Math.random().toString(16).slice(2, 8) }),
                        stroke: new ol.style.Stroke({
                            color: '#' + Math.random().toString(16).slice(2, 8),
                            width: 2
                        })
                    }),
                    // 保证编辑的结束后处于上层
                    zIndex: ++zIndex
                }));
            },
            // 退出绘制
            handleClickExit() {
                this.currentId = -1;
                this.draw && this.map.removeInteraction(this.draw);
                this.draw = null;
            },
            // 点击删除图形
            handleClickDelete() {
                // 删除用户创建的feature
                for (let i = 0; i < this.features.length; i++) {
                    this.drawSource.removeFeature(this.features[i]);
                };
                this.features = [];
                // 将Modify删除,再重新创建Modify
                !this.verifyMode && this.createModify(true);
            }
        },
        mounted() {
            this.initMap();
        }
    }).mount('#app')
    </script>
</body>

</html>

备注

在鼠标靠近图形的边或者端点时,图形最近的点会出现一个吸附点,此时按下鼠标即可进行编辑。存在一个问题,在删除图形后,鼠标靠近图形原位置时(此时图形已经没有了),依然会出现编辑吸附点,且可以拖动这些吸附点。似乎是编辑模块Modify 未能及时更新可编辑的feature的状态。查了写资料,没找到更新Modify的方法。目前的解决办法是,在删除图形后,移除现有的Modify交互,并重新创建一个新的Modify交互。

参考文章

图形编辑官方栗子

ol.interaction.Modify官网文档