1、前言

本文来介绍一下OpenLayers点选框选圈选多边形选择的实现方法,需要注意的是:

  • 点选、框选对点、线、面三种要素均有效
  • 圈选和多边形选择只对点要素有效

2、点选的实现

点选比较简单,创建一个ol.interaction.Select对象,然后监听select事件即可,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>点选</title>
    <link href="lib/ol/ol.css" rel="stylesheet" />
    <script src="lib/ol/ol.js"></script>
</head>
<body>
    <div id="map" style="width:800px;height:800px;"></div>
    <h1 id="msg"></h1>
    <script>
        // 创建要素图层
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.0, 29.0],
                            [119.2, 29.0],
                            [119.2, 29.2],
                            [119.0, 29.2],
                            [119.0, 29.0]
                        ]]),
                        name: 'A'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.4, 29.0],
                            [119.6, 29.0],
                            [119.5, 29.2],
                            [119.4, 29.0]
                        ]]),
                        name: 'B'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.LineString([
                            [119.0, 29.4],
                            [119.2, 29.3],
                            [119.4, 29.5],
                            [119.6, 29.3],
                            [119.8, 29.6]
                        ]),
                        name: 'C'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([119.4, 29.6]),
                        name: 'D'
                    }),
                ]
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    stroke: new ol.style.Stroke({
                        width: 4,
                        color: 'blue'
                    }),
                    fill: new ol.style.Fill({
                        color: 'yellow'
                    })
                }),
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'blue'
                }),
                fill: new ol.style.Fill({
                    color: 'yellow'
                })
            })
        });

        // 创建地图
        var map = new ol.Map({
            target: 'map',
            layers: [
                vectorLayer,
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [119.2, 29.2],
                zoom: 10
            })
        });

        // 创建点选工具
        var interaction = new ol.interaction.Select({
            condition: ol.events.condition.singleClick,
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    stroke: new ol.style.Stroke({
                        width: 4,
                        color: 'red'
                    }),
                    fill: new ol.style.Fill({
                        color: 'green'
                    })
                }),
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'red'
                }),
                fill: new ol.style.Fill({
                    color: 'green'
                })
            }),
            layers: [
                vectorLayer
            ]
        });

        // 监听select事件
        interaction.on('select', function (e) {
            if (e.selected.length > 0) {
                var feature = e.selected[0];
                var name = feature.get('name');
                document.getElementById('msg').innerText = '被选中的要素:' + name;
            }
        });

        // 添加单选工具
        map.addInteraction(interaction);
    </script>
</body>
</html>

运行结果如下图所示:

在这里插入图片描述

点选的另一种实现方式就是监听地图事件,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>点选</title>
    <link href="lib/ol/ol.css" rel="stylesheet" />
    <script src="lib/ol/ol.js"></script>
</head>
<body>
    <div id="map" style="width:800px;height:800px;"></div>
    <h1 id="msg"></h1>
    <script>
        // 选中样式
        var selectedStyle = new ol.style.Style({
            image: new ol.style.Circle({
                radius: 30,
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'red'
                }),
                fill: new ol.style.Fill({
                    color: 'green'
                })
            }),
            stroke: new ol.style.Stroke({
                width: 4,
                color: 'red'
            }),
            fill: new ol.style.Fill({
                color: 'green'
            })
        });

        // 未选中样式
        var unselectedStyle = new ol.style.Style({
            image: new ol.style.Circle({
                radius: 30,
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'blue'
                }),
                fill: new ol.style.Fill({
                    color: 'yellow'
                })
            }),
            stroke: new ol.style.Stroke({
                width: 4,
                color: 'blue'
            }),
            fill: new ol.style.Fill({
                color: 'yellow'
            })
        });

        // 创建要素图层
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.0, 29.0],
                            [119.2, 29.0],
                            [119.2, 29.2],
                            [119.0, 29.2],
                            [119.0, 29.0]
                        ]]),
                        name: 'A'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.4, 29.0],
                            [119.6, 29.0],
                            [119.5, 29.2],
                            [119.4, 29.0]
                        ]]),
                        name: 'B'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.LineString([
                            [119.0, 29.4],
                            [119.2, 29.3],
                            [119.4, 29.5],
                            [119.6, 29.3],
                            [119.8, 29.6]
                        ]),
                        name: 'C'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([119.4, 29.6]),
                        name: 'D'
                    }),
                ]
            }),
            style: unselectedStyle
        });

        // 创建地图
        var map = new ol.Map({
            target: 'map',
            layers: [
                vectorLayer,
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [119.2, 29.2],
                zoom: 10
            })
        });

        // 注册地图事件
        map.on('singleclick', function (e) {
            var pixel = map.getEventPixel(e.originalEvent);
            var currentFeature = map.forEachFeatureAtPixel(pixel, function (feature, layer) {
                return feature;
            });
            if (currentFeature) {
                var features = vectorLayer.getSource().getFeatures();
                features.forEach(function (item) {
                    item.setStyle(unselectedStyle);
                });
                currentFeature.setStyle(selectedStyle);
                var name = currentFeature.get('name');
                document.getElementById('msg').innerText = '被选中的要素:' + name;
            } else {
                var features = vectorLayer.getSource().getFeatures();
                features.forEach(function (item) {
                    item.setStyle(unselectedStyle);
                });
            }
        });
    </script>
