Source: control/ControlCreateTools.js

import { unByKey } from 'ol/Observable'

import OlControl from 'ol/control/Control'
import OlExtElement from 'ol-ext/util/element'

import CustomDrawTouch from '../interaction/CustomDrawTouch'
import { createInteractiveHelp } from './ControlUtils'

/** Controle interaction pour la création */

/**
 *
 * @param {Object} options
 * @param {Object} options.viewer Instance de kmapviewer
 * @param {string} options.className classe de la barre de creation
 * @param {object} options.methods méthodes addPoint,removePoint,cancel, validate
 * @param {object} options.digitalizeOptions options de digit pour les RG interne
 */
class ControlCreateTools extends OlControl {
  constructor (options) {
    if (!options) options = {}

    const className = options.className !== undefined ? options.className : ''

    const classNames = (className || '') + ' kmapv-bottom-tools kmapv-create-tools' + (options.target ? '' : ' ol-unselectable ol-control')
    const element = OlExtElement.create('DIV', {
      className: classNames,
    })

    super({
      element,
      target: options.target,
    })

    if (!!this.viewer || !!this.interaction) {
      console.error('[ControlCreateTools] initialisé sans le viewer ou l\'interaction')
      return
    }

    this.viewer = options.viewer || null
    this.interaction = options.interaction || null
    this.interactionMode = this.interaction instanceof CustomDrawTouch ? 'touch' : 'click'

    this.geometryType = options.geometryType || 'Point'
    this.digitalizeOptions = options.digitalizeOptions || {}

    const geomTitle = { Point: 'le point', LineString: 'la ligne', Polygon: 'la forme' }[this.geometryType]
    const title = options.title || `Créer ${geomTitle}`

    const hideToolbox = !!(options.hideToolbox && !this.isMultiGeometry)
    const hideGPS = options.hideGPS || false

    element.style.display = hideToolbox ? 'none' : null

    // TODO ajouter toggle pour snapper

    const gpsHtml = '<i class="kmapv-icon kmapv-icon-gps-on"></i><span>Pos. GPS</span>'
    const validHtml = '<i class="kmapv-icon kmapv-icon-valid"></i><span>Valider</span>'
    const addHtml = '<i class="kmapv-icon kmapv-icon-plus"></i><span>Ajouter</span>'
    const removeHtml = '<i class="kmapv-icon kmapv-icon-minus"></i><span>Retirer</span>'
    const cancelHtml = '<i class="kmapv-icon kmapv-icon-cancel"></i><span>Annuler</span>'
    const snapHtml = 'Accrochage objet'

    // utilisation du GPS
    this.positionAvailable = this.viewer?.geoLocation && this.viewer.geoLocation.isAvailable()

    const helpTexts = []
    if (!hideGPS) {
      helpTexts.push(`${gpsHtml} Déplacer la carte sur votre position GPS<br/>`)
    }
    if (this.geometryType !== 'Point') {
      if (this.interactionMode === 'touch') {
        helpTexts.push(`${addHtml} Ajouter un point à ${geomTitle}
        <br>
        <div class="subtitle">
          Vous pouvez ajouter un point par tap/clic dans la carte
        </div>`)
      }
      helpTexts.push(`${removeHtml} Retirer un point de la ${geomTitle}<br>`)
    }
    if (!(this.geometryType === 'Point' && this.interactionMode === 'click')) {
      helpTexts.push(`${validHtml} ${title}<br/><div class="subtitle">
        Vous pouvez terminer la création <br/>par un double-clic dans la carte
        </div>`)
    } else {
      helpTexts.push(`<i class="kmapv-icon kmapv-icon-mouse-click"></i> Cliquer dans la carte pour ${title}<br/>`)
    }

    helpTexts.push(`${cancelHtml} Annuler la création`)

    const { helpTitle, helpDiv } = createInteractiveHelp({
      title,
      buttonTitle: options.title || options.label || 'Afficher / Masquer l\'aide',
      helpTexts,
    })

    if (this.digitalizeOptions.snapOptions) {
      helpDiv.firstChild.appendChild(document.createElement('br'))
      OlExtElement.createSwitch({
        html: '',
        after: snapHtml,
        checked: true,
        change: (e) => {
          this.interaction.setSnapOptions(e.target.checked ? this.digitalizeOptions.snapOptions : null)
        },
        parent: helpDiv.firstChild,
      })
      this.interaction.setSnapOptions(this.digitalizeOptions.snapOptions)
    }

    element.appendChild(helpTitle)
    element.appendChild(helpDiv)
    // #endregion

    // #region boutons

    const btnDiv = OlExtElement.create('DIV', {
      className: 'tools',
    })

    this.gpsBtn = document.createElement('button')
    this.gpsBtn.type = 'button'
    this.gpsBtn.disabled = !this.positionAvailable
    this.gpsBtn.innerHTML = gpsHtml
    this.gpsBtn.addEventListener('click', onClickGps.bind(this))

    this.validBtn = document.createElement('button')
    this.validBtn.type = 'button'
    this.validBtn.innerHTML = validHtml
    this.validBtn.addEventListener('click', onClickValid.bind(this))

    this.addBtn = document.createElement('button')
    this.addBtn.type = 'button'
    this.addBtn.innerHTML = addHtml
    this.addBtn.addEventListener('click', onClickPlus.bind(this))

    this.removeBtn = document.createElement('button')
    this.removeBtn.type = 'button'
    this.removeBtn.innerHTML = removeHtml
    this.removeBtn.addEventListener('click', onClickMinus.bind(this))

    this.cancelBtn = document.createElement('button')
    this.cancelBtn.type = 'button'
    this.cancelBtn.innerHTML = cancelHtml
    this.cancelBtn.addEventListener('click', onClickCancel.bind(this))

    if (!hideGPS) { btnDiv.appendChild(this.gpsBtn) }

    if (this.geometryType !== 'Point') {
      // le bouton + n'est pas dispo en mode clic
      if (this.interactionMode === 'touch') {
        btnDiv.appendChild(this.addBtn)
      }
      btnDiv.appendChild(this.removeBtn)
    }
    if (!(this.geometryType === 'Point' && this.interactionMode === 'click')) {
      // pas besoin de valid en mode click + point
      btnDiv.appendChild(this.validBtn)
    }
    btnDiv.appendChild(this.cancelBtn)

    element.appendChild(btnDiv)

    // #endregion

    const listenerListPoint = this.interaction.on('listpoint:change', this.onListPointChange.bind(this))
    const listenerDrawEnd = this.interaction.on('drawend', () => { this.onListPointChange({ listPoints: [] }) })
    // lorsque ce controle est retiré de la carte, on arrête d'écouter les event
    const listenerRemoveControl = this.viewer.Map.getControls().on('remove', (ev) => {
      if (ev.element === this) {
        unByKey(listenerListPoint)
        unByKey(listenerDrawEnd)
        unByKey(listenerRemoveControl)
      }
    })

    this.onListPointChange({ listPoints: [] })
  }

