7 OpenLayers学习笔记-图形绘制2

753 阅读23分钟

需求

用户直接拉框绘制矩形、正多边形,完成后筛选出图形区域内部的点位,设置特殊的样式。

实现过程

与之前4 OpenLayers学习笔记-绘制图形功能的实现过程相同。之前是通过ol.interaction.Draw({type})设置不同的type直接实现。此次通过ol.interaction.Draw({geometryFunction})geometryFunction实现,type全部设置为CirclegeometryFunction函数中进行图形绘制。

知识点

  • ol.interaction.Draw({geometryFunction})geometryFunction是一个可选的函数,它在绘制的过程中每次鼠标移动时都会被调用,用于根据当前坐标 coordinates 和之前绘制的几何图形 geometry 计算新的几何图形。
    • coordinates一个二维数组,包含当前鼠标位置坐标的数组。如果typeCircle,这个数组只有两个元素,点击的第一个点(圆心)坐标和鼠标当前点的坐标,如果typeLineString,这个数组存放的是折线每个段点的坐标。
    • geometrygeometryFunction中,需要return一个geometrygeometryFunction函数的第二个参数geometry是上一个geometryFunction调用返回的geometrygeometryFunction函数第一次执行的时候是undefined,之后就是上一次函数returngeometry
  • ol.interaction.Draw.createBox()函数用于创建一个框选(Box)交互实例。这个交互实例允许用户在地图上绘制矩形框,以便选择或标记特定区域。
  • ol.interaction.Draw.createRegularPolygon(3)函数用于创建一个绘制正多边形的交互实例。这个交互实例允许用户在地图上绘制规则的多边形,用户可以指定多边形边数和角度。
  • new ol.View({projection})projection参数指定视图应该使用的投影方式。在 OpenLayers 中,投影是将地理坐标(通常是经纬度)转换为像素坐标的过程,这对于在屏幕上渲染地图是必要的。OpenLayers 支持多种投影方式,但最常用的两种是:
    • EPSG:3857(也称为 Web Mercator、Google Mercator 或 Spherical Mercator):这是一种基于墨卡托投影的坐标系统,广泛用于 Web 地图服务,因为它与 Google Maps 和其他许多在线地图服务兼容。在这个投影中,地球被投影到一个正方形的平面上,然后这个平面被拉伸以适应一个矩形区域,从而创建了一个在全球范围内连续且无缝的地图。
    • EPSG:4326(也称为 WGS 84):这是全球定位系统(GPS)使用的坐标系统,也是地理坐标系统中最常用的一个。它基于经纬度坐标,其中经度范围从 -180° 到 +180°,纬度范围从 -90° 到 +90°。

代码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/8.2.0/ol.min.css" integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <title>图形绘制2</title>
    <style>
    * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

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

    #container {
        width: 100%;
        height: 100%;
        overflow: hidden;
        position: absolute;
    }

    #app {
        width: 100vw;
        height: 100vh;
    }

    .app-map {
        height: 90vh;
    }

    .app-btns {
        height: 10vh;
        border-top: 1px solid #c6e2ff;
        padding: 10px;
        display: flex;
        justify-content: space-between;
    }

    .app-btns button {
        background: #fff;
        border: 1px solid #dcdfe6;
        color: #606266;
        border-radius: 4px;
        cursor: pointer;
        font-size: 18px;
        height: 100%;
        width: 15%;
    }

    .app-btns button:hover {
        color: #409eff;
        border-color: #c6e2ff;
        background-color: #ecf5ff;
    }

    .app-btns button.active {
        color: #fff;
        background-color: #409eff;
        border-color: #409eff;
    }
    .input-range {
        font-size: 16px;
        display: flex;
        width: 30%;
    }
    .input-range button {
        width: 50%;
        margin-left: 12px;
    }
    .input-range .sides {
        display: flex;
        flex-direction: column;
        justify-content: center;
        width: 50%;
        text-align: center;
        font-size: 18px;
    }
    </style>
</head>