</body>
</html>

运行结果如下图所示:

在这里插入图片描述

3、框选的实现

框选功能的实现思路很简单,ol.interaction.Draw负责绘制矩形,ol.interaction.Select用于盛放被选择的要素,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>框选</title>
    <link href="lib/ol/ol.css" rel="stylesheet" />
    <script src="lib/ol/ol.js"></script>
</head>
<body>
    <div id="map" style="width:800px;height:800px;"></div>
    <h1 id="msg"></h1>
    <script>
        // 创建要素图层
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.0, 29.0],
                            [119.2, 29.0],
                            [119.2, 29.2],
                            [119.0, 29.2],
                            [119.0, 29.0]
                        ]]),
                        name: 'A'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.4, 29.0],
                            [119.6, 29.0],
                            [119.5, 29.2],
                            [119.4, 29.0]
                        ]]),
                        name: 'B'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.LineString([
                            [119.0, 29.4],
                            [119.2, 29.3],
                            [119.4, 29.5],
                            [119.6, 29.3],
                            [119.8, 29.6]
                        ]),
                        name: 'C'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([119.4, 29.6]),
                        name: 'D'
                    }),
                ]
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    stroke: new ol.style.Stroke({
                        width: 4,
                        color: 'blue'
                    }),
                    fill: new ol.style.Fill({
                        color: 'yellow'
                    })
                }),
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'blue'
                }),
                fill: new ol.style.Fill({
                    color: 'yellow'
                })
            })
        });

        // 创建绘制图层
        var drawLayer = new ol.layer.Vector({
            source: new ol.source.Vector(),
            style: new ol.style.Style()
        });

        // 创建地图
        var map = new ol.Map({
            target: 'map',
            layers: [
                vectorLayer,
                drawLayer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [119.2, 29.2],
                zoom: 10
            })
        });

        // 创建选择工具,用于盛放矩形框内的要素
        var select = new ol.interaction.Select({
            condition: ol.events.condition.never,
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    stroke: new ol.style.Stroke({
                        width: 4,
                        color: 'red'
                    }),
                    fill: new ol.style.Fill({
                        color: 'green'
                    })
                }),
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'red'
                }),
                fill: new ol.style.Fill({
                    color: 'green'
                })
            })
        });

        // 创建绘制矩形工具
        var drawBox = new ol.interaction.Draw({
            source: drawLayer.getSource(),
            type: 'Circle',
            geometryFunction: ol.interaction.Draw.createBox()
        });

        // 开始绘制,清除已有要素
        drawBox.on('drawstart', function () {
            select.getFeatures().clear();
            drawLayer.getSource().clear();
        });

        // 结束绘制
        drawBox.on('drawend', function (e) {
            if (e.feature) {
                // 获取框选范围
                var geometry = e.feature.getGeometry();
                var extent = geometry.getExtent();

                // 查询框选范围内的所有点
                vectorLayer.getSource().forEachFeatureIntersectingExtent(extent, function (feature) {
                    select.getFeatures().push(feature);
                });

                // 遍历被选中的要素
                var selected = [];
                var selectedFeatures = select.getFeatures();
                for (var i = 0; i < selectedFeatures.getLength(); i++) {
                    var feature = selectedFeatures.item(i);
                    var name = feature.get('name');
                    selected.push(name);
                }

                // 输出查询结果
                var msg = selected.join('、');
                document.getElementById('msg').innerText = '被选中的要素:' + msg;
            }
        });

        // 添加交互工具
        map.addInteraction(drawBox);
        map.addInteraction(select);
    </script>
</body>
</html>

运行结果如下图所示:

在这里插入图片描述

