简体   繁体   English

TypeScript + OpenLayers 7:设置和获取功能 ID 失败

[英]TypeScript + OpenLayers 7: Set and get feature id fails

I have a map with two custom buttons: Draw Polygon and Remove Feature , which allows me to draw- and remove drawn polygons.我有一个带有两个自定义按钮的 map: Draw PolygonRemove Feature ,它允许我绘制和删除绘制的多边形。 In addition, I create a measure overlay for the polygon(s) which show their area (see image).此外,我为显示其面积的多边形创建了一个测量叠加层(见图)。 To identify the connection between a polygon and an overlay I attempt to set the same id on them so I can find and remove the overlay when removing the polygon by doing:为了识别多边形和覆盖之间的连接,我尝试在它们上设置相同的 id,以便在删除多边形时可以找到并删除覆盖:

const featureId = feature.get('id')
const overlay = map.getOverlayById(featureId)
map.removeOverlay(overlay)

However, when attempting to read the id of the polygon, it always returns undefined.但是,当尝试读取多边形的 id 时,它总是返回 undefined。 I also tried to set the id as a property and fetch that, but that also fails.我还尝试将 id 设置为属性并获取它,但这也失败了。

To make it easier to follow along:为了更容易跟随:

  • I assign the id in the Polygon class我在多边形 class 中分配 id
  • I read the id in the RemovePolygonButton class我在 RemovePolygonButton class 中读取了 ID

import Map from 'ol/Map'
import OSM from 'ol/source/OSM'
import Draw from 'ol/interaction/Draw';
import TileLayer from 'ol/layer/Tile'
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View'
import { Control } from 'ol/control'
import { Geometry } from 'ol/geom';
import { transform, useGeographic } from 'ol/proj';
import Feature, { FeatureLike } from 'ol/Feature';
import { Overlay } from 'ol';
import { getArea } from 'ol/sphere';
import { unByKey } from 'ol/Observable';
import { EventsKey } from 'ol/events';
import { Coordinate } from 'ol/coordinate';

/**
 * Map component
 */
export default class MapComponent {

    map: Map
    featureLayer: FeatureLayer

    constructor() {
        useGeographic()
        
        this.map = new Map({
            controls: [],
            layers: [
                new TileLayer({
                    source: new OSM(),
                })
            ],
            view: new View({
                center: [0, 0],
                zoom: 2
            }),
            target: "map"
        })

        this.featureLayer = new FeatureLayer()

        // Add Feature Layer
        this.map.addLayer(this.featureLayer)

        // Add Custom Controls to Draw- and Remove Polygon
        this.map.addControl(new DrawPolygonButton(this, this.map))
        this.map.addControl(new RemovePolygonButton(this, this.map))
    }

    public getFeatureLayer(): FeatureLayer {
        return this.featureLayer
    }

    public getMap() {
        return this.map
    }
}

/**
 * This is the layer we want to draw the polygon (feature) on
 */
class FeatureLayer extends VectorLayer<VectorSource<Geometry>> {
    constructor() { 
        super({
            source: new VectorSource(),
            properties: {
                title: 'featureLayer'
            }
        })
    }
}

/**
 * A button which starts the drawing process
 */
class DrawPolygonButton extends Control {
    constructor(mapComponent: MapComponent, map: Map) {
        const button = document.createElement('button')
        button.innerHTML = 'Draw Polygon'

        super({ element: button })

        button.addEventListener('click', () => {
            const featureLayerSource = mapComponent.getFeatureLayer()?.getSource()

            if (featureLayerSource) {
                new Polygon(map, featureLayerSource)
            }
        })
    }
}

/**
 * A button which should listen to clicking on the map, and if it hits a polygon on the
 * FeatureLayer it should remove it
 */