  get isMultiGeometry () {
    return ['GeometryCollection', 'MultiPoint', 'MultiPolygon', 'MultiLineString'].includes(this.geometryType)
  }
}

/** Suivant le nombre de points et les RG en entré on active/désactive des boutons */
ControlCreateTools.prototype.onListPointChange = function (ev) {
  const removePointDisabled = ev.listPoints.length === 0
  const addPointDisabled = this.digitalizeOptions.maxPoints ? (ev.listPoints.length >= this.digitalizeOptions.maxPoints) : false
  let validateDisabled = false

  // en mode clic on ne va
  switch (this.geometryType) {
    case 'Point':
      validateDisabled = false
      break
    case 'LineString':
      validateDisabled = this.interactionMode === 'touch' ? ev.listPoints.length < 1 : ev.listPoints.length < 2
      break
    case 'Polygon':
      validateDisabled = this.interactionMode === 'touch'
      // l'outil de sketch d'ou on tire listPoint renvoit directement 2 coordonnée dés qu'on place le premier pt d'un polygone
        ? ev.listPoints.length < 3
        : ev.listPoints.length < 4

      break
  }

  this.validBtn.disabled = validateDisabled
  this.addBtn.disabled = addPointDisabled
  this.removeBtn.disabled = removePointDisabled
}

const onClickGps = function () {
  const position = this.viewer.geoLocation.getPosition()
  if (position) {
    this.viewer.setCenter(position)
  }
}

const onClickValid = function () {
  this.interaction.finishDrawing()
}

const onClickPlus = function () {
  this.interaction.addPoint()
}

const onClickMinus = function () {
  this.interaction.removeLastPoint()
}

const onClickCancel = function () {
  this.interaction.abortDrawing()
}

export default ControlCreateTools