矩形框的绘制也可以使用ol.interaction.DragBox来实现,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>框选</title>
    <link href="lib/ol/ol.css" rel="stylesheet" />
    <script src="lib/ol/ol.js"></script>
</head>
<body>
    <div id="map" style="width:800px;height:800px;"></div>
    <h1 id="msg"></h1>
    <script>
        // 创建要素图层
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.0, 29.0],
                            [119.2, 29.0],
                            [119.2, 29.2],
                            [119.0, 29.2],
                            [119.0, 29.0]
                        ]]),
                        name: 'A'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Polygon([[
                            [119.4, 29.0],
                            [119.6, 29.0],
                            [119.5, 29.2],
                            [119.4, 29.0]
                        ]]),
                        name: 'B'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.LineString([
                            [119.0, 29.4],
                            [119.2, 29.3],
                            [119.4, 29.5],
                            [119.6, 29.3],
                            [119.8, 29.6]
                        ]),
                        name: 'C'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([119.4, 29.6]),
                        name: 'D'
                    }),
                ]
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    stroke: new ol.style.Stroke({
                        width: 4,
                        color: 'blue'
                    }),
                    fill: new ol.style.Fill({
                        color: 'yellow'
                    })
                }),
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'blue'
                }),
                fill: new ol.style.Fill({
                    color: 'yellow'
                })
            })
        });

        // 创建地图
        var map = new ol.Map({
            target: 'map',
            layers: [
                vectorLayer,
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [119.2, 29.2],
                zoom: 10
            })
        });

        // 创建选择工具,用于盛放矩形框内的要素
        var select = new ol.interaction.Select({
            condition: ol.events.condition.never,
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    stroke: new ol.style.Stroke({
                        width: 4,
                        color: 'red'
                    }),
                    fill: new ol.style.Fill({
                        color: 'green'
                    })
                }),
                stroke: new ol.style.Stroke({
                    width: 4,
                    color: 'red'
                }),
                fill: new ol.style.Fill({
                    color: 'green'
                })
            })
        });

        // 创建绘制工具
        var dragBox = new ol.interaction.DragBox({
            condition: ol.events.condition.always
        });

        // 开始绘制,清除已有要素
        dragBox.on('boxstart', function () {
            select.getFeatures().clear();
        });

        // 结束绘制
        dragBox.on('boxend', function () {
            // 获取被选择的要素
            var extent = dragBox.getGeometry().getExtent();
            vectorLayer.getSource().forEachFeatureIntersectingExtent(extent, function (feature) {
                select.getFeatures().push(feature);
            });

            // 遍历被选中的要素
            var selected = [];
            var selectedFeatures = select.getFeatures();
            for (var i = 0; i < selectedFeatures.getLength(); i++) {
                var feature = selectedFeatures.item(i);
                var name = feature.get('name');
                selected.push(name);
            }

            // 输出查询结果
            var msg = selected.join('、');
            document.getElementById('msg').innerText = '被选中的要素:' + msg;
        });

        // 添加交互工具
        map.addInteraction(dragBox);
        map.addInteraction(select);
    </script>
</body>
</html>

运行结果如下图所示:

在这里插入图片描述

4、圈选的实现

圈选功能的实现需要绕一个弯子,ol.interaction.Draw负责绘制圆形,ol.interaction.Select用于盛放被选择的要素,在绘制圆形后需要获取这个圆的外接矩形,利用外接矩形做第一次筛选,然后再利用内置的intersectsCoordinate(coordinates)方法判断点是否在圆内部,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>圈选</title>
    <link href="lib/ol/ol.css" rel="stylesheet" />
    <script src="lib/ol/ol.js"></script>