class RemovePolygonButton extends Control {
    constructor(mapComponent: MapComponent, map: Map) {
        const button = document.createElement('button')
        button.innerHTML = 'Remove Feature'

        super({ element: button })

        button.addEventListener('click', () => {
            map.on('click', (evt: any) => {
                try {
                    const featureLayerSource = mapComponent.getFeatureLayer()?.getSource()
    
                    const features: any[] = [] // It does find features
                    map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) {
                        features.push(feature);
                    })

                    for (const feature of features) {
                        console.log('Feature: ', feature) // Feature exist
                        console.log('Title: ', feature.get('title')) // undefined
                        console.log('ID: ', feature.get('id')) // undefined
                        console.log('ID: ', feature.getId()) // undefined
    
                        const featureId = feature.get('id')
                        const overlay = map.getOverlayById(featureId)

                        // Remove overlay
                        map.removeOverlay(overlay)

                        // Remove feature
                        featureLayerSource?.removeFeature(feature)

                    }
                } catch (err) {
                    console.log('Error: ', err)
                }
            })
        })
    }
}

/**
 * The Polygon will be added to the map
 */
class Polygon extends Draw {
    id: string
    sketch: Feature | undefined
    measureTooltipElement: HTMLElement | undefined
    measureTooltip: Overlay | undefined

    constructor(map: Map, featureLayerSource: VectorSource) {
        super({
            type: 'Polygon',
            source: featureLayerSource
        })    

        this.id = 'randomid' // Creating id

        // this.setId('randomId') This does not work: Property 'setId' does not exist on type 'Polygon'.ts(2339)

        this.set('id', this.id) // Assigning id with set()

        this.setProperties({ // Assigning id (and title) with setProperties() 
            'id': this.id,
            'title': this.id
        })

        this.createMeasureTooltip(map)
        let listener: EventsKey | EventsKey[] | undefined = undefined

        this.on('drawstart', (event: any) => {
            this.sketch = event.feature
            
            if (!this.sketch) {
                return
            }

            let tooltipCoord: Coordinate = event.coordinate;
        
            // Show measurements while drawing
            listener = this.sketch.getGeometry()?.on('change', (evt: any) => {
                const geom = evt.target
                const output = this.formatArea(geom)
                tooltipCoord = geom.getInteriorPoint().getCoordinates()
            
                if (this.measureTooltipElement && this.measureTooltip) {
                    this.measureTooltipElement.innerHTML = output
                    this.measureTooltip.setPosition(tooltipCoord)
                }
            })
        })


        this.on('drawend', () => {
            map.removeInteraction(this)

            if (this.measureTooltipElement && this.measureTooltip) {
                this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'
                this.measureTooltip.setOffset([0, -7])

                // unset sketch
                this.sketch = undefined
                
                // unset tooltip so that a new one can be created
                this.measureTooltipElement = undefined
                this.createMeasureTooltip(map)
                
                if (listener) {
                    unByKey(listener)
                }
            }

            // Create measure tooltip
            this.createMeasureTooltip(map)
        })        

        map.addInteraction(this);
    } 

    private formatArea(polygon: any): string {
        const area = getArea(polygon)
        return area > 10000 ? 
            Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>' :
            Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>'
    }

    private createMeasureTooltip(map: Map): void {
        if (this.measureTooltipElement) {
            this.measureTooltipElement?.parentNode?.removeChild(this.measureTooltipElement)
        }

        this.measureTooltipElement = document.createElement('div')
        this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure'
        this.measureTooltip = new Overlay({
            id: this.id, // Assigning overlay id
            element: this.measureTooltipElement,
            offset: [0, -15],
            positioning: 'bottom-center',
            stopEvent: false,
            insertFirst: false,
        })

        map.addOverlay(this.measureTooltip)
    }
}

在此处输入图像描述 在此处输入图像描述

Your code is setting properties on the draw interaction, to set properties or an id on the features it draws you would need您的代码正在绘制交互上设置属性,以设置您需要绘制的特征的属性或 id

    this.on('drawend', (event) => {
        event.feature.setId('randomId')
        

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM