import '../../typedef/index'
import Button from 'ol-ext/control/Button'
import TextButton from 'ol-ext/control/TextButton'
import Toggle from 'ol-ext/control/Toggle'
import Bar from 'ol-ext/control/Bar'
import DragZoom from 'ol/interaction/DragZoom'
import OlExtElement from 'ol-ext/util/element'
import LayerSwitcher from 'ol-ext/control/LayerSwitcher'
import SearchPhoton from 'ol-ext/control/SearchPhoton'
import SearchBANAdvanced from './SearchBANAdvanced'
import SearchWFS from './SearchWFS'
import ControlBarSelectCreate from './ControlBarSelectCreate'
import ControlBarLayerVisibility from './ControlLayerVisibility'
import ControlTriangulation from './ControlTriangulation'
import ControlRecordTrace from './ControlRecordTrace'
import ControlLayerFilters from './ControlLayerFilters'
import { getButtonHtml } from './ControlBarUtils'
import { SelectModes } from '../datalayer/data-layer'
import { unByKey } from 'ol/Observable'
import CustomGeoBookmark from './CustomGeoBookmark'
import ControlZoomScaleResolution from './ControlZoomScaleResolution'
import ControlBarZoom from './ControlBarZoom'
import ZoomSlider from 'ol/control/ZoomSlider'
import Rotate from 'ol/control/Rotate'
import * as olEasing from 'ol/easing'
class ControlBar extends Bar {
/**
* surcharge de olext bar afin de simplifier son utilisation
* @param {Object} options Options compatible ol-ext ol.control.bar surchargé de buttonList
* @param {string[]} hideOnMapMode Cache la toolbar si un de ces modes de carte est lancé
* @param {Array<btnOption>} options.buttonList
* @param {String} btnOption.type Type de bouton (control, button, toggle, textButton)
* @param {Object} btnOption.control [control] ol.control valide
* @param {String} btnOption.className [button,toggle,textButton] classe du bouton
* @param {String} btnOption.title [button,toggle,textButton] titre du bouton
* @param {String} btnOption.icon [button,toggle] icon du bouton
* @param {String} btnOption.iconId [button,toggle] icon du bouton
* @param {String} btnOption.text [textButton] texte du bouton
* @param {String} btnOption.html [button,toggle,textButton][remplace icon ou text] contenu html
* @param {function} btnOption.onClick [button,toggle,textButton] fonction a appeler au click
* @param {function} btnOption.handleClick [button,textButton]remplace onClick] fonction a appeler au click
* @param {function} btnOption.onToggle [toggle][remplace onClick] fonction a appeler au toggle (or use change:active event)
* @param {ol.interaction} btnOption.interaction [toggle] interaction associée au controle
* @param {bool} btnOption.active [toggle] the control is created active, default false
* @param {bool} btnOption.disable [toggle] the control is created disabled, default false
* @param {Bar} btnOption.bar [toggle] a subbar associated with the control (drawn when active if control is nested in a ol.control.Bar)
* @param {bool} btnOption.autoActive [toggle] the control will activate when shown in an ol.control.Bar, default false
*/
constructor (options) {
super(options)
// lire les options pour set des boutons, des toggles
if (options.position) {
this.setPosition(options.position)
}
this.viewer = options.viewer || null
this.hideOnMapMode = options.hideOnMapMode || []
this.selectToggle = null
if (options.buttonList) {
options.controls = this.buildButtons(options.buttonList)
}
this.viewer.on('change:mapmode', (mapMode) => {
if (this.hideOnMapMode.length === 0) return
if (this.hideOnMapMode.indexOf(mapMode.name) > -1) { this.setVisible(false) } else if (!this.getVisible()) { this.setVisible(true) }
})
/* const listenerRemoveControl = this.viewer.Map.getControls().on('remove', (ev) => {
if (ev.element === this) {
unByKey(listenerRemoveControl)
} else {
const ctrl = this.getControlByName(ev.element.get('name'))
const ctrlIndex = this.controls_.findIndex((control) => {
return control === ctrl
})
if (ctrlIndex > -1) {
this.controls_.splice(ctrlIndex, 1)
}
}
}) */
// Bar.call(this, options)
}
}
ControlBar.prototype.setMap = function (map) {
unByKey(this.listenerRemoveControl)
Bar.prototype.setMap.call(this, map)
if (map) {
this.listenerRemoveControl = map.getControls().on('remove', (ev) => {
if (ev.element === this) {
unByKey(this.listenerRemoveControl)
} else {
const ctrl = this.getControlByName(ev.element.get('name'))
const ctrlIndex = this.controls_.findIndex((control) => {
return control === ctrl
})
if (ctrlIndex > -1) {
this.controls_.splice(ctrlIndex, 1)
}
}
})
}
}
ControlBar.prototype.addControl = function (control) {
Bar.prototype.addControl.call(this, control)
// dans notre bar les contrôles peuvent être "modal", activer un modale désactive les autres
if (control.get('modal') && control instanceof Toggle) {
control.on('change:active', (evt) => {
if (evt.active === false) { return }
this.getActiveControls().forEach((ctrl) => {
if (ctrl.get('modal') && evt.target !== ctrl) {
ctrl.setActive(false)
}
})
})
}
}
/**
* Supprime un control de la bar
* @param {string} name control name utilisé lors de l'initialisation du control
*/
ControlBar.prototype.removeControl = function (name) {
const ctrl = this.getControlByName(name)
const ctrlIndex = this.controls_.findIndex((control) => {
return control === ctrl
})
if (ctrlIndex > -1) {
this.controls_.splice(ctrlIndex, 1)
this.viewer.Map.removeControl(ctrl)
}
}
/**
* construit des boutons suivant les parametre suivant
* @param {Array<btnOption>} buttonList
* @param {String} btnOption.type Type de bouton (control, button, toggle, textButton)
* @param {Object} btnOption.control [control] ol.control valide
* @param {String} btnOption.className [button,toggle,textButton] classe du bouton
* @param {String} btnOption.title [button,toggle,textButton] titre du bouton
* @param {String} btnOption.icon [button,toggle] icon du bouton
* @param {String} btnOption.iconId [button,toggle] icon du bouton
* @param {String} btnOption.text [textButton] texte du bouton
* @param {String} btnOption.html [button,toggle,textButton][remplace icon ou text] contenu html
* @param {function} btnOption.onClick [button,toggle,textButton] fonction a appeler au click
* @param {function} btnOption.handleClick [button,textButton]remplace onClick] fonction a appeler au click
* @param {function} btnOption.onToggle [toggle][remplace onClick] fonction a appeler au toggle (or use change:active event)
* @param {ol.interaction} btnOption.interaction [toggle] interaction associée au controle
* @param {bool} btnOption.active [toggle] the control is created active, default false
* @param {bool} btnOption.disable [toggle] the control is created disabled, default false
* @param {ol.control.Bar} btnOption.bar [toggle] a subbar associated with the control (drawn when active if control is nested in a ol.control.Bar)
* @param {bool} btnOption.autoActive [toggle] the control will activate when shown in an ol.control.Bar, default false
* @returns Array<ol.control.Control>
*/
ControlBar.prototype.buildButtons = function (buttonList) {
// type: button, toggle , textButton ou Control
return buttonList.map((options) => {
// c'est déjà un control, on l'utilise tel quel
if (options.type === 'control') { return options.control }
// prends des options supplémentaire afin d'harmoniser (icon, onclick...)
// mais si l'option native de olExt est présenté, elle a raison,
// exemple options.html prend le pas sur options.icon, handleClick > onClick
switch (options.type) {
case 'button':
return new Button({
html: getButtonHtml(options.html, options.iconId, options.icon, ''),
handleClick: options.onClick || undefined,
...options,
})
case 'toggle':
return new Toggle({
html: getButtonHtml(options.html, options.iconId, options.icon, ''),
onToggle: options.onClick,
...options,
})
case 'textButton':
return new TextButton({
html: `${options.text}`,
handleClick: options.onClick || undefined,
...options,
})
default: return null
}
})
}
/**
*
* @param {option} Object
* @param {String} option.type Type de bouton (control, button, toggle, textButton)
* @param {Object} option.control [control] ol.control valide
* @param {String} option.className [button,toggle,textButton] classe du bouton
* @param {String} option.title [button,toggle,textButton] titre du bouton
* @param {String} option.icon [button,toggle] icon du bouton
* @param {String} option.text [textButton] texte du bouton
* @param {String} option.html [button,toggle,textButton][remplace icon ou text] contenu html
* @param {function} option.onClick [button,toggle,textButton] fonction a appeler au click
* @param {function} option.handleClick [button,textButton]remplace onClick] fonction a appeler au click
* @param {function} option.onToggle [toggle][remplace onClick] fonction a appeler au toggle (or use change:active event)
* @param {ol.interaction} option.interaction [toggle] interaction associée au controle
* @param {bool} option.active [toggle] the control is created active, default false
* @param {bool} option.disable [toggle] the control is created disabled, default false
* @param {ol.control.Bar} option.bar [toggle] a subbar associated with the control (drawn when active if control is nested in a ol.control.Bar)
* @param {bool} option.autoActive [toggle] the control will activate when shown in an ol.control.Bar, default false
* @return {ol.control.Button}
*/
ControlBar.prototype.addButton = function (options) {
const control = this.buildButtons([options])[0]
this.addControl(control)
return control
}
/** non implementé */
ControlBar.prototype.addGroup = function (options) {
// TODO: ajoute un groupe (un controlbar imbriqué)
}
/** non implementé */
ControlBar.prototype.addControlBar = function (options) {
// TODO: ajoute un sous menu
}
ControlBar.prototype.addSeparator = function (options) {
options = options || {}
const className = options.className ? options.className + ' separator' : 'separator'
return this.addButton({
type: 'textButton',
name: 'separator',
className,
text: '',
})
}
/** Met a jour le html d'un control */
ControlBar.prototype.updateControlHtml = function (name, html) {
const control = this.getControlByName(name)
if (control) { control.setHtml(html) }
}
/** Met a jour l'icone */
ControlBar.prototype.updateControlIcon = function (name, icon) {
this.updateControlHtml(name, `<i class="${icon}"></i>`)
}
/**
* Renvoit un controle de la toolbar
* @param {string} name
* @returns {ol.control} control
*/
ControlBar.prototype.getControlByName = function (name) {
const controls = this.getControlsByName(name)
return controls.length === 1 ? controls[0] : null
}
/**
* Supprime la bar de création/sélection de la controlbar
*/
ControlBar.prototype.removeSelectCreateBar = function () {
this.removeControl('kmapv-select-create-bar')
this.removeControl('kmapv-clear-selection')
this.removeControl('kmapv-change-selectmode')
}
/**
* @typedef {Object} ClearButtonOptions
* @property {Element|string} [html] contenu du bouton (priorité 1)
* @property {string} [iconId] id du d'element du DOM (priorité 2)
* @property {string} [icon] <i class='icon'/> du bouton (priorité 3)
* @property {string} [title] tooltip du bouton clear
*
* Options supplémentaire pour l'ajout de la barre de selection
* @typedef {ClearButtonOptions} ClearButton
*/
/**
* Ajoute la bar de création/sélection sur la controlbar
* @param {SelectCreateOptions} options Options de barre d'outil de selection / creation
* @example
* returns ajoute la sous-barre de création-selection a cette barre d'outil
* mapviewer.horizontalToolbar.addSelectCreateBar({
* "className": "audit-edit-bar",
* "allowChangeSelectMode":true
* "clearButton": { // paramètre optionnels du bouton de clear sélection
* "icon": null, // voir getButtonHtml
* "html": "<i class=\\" q - icon map - tool - icon material - icons \\ ">not_interested</i>",
* "title": "Effacer la sélection"
* },
* "tools": [{ // liste des outils a afficher
* "type": "select",
* "toolId": "select-single", // sera renvoyé lors de la levé de l'event change:selection
* "html": "<i class=\\" q - icon map - tool - icon material - icons \\ ">touch_app</i>",
* "title": "Outil de sélection"
* }, {
* "type": "select",
* "toolId": "select-and-edit",
* "html": "<i class=\\" q - icon map - tool - icon material - icons \\ ">edit</i>",
* "title": "Editer",
* },
* { // separateur dans la barre d'outils
* "type": "separator"
* }, { // exemple d'un outil de création
* "toolId": "create-EQU", // sera renvoyé lors de la levé de l'event createfeature:create
* "idFeature" : "efefef-1234",
* "properties" : {test:1},
* "title": "Créer un Equipement",
* "type": "create",
* "iconId": "map-create-icon-create-EQU", // voir getButtonHtml
* "icon": "mdi-network",
* "options": {
* "geometryType": "GeometryCollection", // type de geometrie a créer (type geojson)
* "idLayer": "features-EQU", // calque ou créer la geométrie
* "digitalizeOptions": { // options de l'outil de digitalisation
* "showConstructionPoint": true,
* "maxPoints" : 5,
* "showConstructionLine" : true,
* },
* "createTemplates": { // templates de création de géométries
* "features": [{ // geojson features
* "type": "Feature",
* "geometry": {
* "type": "MultiPolygon",
* "coordinates": [coordonnées de l objet]
* },
* "properties": { // propriétés recopiées sur la feature openlayers créées (si elle n'existe pas déjà)
* "name": "Assainissement - Arbre"
* },
* "display": { // libellé affiché dans l'ihm de création
* "label": "Assainissement - Arbre"
* }
* }, {
* "type": "Feature",
* "geometry": {
* "type": "MultiPolygon",
* "coordinates": [coordonnées de l objet]
* },
* "properties": {
* "name": "Assainissement - Bac graisse"
* },
* "display": {
* "label": "Assainissement - Bac graisse"
* }
* },
* ]
* }
* }
* }
* ]
*})
*/
ControlBar.prototype.addSelectCreateBar = function (options) {
// on ne peut avoir qu'une seule selectCreateBar par controlbar
this.removeSelectCreateBar()
options = options || { }
options = {
...{ allowChangeSelectMode: true },
...options,
viewer: this.viewer,
}
const bar = new ControlBarSelectCreate(options)
this.addControl(bar)
// si il y a des outils de sélection, on ajoute le bouton de désélection
if (options.tools.some((tool) => {
return ['select', 'rectangular', 'multiselect', 'zonal', 'polygon'].indexOf(tool.type) > -1
})) {
if (options.allowChangeSelectMode) {
const btnRender = {
replace: { html: '<i class="kmapv-icon kmapv-icon-selectmode-replace"></i>', title: 'Simple : la nouvelle sélection remplace l\'ancienne' },
toggle: { html: '<i class="kmapv-icon kmapv-icon-selectmode-toggle"></i>', title: 'Inversion : Sélectionner un élément le bascule entre l\'état sélectionné et désélectionné' },
add: { html: '<i class="kmapv-icon kmapv-icon-selectmode-add"></i>', title: 'Additif: la nouvelle sélection s\'ajoute à l\'ancienne' },
}
const currentMode = this.viewer.dataLayer.getSelectMode()
const changeSelectModeBtn = new Button({
html: btnRender[currentMode].html,
name: 'kmapv-change-selectmode',
title: btnRender[currentMode].title,
handleClick: () => {
const currentMode = this.viewer.dataLayer.getSelectMode()
let newMode = SelectModes.REPLACE
switch (currentMode) {
case SelectModes.REPLACE:
newMode = SelectModes.ADD
break
case SelectModes.ADD:
newMode = SelectModes.TOGGLE
break
default:
}
this.viewer.dataLayer.setSelectMode(newMode)
},
})
this.viewer.on('change:selectMode', (evt) => {
changeSelectModeBtn.setHtml(btnRender[evt.selectMode].html)
changeSelectModeBtn.setTitle(btnRender[evt.selectMode].title)
})
this.addControl(changeSelectModeBtn)
}
const clearBtn = new Button({
html: getButtonHtml(options?.clearButton?.html, options?.clearButton?.iconId, options?.clearButton?.icon, '<i class="kmapv-icon kmapv-icon-clear-selection"></i>'),
name: 'kmapv-clear-selection',
title: options?.clearButton?.title || 'Effacer la sélection',
handleClick: () => {
this.viewer.dataLayer.clearCurrentSelection()
},
})
this.viewer.on('change:selection', (evt) => {
clearBtn.setVisible(evt.selection.length > 0)
})
clearBtn.setVisible(this.viewer.dataLayer.getCurrentSelection().length > 0)
this.addControl(clearBtn)
}
}
ControlBar.prototype.addLayerVisibilityBar = function (options) {
options = options || {}
options = {
...options,
viewer: this.viewer,
}
const bar = new ControlBarLayerVisibility(options)
this.addControl(bar)
}
/**
* Paramètre de recherche PostFilter
* @typdef {Object} PostFilter
* @property {'citycode'|'postalcode'|'city'|'context'} type type de filtre (seul les types 'citycode' et 'postalcode' sont pris en charge)
* @property {Array<string|number>} values liste des valeurs que l'on accepte
*
* Paramètre de recherche WfsSource
* @typdef {Object} WfsSource
* @property {String} name type de filtre
* @property {Object} wfs Paramère générale de la source
* @property {string} wfs.url Url du service
* @property {string?} [wfs.version=1.0.0] version du service
* @property {string} featureNS Namespace (a retrouver avec getCapabilities)
* @property {string} featurePrefix prefix de la source a interroger
* @property {Array<string>} featureTypes // liste des couches a interroger
* @property {Array<string>} searchIn // recherche ce que l'utilisateur va taper dans ces champs
* @property {Object} prefilter préfiltrage sur une des propriétée
* @property {string | Array} prefilter.key Nom du champ que l'on préfiltre, on peut utiliser une valeur, une liste de valeur ou un mot clé pour utiliser un résultat précédent (code_dep: "94" ou code_insee: ['94041','94081','94046','94002'] ou code_dep: '__PREVIOUS_RESULT__.commune.code_dep' ou code_com: '__PREVIOUS_RESULT__.commune.<%= code_insee.slice(2) %>')
* @property {string | Array} value nom du champ ou des champs a retourner (pour utiliser dans la cascade)
* @property {string} display libellé a afficher dans la liste
* @property {string?} placeholder surcharge du placeholder de la zone de recherche pour cette étape
* @property {string?} geometryName nom de la propriété géométrie (utilisé pour filtre bbox ou lors du zoom vers une feature)
* @property {boolean?} useBbox tente d'utiliser la bbox du résultat fin le plus proche comme filtre, geometryName est nécessaire
* @property {number?} minLength surcharge du nombre de caractère minimum a taper pour cette étape
*
*
* Permet d'ajouter un contrôle de recherche
* @param {Object} options Options de création du contrôle de recherche
* @param {'ban'|'photon'|'wfs'} [options.provider=ban] Nom du fournisseur pour la recherche
* @param {boolean} [options.reverse=false] Affiche un outil de géocodage inverse d'adresse
* @param {string} [options.reverseTitle=Cliquer sur la carte...] Titre à afficher sur le tooltip du bouton de géocodage inverse
* @param {boolean} [options.position=true] Priorise les résultats près du centre de la carte affichée
* @param {string} [options.label=Rechercher] Libellé affiché pour la zone de recherche
* @param {string} [options.placeholder=Rechercher une adresse] Placeholder de la zone de recherche
* @param {integer} [options.maxItems=10] Nombre de résultats affichés classés par score
* @param {integer} [options.limit=10] Nombre de résultats recherchés (utile lorsque l'on va appliquer un filtre)
* @param {number} [options.typing=500] le délais en ms pour lancer la recherche après une saisie utilisateur
* @param {integer} [options.minLength=3] la longueur de la chaine de recherche à partir de laquelle lancer la recherche
* @param {integer} [options.resultZoom=16] Zoom minimal à appliquer lors de la localisation sur la carte d'un résultat
* @param {Array<string>} [options.citycodes=[]] Liste de code insee sur lesquels on va lancer la recherche (attention, une requête sera réalisée par code insee)
* @param {Array<PostFilter>} [options.postfilters=[]] Liste des filtres à appliquer sur les résultats (attention, il est possible qu'aucun résultat ne s'affiche)
* @param {Array<WfsSource>} [options.wfsSources=[]] Options de recherche pour le type wfs en cascade (dans l'ordre du tableau)
*/
ControlBar.prototype.addSearchControl = function (options = {}) {
const searchOptions = {
provider: 'ban',
reverse: false,
reverseTitle: 'Cliquer sur la carte...',
position: true,
label: 'Rechercher',
placeholder: 'Rechercher une adresse',
maxItems: 10,
typing: 500,
minLength: 3,
limit: 10,
resultZoom: 16,
citycodes: [],
postFilters: [],
wfsSources: [],
...options,
}
const searchComponents = {
ban: SearchBANAdvanced,
photon: SearchPhoton,
wfs: SearchWFS,
}
if (!searchComponents[searchOptions.provider]) {
return
}
const SearchComponent = searchComponents[searchOptions.provider]
const search = new SearchComponent(searchOptions)
this.addControl(search)
// Select feature when click on the reference index
search.on('select', (event) => {
const view = this.viewer.Map.getView()
view.animate({
center: event.coordinate,
zoom: Math.max(view.getZoom(), searchOptions.resultZoom),
})
})
}
/**
* Ajoute le bouton de zoom rectangle a la toolbar
* @param {Object} options
* @param {Element|string} [options.html] contenu du bouton (priorité 1)
* @param {string} [options.iconId] id du d'element du DOM (priorité 2)
* @param {string} [options.icon] <i class='icon'/> du bouton (priorité 3)
*/
ControlBar.prototype.addZoomBox = function (options = {}) {
const dragZoom = new DragZoom({
condition: () => { return true },
})
const btnDragZoom = new Toggle({
html: getButtonHtml(options.html, options.iconId, options.icon, '<i class="kmapv-icon kmapv-icon-zoom-area"></i>'),
name: 'kmapv-zoom-area',
title: options.title || 'Zoom rectangle',
interaction: dragZoom,
})
// dragZoom.on('boxcancel', () => { btnDragZoom.setActive(false) })
dragZoom.on('boxend', () => { btnDragZoom.setActive(false) })
this.addControl(btnDragZoom)
}
ControlBar.prototype.addZoom = function (options = {}) {
// Contrôle de niveau de zoom
if (!options.extent) {
options.extent = this.viewer.zoomOrigin && (() => typeof this.viewer.zoomOrigin === 'function' ? this.viewer.zoomOrigin() : this.viewer.zoomOrigin)
}
this.addControl(new ControlBarZoom(options))
}
ControlBar.prototype.addZoomSlider = function (options = {}) {
// Contrôle de slider de zoom
this.addControl(new ZoomSlider({}))
}
ControlBar.prototype.addRotate = function (options = {}) {
this.addControl(new Rotate({
tipLabel: 'Retour au nord',
autoHide: true,
resetNorth: () => {
// On surcharge la fonction de réinitialisation du
// nord pour lever l'event resetnorth à l'exterieur
if (this.viewer.getRotation()) {
this.viewer.Map.getView().animate({
rotation: 0,
duration: 250,
easing: olEasing.easeOut,
})
this.viewer.dispatchEvent('resetnorth')
}
},
}))
}
/**
* Ajoute le bouton de sélection triangle
* @param {Object} options
* @param {Element|string} [options.html] contenu du bouton (priorité 1)
* @param {string} [options.iconId] id du d'element du DOM (priorité 2)
* @param {string} [options.icon] <i class='icon'/> du bouton (priorité 3)
* @param {object} [options.snapOptions] options de snap (doc TODO)
*/
ControlBar.prototype.addTriangulationTool = function (options = { snapOptions: {} }) {
const btn = new Button({
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-triangulation"></i>'),
name: 'kmapv-triangulation-tool',
title: options?.button?.title || 'Outil de triangulation',
handleClick: () => {
const ctrl = new ControlTriangulation({ viewer: this.viewer, snapOptions: options.snapOptions })
this.viewer.Map.addControl(ctrl)
},
})
this.addControl(btn)
}
/**
* Ajoute le bouton d'export de la carte vers une image
* @param {Object} options
* @param {Element|string} [options.html] contenu du bouton (priorité 1)
* @param {string} [options.iconId] id du d'element du DOM (priorité 2)
* @param {string} [options.icon] <i class='icon'/> du bouton (priorité 3)
* @param {string} options.imageType A string indicating the image format, default image/png
* @param {number} options.quality Number between 0 and 1 indicating the image quality to use for image formats that use lossy compression such as image/jpeg and image/webp
* @param {string} options.orientation Page orientation (landscape/portrait), default guest the best one
* @param {boolean} options.immediate force print even if render is not complete, default false
* @param {string} options.filename Nom de fichier
*/
ControlBar.prototype.addExportMapButton = function (options = { }) {
const btn = new Button({
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-download"></i>'),
name: 'kmapv-export-map-tool',
title: options?.button?.title || 'Télécharger une capture d\'écran de la carte',
handleClick: () => {
this.viewer.print(options)
},
})
this.addControl(btn)
}
/**
* Ajoute le bouton de copie de la carte vers le presse papier
* @param {Object} options
* @param {Element|string} [options.html] contenu du bouton (priorité 1)
* @param {string} [options.iconId] id du d'element du DOM (priorité 2)
* @param {string} [options.icon] <i class='icon'/> du bouton (priorité 3)
* @param {string} options.imageType A string indicating the image format, default image/png
* @param {number} options.quality Number between 0 and 1 indicating the image quality to use for image formats that use lossy compression such as image/jpeg and image/webp
* @param {string} options.orientation Page orientation (landscape/portrait), default guest the best one
* @param {boolean} options.immediate force print even if render is not complete, default false
*/
ControlBar.prototype.addCopyMapButton = function (options = { }) {
const btn = new Button({
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-clipboard"></i>'),
name: 'kmapv-clipboard-tool',
title: options?.button?.title || 'Copier la carte dans le presse papier',
handleClick: () => {
this.viewer.copyMap(options)
},
})
this.addControl(btn)
}
ControlBar.prototype.addRecordTraceButton = function (options = {}) {
options = { ...options, viewer: this.viewer }
const btn = new ControlRecordTrace(options)
this.addControl(btn)
return btn
}
ControlBar.prototype.addLayerManagerTool = function (options = { }) {
const toggle = new Toggle({
name: 'kmapv-layer-manager-bar',
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-layers"></i>'),
title: options?.button?.title || 'Afficher le gestionnaire de calque',
})
// lorsque l'on clique sur un bouton, le toggle va prendre l'icone du bouton actif, sinon celui du bouton "par défaut"
toggle.on('change:active', (evt) => {
if (evt.active && this.viewer.layerManager === null) {
this.viewer.layerManager = new LayerSwitcher({
...{
reordering: false,
collapsed: false,
},
...options,
})
this.viewer.layerManager.on('drawlist', (e) => {
const ui = e.layer.get(this.viewer.commonLayer.propertiesName.UI_LAYER)
if (ui?.rightIcon) {
const rightIcon = OlExtElement.create('I', {
className: ui.rightIcon,
})
e.li.querySelector('.ol-layerswitcher-buttons').appendChild(rightIcon)
}
})
this.viewer.layerManager.on('layer:visible', ({ layer }) => {
if (layer?.getVisible()) {
const group = this.viewer.commonLayer.getLayerGroup(layer)
if (group && !group.getVisible()) {
group.setVisible(true)
}
}
})
this.viewer.layerManager.tip = {
up: 'Réordonner',
down: 'Descendre',
info: 'Informations...',
extent: 'Zoom vers l\'étendue de la couche',
trash: 'Retirer le calque',
plus: 'Déplier / Replier',
}
this.viewer.Map.addControl(this.viewer.layerManager)
} else if (evt.active) {
// show et hide ne marchent pas
this.viewer.layerManager.element.classList.add('ol-forceopen')
this.viewer.layerManager.element.classList.remove('ol-collapsed')
this.viewer.layerManager.overflow()
} else {
this.viewer.layerManager.element.classList.remove('ol-forceopen')
this.viewer.layerManager.element.classList.add('ol-collapsed')
this.viewer.layerManager.overflow()
}
})
toggle.set('modal', true)
this.addControl(toggle)
}
ControlBar.prototype.addUnlockButton = function (options = { }) {
const storageKey = options.storageKey || 'KARTEIS_UNLOCK_TOKEN'
const btn = new Button({
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-unlock"></i>'),
name: 'kmapv-unlock-tool',
title: options?.button?.title || 'Se connecter',
handleClick: () => {
window.location.href = options.url + `?uriredirect=${encodeURIComponent(window.location.href)}&storageKey=${storageKey}`
},
})
this.addControl(btn)
}
ControlBar.prototype.addMeasureTool = function (options = { }) {
// bouton pour afficher les longueurs des segments, change l'état des deux interaction
const showSegmentToggle = new Toggle({
html: getButtonHtml(options?.buttons?.toggleSegment?.html, options?.buttons?.toggleSegment?.iconId, options?.buttons?.toggleSegment?.icon, '<i class="kmapv-icon kmapv-icon-simplify"></i>'),
title: options?.buttons?.toggleSegment?.title || 'Afficher/Masquer la longueur des segments',
onToggle: (active) => {
this.viewer.dataLayer._measureAreaInteraction.setSegmentVisible(active)
this.viewer.dataLayer._measureLineInteraction.setSegmentVisible(active)
onToggle()
},
})
const maintButton = new Toggle({
html: getButtonHtml(options?.buttons?.measure?.html, options?.buttons?.measure?.iconId, options?.buttons?.measure?.icon, '<i class="kmapv-icon kmapv-icon-measure"></i>'),
title: options?.buttons?.measure?.title || 'Outil de mesure',
onToggle: (active) => {
if (active) {
// a la re-ouverture, remet le bon état sur le toggle d'affichage de longeur des sgments
showSegmentToggle.setActive(this.viewer.dataLayer._measureAreaInteraction.getSegmentVisible())
}
},
})
// quand on clic dessus on ferme les autres sous-menu
maintButton.set('modal', true)
const onToggle = function (active) {
maintButton.toggle()
}
const subBar = new Bar({
// toggleOne: true,
autoDeactivate: true,
controls: [
new Button({
html: getButtonHtml(options?.buttons?.measureLine?.html, options?.buttons?.measureLine?.iconId, options?.buttons?.measureLine?.icon, '<i class="kmapv-icon kmapv-icon-measure-line"></i>'),
title: options?.buttons?.measureLine?.title || 'Mesurer une distance',
// autoActivate: true,
handleClick: () => {
this.viewer.dataLayer.changeMapMode('measureLine')
onToggle()
},
}),
new Button({
html: getButtonHtml(options?.buttons?.measureArea?.html, options?.buttons?.measureArea?.iconId, options?.buttons?.measureArea?.icon, '<i class="kmapv-icon kmapv-icon-measure-area"></i>'),
title: options?.buttons?.measureArea?.title || 'Mesurer une surface',
handleClick: () => {
this.viewer.dataLayer.changeMapMode('measureArea')
onToggle()
},
}),
new Button({
html: getButtonHtml(options?.buttons?.delete?.html, options?.buttons?.delete?.iconId, options?.buttons?.delete?.icon, '<i class="kmapv-icon kmapv-icon-delete"></i>'),
title: options?.buttons?.delete?.title || 'Effacer les mesures',
handleClick: () => {
this.viewer.dataLayer._measureAreaInteraction.clear()
this.viewer.dataLayer._measureLineInteraction.clear()
onToggle()
},
}),
new TextButton({
className: 'separator',
text: '',
}),
showSegmentToggle,
],
})
maintButton.setSubBar(subBar)
this.addControl(maintButton)
}
/** Bookmark positions on ol maps.
* @param {} options Geobookmark's options
* @param {string} options.className default ol-bookmark
* @param {string | undefined} options.title Title to use for the button tooltip, default "Geobookmarks"
* @param {string} options.placeholder input placeholder, default Add a new geomark...
* @param {string} [options.deleteTitle='Suppr.'] title for delete buttons
* @param {bool} options.editable enable modification, default true
* @param {string} options.namespace a namespace to save the boolmark (if more than one on a page), default ol
* @param {Array<any>} options.marks a list of default bookmarks:
*/
ControlBar.prototype.addBookMark = function (options = { }) {
const bookMark = new CustomGeoBookmark({ ...options, viewer: this.viewer })
this.addControl(bookMark)
}
ControlBar.prototype.addScaleManagerTool = function (options = { }) {
const zoomScaleResolutionTool = new ControlZoomScaleResolution({ ...options, viewer: this.viewer })
this.addControl(zoomScaleResolutionTool)
}
ControlBar.prototype.addLayerFilterTool = function (options = {}) {
if (this.viewer.layerFilter.layerFilterControl === null) {
this.viewer.layerFilter.layerFilterControl = new ControlLayerFilters({ viewer: this.viewer })
this.viewer.Map.addControl(this.viewer.layerFilter.layerFilterControl)
}
if (!options?.noButton) {
const toggle = new Toggle({
name: 'kmapv-layers-filters-bar',
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-filter"></i>'),
title: options?.button?.title || 'Afficher la gestion des filtres de carte',
})
// calque l'état du toggle sur l'état visible du gestionnaire de filtres
this.viewer.layerFilter.layerFilterControl.on('change:visible', (event) => {
toggle.setActive(event.visible)
})
// highlight du bouton si on a une filtre actif
this.viewer.layerFilterInteraction.on('change:visible', (event) => {
toggle.element.classList.toggle('ol-highlight', event.visible)
})
toggle.on('change:active', (evt) => {
if (evt.active) {
this.viewer.layerFilter.layerFilterControl.show()
} else {
this.viewer.layerFilter.layerFilterControl.hide()
}
})
toggle.set('modal', true)
this.addControl(toggle)
}
}
ControlBar.prototype.addLayerLegendTool = function (options = {}) {
const toggle = new Toggle({
name: 'kmapv-layers-legend-bar',
html: getButtonHtml(options?.button?.html, options?.button?.iconId, options?.button?.icon, '<i class="kmapv-icon kmapv-icon-map-legend"></i>'),
title: options?.button?.title || 'Afficher la légende',
})
// calque l'état du toggle sur l'état visible du gestionnaire de filtres
this.viewer.legendManager.on('change:visible', (event) => {
toggle.setActive(event.visible)
})
toggle.setActive(this.viewer.legendManager.isVisible())
toggle.on('change:active', (evt) => {
if (evt.active) {
this.viewer.legendManager.show()
} else {
this.viewer.legendManager.hide()
}
})
toggle.set('modal', true)
this.addControl(toggle)
}
export default ControlBar