</head>
<body>
    <div id="map" style="width:800px;height:800px;"></div>
    <h1 id="msg"></h1>
    <script>
        // 创建要素图层
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Point([120.0, 30.0]),
                        name: 'A'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([120.1, 30.1]),
                        name: 'B'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([120.2, 30.2]),
                        name: 'C'
                    })
                ]
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    fill: new ol.style.Fill({
                        color: 'blue'
                    })
                })
            })
        });

        // 创建绘制图层
        var drawLayer = new ol.layer.Vector({
            source: new ol.source.Vector(),
            style: new ol.style.Style()
        });

        // 创建地图
        var map = new ol.Map({
            target: 'map',
            layers: [
                vectorLayer,
                drawLayer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [120, 30],
                zoom: 10
            })
        });

        // 创建选择工具,用于盛放圆形内的要素
        var select = new ol.interaction.Select({
            condition: ol.events.condition.never,
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    fill: new ol.style.Fill({
                        color: 'red'
                    })
                })
            })
        });

        // 创建绘制圆形工具
        var drawBox = new ol.interaction.Draw({
            source: drawLayer.getSource(),
            type: 'Circle'
        });

        // 开始绘制,清除已有要素
        drawBox.on('drawstart', function () {
            select.getFeatures().clear();
            drawLayer.getSource().clear();
        });

        // 结束绘制
        drawBox.on('drawend', function (e) {
            if (e.feature) {
                // 获取圆的外接矩形范围
                var circle = e.feature.getGeometry();
                var extent = circle.getExtent();

                // 查询外接矩形范围内的所有点
                vectorLayer.getSource().forEachFeatureIntersectingExtent(extent, function (feature) {
                    var coordinates = feature.getGeometry().getCoordinates();

                    // 判断该点是否在圆内部
                    if (circle.intersectsCoordinate(coordinates)) {
                        select.getFeatures().push(feature);
                    }
                });

                // 遍历被选中的要素
                var selected = [];
                var selectedFeatures = select.getFeatures();
                for (var i = 0; i < selectedFeatures.getLength(); i++) {
                    var feature = selectedFeatures.item(i);
                    var name = feature.get('name');
                    selected.push(name);
                }

                // 输出查询结果
                var msg = selected.join('、');
                document.getElementById('msg').innerText = '被选中的要素:' + msg;
            }
        });

        // 添加交互工具
        map.addInteraction(drawBox);
        map.addInteraction(select);
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

5、多边形选择的实现

多边形选择的实现方式和圈选类似,代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>多边形选择</title>
    <link href="lib/ol/ol.css" rel="stylesheet" />
    <script src="lib/ol/ol.js"></script>
</head>
<body>
    <div id="map" style="width:800px;height:800px;"></div>
    <h1 id="msg"></h1>
    <script>
        // 创建要素图层
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: [
                    new ol.Feature({
                        geometry: new ol.geom.Point([120.0, 30.0]),
                        name: 'A'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([120.1, 30.1]),
                        name: 'B'
                    }),
                    new ol.Feature({
                        geometry: new ol.geom.Point([120.2, 30.2]),
                        name: 'C'
                    })
                ]
            }),
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    fill: new ol.style.Fill({
                        color: 'blue'
                    })
                })
            })
        });

        // 创建绘制图层
        var drawLayer = new ol.layer.Vector({
            source: new ol.source.Vector(),
            style: new ol.style.Style()
        });

        // 创建地图
        var map = new ol.Map({
            target: 'map',
            layers: [
                vectorLayer,
                drawLayer
            ],
            view: new ol.View({
                projection: 'EPSG:4326',
                center: [120, 30],
                zoom: 10
            })
        });

        // 创建选择工具,用于盛放多边形内的要素
        var select = new ol.interaction.Select({
            condition: ol.events.condition.never,
            style: new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 30,
                    fill: new ol.style.Fill({
                        color: 'red'
                    })
                })
            })
        });

        // 创建绘制多边形工具
        var drawBox = new ol.interaction.Draw({
            source: drawLayer.getSource(),
            type: 'Polygon'
        });

        // 开始绘制,清除已有要素
        drawBox.on('drawstart', function () {
            select.getFeatures().clear();
            drawLayer.getSource().clear();
        });

        // 结束绘制
        drawBox.on('drawend', function (e) {
            if (e.feature) {
                // 获取多边形的外接矩形范围
                var polygon = e.feature.getGeometry();
                var extent = polygon.getExtent();

                // 查询外接矩形范围内的所有点
                vectorLayer.getSource().forEachFeatureIntersectingExtent(extent, function (feature) {
                    var coordinates = feature.getGeometry().getCoordinates();

                    // 判断该点是否在圆内部
                    if (polygon.intersectsCoordinate(coordinates)) {
                        select.getFeatures().push(feature);
                    }
                });

                // 遍历被选中的要素
                var selected = [];
                var selectedFeatures = select.getFeatures();
                for (var i = 0; i < selectedFeatures.getLength(); i++) {
                    var feature = selectedFeatures.item(i);
                    var name = feature.get('name');
                    selected.push(name);
                }

                // 输出查询结果
                var msg = selected.join('、');
                document.getElementById('msg').innerText = '被选中的要素:' + msg;
            }
        });

        // 添加交互工具
        map.addInteraction(drawBox);
        map.addInteraction(select);
    </script>
</body>
</html>

运行结果如下图所示:
在这里插入图片描述

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