<body>
    <div id="app">
        <div class="app-map" id="app-map"></div>
        <div class="app-btns">
            <button :class="{active: 1 === currentId}" @click='handleClickDraw(1)'>画六角星</button>
            <button :class="{active: 2 === currentId}" @click='handleClickDraw(2)'>画矩形</button>
            <div class="input-range">
                <div class="sides">
                    <input @change='handleRangeChange' v-model='sides' type="range" id="range" min="3" max="20" />
                    <div>
                        <span>多边形边数:</span>
                        <span v-text='sides'></span>
                    </div>
                </div>
                <button :class="{active: 3 === currentId}" @click='handleClickDraw(3)'>画正{{sides}}边形</button>
            </div>
            <button :class="{active: id === ''}" @click='handleClickCancel'>退出绘制</button>
        </div>
    </div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/8.2.0/dist/ol.min.js" integrity="sha512-+nvfloZUX7awRy1yslYBsicmHKh/qFW5w79+AiGiNcbewg0nBy7AS4G3+aK/Rm+eGPOKlO3tLuVphMxFXeKeOQ==" 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 { createApp } = Vue;
    // feature图片
    const base64Img = 'data:image/png;base64,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';
    // 画六角星鼠标悬浮样式
    const starHover = 'data:image/png;base64,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';
    // 画多边形时鼠标悬浮样式
    const squareHover = 'data:image/png;base64,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';
    // 画时折线鼠标悬浮样式
    const boxHover = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAAAXNSR0IArs4c6QAABRRJREFUeF7tmLFrVEschc8smouIYJXO2sLY2KUwu9sFLRTB2hsLS7GwsbAXLEQECwW9/gVRCy2zG0GwEFSwsLNUEAtByI2489DHe4XZZCeB+7477x7bnf39znznY2IS5H+dJhA6fXtfXhag4xJYAAvQcQIdv75fAAvQcQIdv75fAAvQcQIdv75fAAvQcQIdv75fAAvQcQIdv75fAAvQcQIdv75fAAuQTmBuXB7vKS7GGBYUdEzSgqT59Ak+2QCBTwp6I4V3IcYPP3u91z9OPnibuif5BShelMua6J6kI6nDfe6/JxClryHqej2o7qZsTxKgGF24rBBupwz0mZYQCLpfL1WXZqWZKUAxKp8raHnWIH/eSgJP6n51dqdkOwpQjFeuSvFmK6/mUKkETtf96tl2h7cVYP/6yole1Csp7kvd5HOtJLAZJjq6Maw+Tku3rQDFuHws6Uwrr+RQuyMQ42o9eHQuXYD35+eKLwc/Szq8u00+3VIC3+rvh+Z16k79Z76pL8CB0cXFSZi8bOllHGsPBMJEw41hNUoSoFgrr6inW3vY46+0lECUrm32qxtpAqyXq4ra8deHfwcFbbGqpQz+n7GiBmkXC0/r/sMt/6eb+iOgWC/XlDi47lcz/5aQFtCn9kKgGJcx6XtBo3qpGqa+ABYgiSp/yALwHaAJLACKn19uAfgO0AQWAMXPL7cAfAdoAguA4ueXWwC+AzSBBUDx88stAN8BmsACoPj55RaA7wBNYAFQ/PxyC8B3gCawACh+frkF4DtAE1gAFD+/3ALwHaAJLACKn19uAfgO0AQWAMXPL7cAfAdoAguA4ueXWwC+AzSBBUDx88stAN8BmsACoPj55RaA7wBNYAFQ/PxyC8B3gCawACh+frkF4DtAE1gAFD+/3ALwHaAJLACKn19uAfgO0AQWAMXPL7cAfAdoAguA4ueXWwC+AzSBBUDx88stAN8BmsACoPj55RaA7wBNYAFQ/PxyC8B3gCawACh+frkF4DtAE1gAFD+/3ALwHaAJLACKn19uAfgO0AQWAMXPL7cAfAdoAguA4ueXWwC+AzSBBUDx88stAN8BmsACoPj55RaA7wBNYAFQ/PxyC8B3gCawACh+frkF4DtAE1gAFD+/3ALwHaAJLACKn19uAfgO0AQWAMXPL7cAfAdoAguA4ueXWwC+AzSBBUDx88ubEmBVUWeTrhc0SjrnQ80QiBqkDQ5P6/7DM3+eDdO+XKyVV9TTrbTBPpUDgShd2+xXN5IEODC6uDgJk5c5XMwZ0wiEiYYbw2rLaz31BdD783PFl4OfJR1OG+9TLSfwrf5+aF6n7tRJL8CvQ8W4fCxpy8+Mll/U8aYRiHG1Hjw6N+2j6S+ApP3rKyd6Ua+kuM9UsyawGSY6ujGsPu5KgL9fgZWrUryZ9fUd/nTdr55th2HbF+CfLxSj8rmCls0xSwJP6n6146/zMwX4/RKMLlxWCLezRNDV0EH366Xq0qzrJwnwW4IX5bImuifpyKyh/pwjEKWvIep6PajupqRIFuDXsLlxebynuBhjWFDQMUkLkuZTFvlMYwQ+KeiNFN6FGD/87PVe/zj54G3qtl0JkDrU5/IhYAHy6aqRpBagEaz5DLUA+XTVSFIL0AjWfIZagHy6aiSpBWgEaz5DLUA+XTWS1AI0gjWfoRYgn64aSWoBGsGaz1ALkE9XjSS1AI1gzWeoBcinq0aSWoBGsOYz1ALk01UjSf8Ccp6Qrs3ah6cAAAAASUVORK5CYII=';
    // 基础样式
    const basePointStyle = {
        src: base64Img,
        scale: 0.6,
        anchor: [0.5, 0.5],
        rotateWithView: true,
        rotation: 0,
        opacity: 1
    };
    // 根据基础样式,创建其他样式
    const createStyle = (imageParams, styleParams) => {
        return new ol.style.Style({
            image: new ol.style.Icon({
                ...basePointStyle,
                ...imageParams
            }),
            ...styleParams
        });
    };
    // 填充样式
    const fill = new ol.style.Fill({ color: 'rgba(0, 0, 0, 0.1)' });
    // 线条样式
    const stroke = new ol.style.Stroke({ color: '#07c160', width: 2 });
    // 基础样式style
    const baseStyle = createStyle();
    // 范围内的点位样式
    const inStyle = createStyle({ scale: 1 });
    // 在地图上绘制的点的样式
    const pointStyle = createStyle({ scale: 2 });
    // 圆,多边形范围外的点位的样式
    const outStyle = createStyle({ opacity: 0.6 });
    // 绘制点时鼠标悬浮的状态
    const hoverStyle = {
        'Star': createStyle({
            src: starHover,
            scale: 0.3
        }, {
            stroke
        }),
        'Box': createStyle({
            src: boxHover,
            scale: 0.3
        }, {
            stroke
        }),
        'Square': createStyle({
            src: squareHover,
            scale: 0.3
        }, {
            stroke
        })
    };
    const vm = createApp({
        data() {
            return {
                map: {},
                drawSource: {},
                draw: null,
                pointLayer: null,
                prevFeature: null,
                currentId: -1,
                sides: 3,
                drawTypes: [{
                    type: 'Circle',
                    hover: hoverStyle.Star,
                    id: 1,
                    geometryFunction: function (coordinates, geometry) {
                        const center = coordinates[0];
                        const last = coordinates[coordinates.length - 1];
                        const dx = center[0] - last[0];
                        const dy = center[1] - last[1];
                        const radius = Math.sqrt(dx * dx + dy * dy);
                        const rotation = Math.atan2(dy, dx);
                        const newCoordinates = [];
                        const numPoints = 12;
                        for (let i = 0; i < numPoints; ++i) {
                          const angle = rotation + (i * 2 * Math.PI) / numPoints;
                          const fraction = i % 2 === 0 ? 1 : 0.5;
                          const offsetX = radius * fraction * Math.cos(angle);
                          const offsetY = radius * fraction * Math.sin(angle);
                          newCoordinates.push([center[0] + offsetX, center[1] + offsetY]);
                        }
                        newCoordinates.push(newCoordinates[0].slice());
                        if (!geometry) {
                          geometry = new ol.geom.Polygon([newCoordinates]);
                          // geometry = new ol.geom.LineString(coordinates);
                        } else {
                          geometry.setCoordinates([newCoordinates]);
                          // geometry.setCoordinates(coordinates);
                        }
                        return geometry;
                    }
                }, {
                    type: 'Circle',
                    hover: hoverStyle.Box,
                    id: 2,
                    geometryFunction: ol.interaction.Draw.createBox()
                }, {
                    type: 'Circle',
                    id: 3,
                    hover: hoverStyle.Square,
                    geometryFunction: ol.interaction.Draw.createRegularPolygon(3)
                }]
            }
        },
        methods: {
            // 初始化地图
            initMap() {
                // 创建放置用户绘制的feature的图层
                this.drawSource = new ol.source.Vector();
                this.drawVector = new ol.layer.Vector({
                    source: this.drawSource,
                });
                // 高德地图瓦片地址
                const vectorLayer = new ol.layer.Tile({
                    source: new ol.source.XYZ({
                        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: [vectorLayer, this.drawVector],
                    view: new ol.View({
                        projection: 'EPSG:3857',
                        //设定中心点,因为默认坐标系为 3587,所以要将我们常用的经纬度坐标系4326 转换为 3587坐标系
                        center: ol.proj.transform([111.8453154, 32.7383500], 'EPSG:4326', 'EPSG:3857'),
                        zoom: 5,
                    })
                });
                // 绑定地图事件
                this.bindMapEvt();
                // 渲染1000个点位到地图上
                this.renderPoint(1000);
            },
            // 绑定地图事件
            bindMapEvt() {
                // 监听鼠标点击
                this.map.on('click', (evt) => {
                    const clickPoint = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
                    console.log('当前点击坐标为 : ' + clickPoint[0].toFixed(7) + ',' + clickPoint[1].toFixed(7));
                });
            },
            // 点击绘制各种图形
            handleClickDraw(id) {
                const { map } = this;
                const item = this.drawTypes.find(e => e.id === id);
                const { type, geometryFunction } = item;
                this.currentId = id;
                // 删除上一种绘制
                this.draw && map.removeInteraction(this.draw);
                // 恢复所有点位的透明度为1
                this.setFeatureOpacity();
                // 根据 type 创建交互
                this.draw = new ol.interaction.Draw({
                    source: this.drawSource,
                    type: type,
                    style: item.hover,
                    geometryFunction: geometryFunction
                });
                // 将交互添加到地图
                map.addInteraction(this.draw);
                // 监听绘制完成的事件
                this.draw.on('drawend', (event) => {
                    // 获取绘制的feature
                    const feature = event.feature;
                    // 删除上一个feature
                    this.prevFeature && this.drawSource.removeFeature(this.prevFeature);
                    this.prevFeature = feature;
                    // 将图形内、外的点位设置不同的样式
                    this.handleDrawEnd(feature);
                });
            },
            // 多边形边数发生变化,重新设置画多边形的 geometryFunction
            handleRangeChange () {
                const square = this.drawTypes.find(e => e.id === 3);
                // 根据边数重新设置 geometryFunction
                square.geometryFunction = ol.interaction.Draw.createRegularPolygon(parseInt(this.sides));
                // 根据id触发点击事件
                this.handleClickDraw(3);
            },
            // 处理绘制圆和多边形的处理
            handleDrawEnd(feature) {
                // 设置绘制完成后圆和多边形的样式
                feature.setStyle(new ol.style.Style({
                    fill: new ol.style.Fill({ color: 'rgba(255, 0, 0, 0)' }),
                    stroke: new ol.style.Stroke({ color: '#07c160', width: 2 })
                }));
                // 获取feature的Geometry
                const geometry = feature.getGeometry();
                // 遍历1000个点位
                this.pointLayer.getSource().forEachFeature(function(point) {
                    const pointGeometry = point.getGeometry();
                    // 判断监控点位是否在范围内
                    if (geometry.intersectsExtent(pointGeometry.getExtent())) {
                        point.setStyle(inStyle); // 在范围内
                    } else {
                        point.setStyle(outStyle); // 不在范围内
                    }
                });
            },
            // 点击取消,删除上一个交互
            handleClickCancel() {
                this.currentId = 'none';
                this.draw && this.map.removeInteraction(this.draw);
                this.draw = null;
            },
            // 恢复点位状态
            setFeatureOpacity() {
                // 遍历1000个点位,恢复样式
                this.pointLayer.getSource().forEachFeature(function(monitorFeature) {
                    monitorFeature.setStyle(baseStyle);
                });
            },
            // 在地图上添加点位
            renderPoint(numPoints) {
                const positions = this.createCircularPosition(numPoints); // 生成坐标数据
                // 根据positions创建一个新的数据源和要素数组,
                const vectorSource = new ol.source.Vector({
                    features: positions.map(e => {
                        // ol.proj.fromLonLat用于将经纬度坐标从 WGS84 坐标系转换为地图投影坐标系
                        const feature = new ol.Feature({
                            geometry: new ol.geom.Point(ol.proj.fromLonLat(e)),
                            custom: {
                                id: Math.ceil(Math.random() * 100000)
                            }
                        });
                        feature.setStyle(baseStyle);
                        return feature;
                    })
                });
                // 创建带有数据源的矢量图层
                this.pointLayer = new ol.layer.Vector({
                    source: vectorSource,
                    layerID: 'addpointLayer'
                });
                // 将矢量图层添加到地图上
                this.map.addLayer(this.pointLayer);
            },
            // 创建数据
            createCircularPosition(numPoints) {
                const center = [108.55, 34.32];
                const circularManyPosition = [];
                const minLat = 3.86;
                const maxLat = 53.56;
                const minLon = 73.66;
                const maxLon = 135.05;
                for (var i = 0; i < numPoints; i++) {
                    var lat = Math.random() * (maxLat - minLat) + minLat;
                    var lon = Math.random() * (maxLon - minLon) + minLon;
                    circularManyPosition.push([lon, lat]);
                }
                return circularManyPosition;
            }
        },
        mounted() {
            this.initMap();
        }
    }).mount('#app')
    </script>
</body>

</html>

参考文章

geometryFunction官方文档

ol.interaction.Draw.createBox()官方文档

ol.interaction.Draw.createRegularPolygon(3)官方文档

Draw Shapes图形绘制官方栗子