Source: control/ControlLayerVisibility.js

import { unByKey } from 'ol/Observable'

import Bar from 'ol-ext/control/Bar'
import Toggle from 'ol-ext/control/Toggle'
import TextButton from 'ol-ext/control/TextButton'

import { getButtonHtml } from './ControlBarUtils'

// écouteurs d'event sur les suppressions de calques de core
const coreLayerEvents = []

// change la visibilité d'un calque
const toggleLayerVisibility = async function (evt) {
  if (evt.target.get('layerid') === '__allbackground') {
    this.updating = true
    this.viewer.commonLayer.getLayers('background').forEach((layer) => layer.setVisible(evt.active))
    this.updating = false
    setBackGroundActiveState.call(this, evt.target)
    return
  }
  const layer = this.viewer.commonLayer.getLayer(evt.target.get('layerid'), evt.target.get('type'))
  layer.setVisible(evt.active)
}

// calcul l'état du bouton "background"
const setBackGroundActiveState = function (ctrl) {
  // on ne change pas l'état du bouton si c'est a cause de toggleLayerVisibility
  if (this.updating) { return }
  const active = this.viewer.commonLayer.getLayers('background').some((layer) => layer.getVisible())
  ctrl.setActive(active)
}

const onToggle = function (active) {
  this.toggle.toggle()
}

/**
 *
 * @param {Object} options
 * @param {Object} options.viewer Instance de kmapviewer
 * @param {string} options.className classe de la barre de layers
 * @param {Element|string} html contenu du bouton
 * @param {string} icon icone si html non saisie (utilisé comme <i class='icon'/>)
 * @returns {object} ControlBarLayerBar
 */
const ControlBarLayerVisibility = function (options) {
  options = options || {}
  this.viewer = options.viewer || null
  this.className = (options.className || '') + ' kmapv-layer-visibility-bar'
  this.updating = false

  this.toggle = new Toggle({
    name: 'kmapv-layer-visibility-bar',
    html: options.html ? options.html : (options.icon ? `<i class="${options.icon}"></i>` : '<i class="kmapv-icon kmapv-icon-layers"></i>'),
    title: options.title,
  })
  this.toggle.set('modal', true)
  // si on ajoute ou supprimer des calques on rebuild la liste des calques
  this.viewer.Map.getLayers().on('change:length', this.setLayerList.bind(this))
  this.setLayerList()
  return this.toggle
}

ControlBarLayerVisibility.prototype.setLayerList = function () {
  // retire les event qu'on a posé sur core liés aux calques
  coreLayerEvents.forEach(unByKey)
  coreLayerEvents.splice(0, coreLayerEvents.length)
  // retire la liste des calques actuels
  this.toggle.setSubBar(null)

  const layerIdProperty = this.viewer.commonLayer.propertiesName.ID_LAYER
  const uiProperty = this.viewer.commonLayer.propertiesName.UI_LAYER

  let controls = []
  const backgroundLayers = this.viewer.commonLayer.getLayers('background')

  // Il y a un background, on le mets dans la liste des boutons, il agira sur tous les backgrounds
  if (backgroundLayers.length > 0) {
    const ctrl = new Toggle({
      html: '<i class="kmapv-icon kmapv-icon-map"></i>',
      name: 'kmapv-layer-allbackground',
      title: 'Fond de plan',
      onToggle: onToggle.bind(this),
    })

    ctrl.set('layerid', '__allbackground')
    ctrl.set('type', 'background')

    // avant l'event change:active car celui-ci est appelé au chargement
    setBackGroundActiveState.call(this, ctrl)
    ctrl.on('change:active', toggleLayerVisibility.bind(this))
    backgroundLayers.forEach(layer => {
      const layerId = layer.get(layerIdProperty)
      // abonnement a la visibilité d'un calque pour refleter le toggle si un evenement exterieur modifi l'état du groupe "background"
      const listenerId = layer.on('change:visible', () => setBackGroundActiveState.call(this, ctrl))

      coreLayerEvents.push(this.viewer.once(`removedLayer:${layerId}`, () => {
      // Retire les events de la Map et la View liés au layer
        unByKey(listenerId)
      }))
    })

    controls.push(ctrl)
  }

  const datalayers = this.viewer.commonLayer.getLayers('data')
  if (controls.length > 0 && datalayers.length > 0) {
    const separator = new TextButton({
      name: 'kmapv-separator',
      className: 'separator',
      text: '',
    })
    separator.set('type', 'separator')
    controls.push(separator)
  }

  const layerCtrls = this.viewer.commonLayer.getLayers('data').filter(layer => layer.displayInLayerSwitcher !== false).map(layer => {
    const layerId = layer.get(layerIdProperty)
    const ui = layer.get(uiProperty)
    const layerVisible = layer.getVisible()
    const ctrl = new Toggle({
      // html: ,
      name: `kmapv-layer-${layerId}`,
      onToggle: onToggle.bind(this),
      className: layerVisible ? '' : 'faded',
      active: layer.getVisible(),
      title: ui?.title,
      html: getButtonHtml(ui.html, ui.iconId, ui.icon, '<i class="kmapv-icon kmapv-icon-eye"></i>'),
    })
    ctrl.set('layerid', layerId)
    ctrl.set('order', layer.getZIndex())
    ctrl.set('type', 'data')
    ctrl.on('change:active', toggleLayerVisibility.bind(this))

    // abonnement a la visibilité d'un calque pour refleter le toggle si un evenement exterieur modifi l'état du calque
    const listenerId = layer.on('change:visible', (e) => {
      ctrl.setActive(e.target.get(e.key))
    })
    coreLayerEvents.push(this.viewer.once(`removedLayer:${layerId}`, () => {
      // Retire les events de la Map et la View liés au layer
      unByKey(listenerId)
    }))
    return ctrl
    // controls.push(ctrl)
  }).sort((a, b) => a.get('order') - b.get('order'))

  controls = controls.concat(layerCtrls)

  const bar = new Bar({
    className: this.className,
    group: true,
    toggleOne: false,
    controls,
  })

  this.toggle.setSubBar(bar)
}

export default ControlBarLayerVisibility