Home Reference Source

src/api/FeatureAPI.js

import $ from 'jquery'
import Collection from 'ol/Collection'
import Draw from 'ol/interaction/Draw'
import Modify from 'ol/interaction/Modify'
import { cssClasses } from '../globals'
import { FeatureInteraction } from '../interactions/FeatureInteraction'

export class FeatureAPI {
  constructor (mainAPI, map) {
    /**
     * @type {API}
     * @private
     */
    this.mainAPI_ = mainAPI

    /**
     * @type {G4UMap}
     * @private
     */
    this.map_ = map
  }

  /**
   * draw a feature
   * @param {object} [options={}]
   * @param {StyleLike} [options.style]
   * @param {string} [options.type='Point'] possible values are: 'Point', 'LineString', 'Polygon', 'MultiPoint',
   *  'MultiLineString', 'MultiPolygon' or 'Circle'
   * @returns {Promise<Feature>}
   */
  drawFeature (options = {}) {
    this.mainAPI_.cancelInteractions()

    const collection = new Collection()

    const style = this.map_.get('styling').getStyle(options.style || this.mainAPI_.getDrawStyle())
    this.map_.get('styling').manageFeatureCollection(collection)

    const interaction = new Draw({
      features: collection,
      type: options.type || 'Point',
      style: style
    })

    this.map_.addSupersedingInteraction('singleclick dblclick pointermove', interaction)

    $(this.map_.getViewport()).addClass(cssClasses.crosshair)

    return new Promise(resolve => {
      this.mainAPI_.once('cancelInteractions', () => {
        if (interaction.getActive()) {
          interaction.setActive(false)
          this.map_.removeInteraction(interaction)
          $(this.map_.getViewport()).removeClass(cssClasses.crosshair)
          resolve(null)
        }
      })
      interaction.on('drawend', e => {
        interaction.setActive(false)
        this.map_.removeInteraction(interaction)
        $(this.map_.getViewport()).removeClass(cssClasses.crosshair)
        resolve(e.feature)
      })
    })
  }

  /**
   * Select a feature with a single click
   * @returns {Promise<{feature: Feature, layer: VectorLayer}>}
   */
  selectFeature () {
    this.mainAPI_.cancelInteractions()

    const interaction = new FeatureInteraction({
      type: 'singleclick'
    })

    this.map_.addSupersedingInteraction('singleclick', interaction)

    $(this.map_.getViewport()).addClass(cssClasses.arrow)

    return new Promise(resolve => {
      this.mainAPI_.once('cancelInteractions', () => {
        if (interaction.getActive()) {
          interaction.setActive(false)
          this.map_.removeInteraction(interaction)
          $(this.map_.getViewport()).removeClass(cssClasses.arrow)
          resolve(null)
        }
      })
      interaction.on('interaction', e => {
        if (e.interacted.length) {
          interaction.setActive(false)
          this.map_.removeInteraction(interaction)
          $(this.map_.getViewport()).removeClass(cssClasses.arrow)
          resolve({
            feature: e.interacted[0].feature,
            layer: e.interacted[0].layer
          })
        }
      })
    })
  }

  /**
   * Modify a given Feature. The end function needs to be called to indicate that a modifying process is completed.
   * @param {ol.Feature[]|ol.Feature} features
   * @param {Object} options
   * @param {StyleLike} [options.style]
   */
  modifyFeature (features, options = {}) {
    this.mainAPI_.cancelInteractions()

    features = Array.isArray(features) ? features : [features]

    options.features = new Collection(features)

    if (options.style) {
      options.style = this.map_.get('styling').getStyle(options.style)
    }

    const interaction = new Modify(options)

    this.map_.addSupersedingInteraction('singleclick dblclick pointermove', interaction)

    $(this.map_.getViewport()).addClass(cssClasses.crosshair)

    this.mainAPI_.once('cancelInteractions', () => {
      $(this.map_.getViewport()).removeClass(cssClasses.crosshair)
      interaction.setActive(false)
      this.map_.removeInteraction(interaction)
    })
  }
}