openlayers7实现点图查询的两种方法

241 阅读1分钟

openlayers实现点图查询我能想到的有两种方法:

一种是通过给map挂载点击事件,点击事件会传入事件对象e,利用map.getEventPixel(e.originalEvent)方法获取点击的像元pixel,然后通过map.forEachFeatureAtPixel(pixel,(feature)=>{return feature;})遍历map中的所有与pixel相交的feature,以此获得点击到的feature对象。

                map.on("click", (e) => {
                    const pixel = map.getEventPixel(e.originalEvent);
                    const feature = map.forEachFeatureAtPixel(pixel, (feature, whereLayer) => {
                        // 第二个参数whereLayer代表feature所在图层
                        return feature;
                    })
                    this.feature = feature;
                })

另一种是通过给map添加 选择交互## ol/interaction/Select 的方式获得点击到的feature

            // 设置点击时被选中
            const select = new Select({ condition: click });
            select.on("select", (e) => {
                const feature = e.target.getFeatures();
                this.feature = feature.array_[0];
            })
            map.addInteraction(select);

最后通过设置Overlay的方式展示点击的feature的信息

下面是我在vue2项目中写的一个点图查询的组件(这也是上面的代码的出处)

<template>
    <div id="map">
        <div id="popup" class="ol-popup">
            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
            <div id="popup-content"></div>
        </div>
    </div>
</template>
<script>
import VectorLayer from 'ol/layer/Vector';
import Map from "ol/Map"
import { Overlay, View } from 'ol';
import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import * as olProj from "ol/proj";
import { Style, Fill } from 'ol/style';
import Select from 'ol/interaction/Select';
import { click } from 'ol/events/condition';

export default {
    data() {
        return {
            openMap: null,
            feature: null
        }
    },
    mounted() {
        this.initMap();
        this.addClickEvt();
        // 还有一种方法就是点图选择要素(这里不采用这种方式)
        // this.addSelectInteraction();
        this.addOverlay();
    },
    methods: {
        initMap() {
            this.openMap = new Map({
                target: "map",
                layers: [
                    new VectorLayer({
                        source: new VectorSource({
                            url: 'https://openlayers.org/data/vector/ecoregions.json',
                            format: new GeoJSON(),
                        }),
                        background: 'white',
                        style: function (feature) {
                            const style = new Style({
                                fill: new Fill({
                                    color: '#eeeeee',
                                }),
                            });
                            const color = feature.get('COLOR') || '#eeeeee';
                            style.getFill().setColor(color);
                            return style;
                        },
                    })
                ],
                view: new View({
                    center: olProj.fromLonLat([108.945951, 34.465262]),
                    zoom: 4
                }),
                controls: []
            })
        },
        addClickEvt() {
            this.openMap.on("click", (e) => {
                const pixel = this.openMap.getEventPixel(e.originalEvent);
                const feature = this.openMap.forEachFeatureAtPixel(pixel, (feature, whereLayer) => {
                    // 第二个参数whereLayer代表feature所在图层
                    return feature;
                })
                this.feature = feature;
            })
        },
        addSelectInteraction() {
            // 设置点击时被选中
            const select = new Select({ condition: click });
            select.on("select", (e) => {
                const feature = e.target.getFeatures();
                this.feature = feature.array_[0];
            })
            this.openMap.addInteraction(select);
        },
        addOverlay() {
            const container = document.getElementById('popup');
            const content = document.getElementById('popup-content');
            const closer = document.getElementById('popup-closer');
            const overlay = new Overlay({
                element: container,
                // autoPan属性用来保证view能够完全将弹出的弹窗展示出来
                autoPan: {
                    animation: {
                        duration: 250,
                    },
                },
            });
            closer.onclick = function () {
                overlay.setPosition(undefined);
                closer.blur();
                return false;
            };
            // 这里用箭头函数,使得this指向当前的vue实例
            this.openMap.on('singleclick', (evt) => {
                const coordinate = evt.coordinate;
                try {
                    content.innerHTML = `ECO_NAME: ${this.feature.values_.ECO_NAME}`;
                    overlay.setPosition(coordinate);
                } catch (error) {
                    // 如果点击的pixel没有feature则将刚才的弹窗删去
                    overlay.setPosition(undefined);
                }
            });
            this.openMap.addOverlay(overlay);
        }
    }
}
</script>
<style>
#map {
    height: 100%;
    width: 100%;
}

.ol-popup {
    position: absolute;
    background-color: white;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
    padding: 15px;
    border-radius: 10px;
    border: 1px solid #cccccc;
    bottom: 12px;
    left: -50px;
    min-width: 280px;
    line-height: 20px;
}

.ol-popup:after,
.ol-popup:before {
    top: 100%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
}

.ol-popup:after {
    border-top-color: white;
    border-width: 10px;
    left: 48px;
    margin-left: -10px;
}

.ol-popup:before {
    border-top-color: #cccccc;
    border-width: 11px;
    left: 48px;
    margin-left: -11px;
}

.ol-popup-closer {
    text-decoration: none;
    position: absolute;
    top: 2px;
    right: 8px;
}

.ol-popup-closer:after {
    content: "✖";
}
</style>

最终的效果:

这是第一种方法的addClickEvt()

01.gif 这是第二种方法的addSelectInteraction()

02.gif