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