@geogirafe/lib-geoportal 1.2.0-dev.2870319621 → 1.2.0-dev.2873796427

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/base/GirafeDraggableElement.js +2 -2
  2. package/base/GirafeResizableElement.js +4 -4
  3. package/components/basemap/component.js +1 -1
  4. package/components/cross-section/cross-section-settings/component.js +1 -1
  5. package/components/cross-section/scatterplot.js +1 -1
  6. package/components/drawing/component-mobile.js +5 -1
  7. package/components/drawing/component.js +8 -4
  8. package/components/drawing/fixed-dimension/component.js +1 -1
  9. package/components/edit/component.js +1 -1
  10. package/components/edit/editform/component.js +1 -1
  11. package/components/extlayers/component.js +1 -1
  12. package/components/map-2d/component.js +1 -1
  13. package/components/map-2d/tools/swipemanager.js +2 -2
  14. package/components/modals/component.js +1 -1
  15. package/components/print/component.js +7 -7
  16. package/components/print/tools/MFPLegendEncoder.js +1 -1
  17. package/components/querybuilder/component.js +2 -2
  18. package/components/scale/component.js +1 -1
  19. package/components/search/component.js +5 -1
  20. package/components/search-mobile/component.js +5 -1
  21. package/components/selectionwindow/component.js +1 -1
  22. package/components/share/component.js +1 -1
  23. package/components/themes/component.js +6 -1
  24. package/components/themes-mobile/layer-selected/component.js +1 -1
  25. package/components/timerestriction/timepicker/component.js +1 -1
  26. package/components/timerestriction/timeslider/component.js +4 -4
  27. package/components/treeview/tools/treeviewelement.d.ts +1 -2
  28. package/components/treeview/tools/treeviewelement.js +12 -12
  29. package/components/treeview/tools/treeviewfilter.js +3 -3
  30. package/components/treeview/tools/treeviewgroupelement.d.ts +2 -1
  31. package/components/treeview/tools/treeviewgroupelement.js +11 -2
  32. package/components/treeview/treeviewgroup/component.js +18 -19
  33. package/components/treeview/treeviewitem/component.d.ts +1 -1
  34. package/components/treeview/treeviewitem/component.js +27 -29
  35. package/components/treeview/treeviewroot/component.d.ts +2 -1
  36. package/components/treeview/treeviewroot/component.js +25 -4
  37. package/components/treeview/treeviewtheme/component.js +20 -16
  38. package/components/userpreferences/component.js +5 -1
  39. package/models/layers/grouplayer.js +1 -1
  40. package/models/layers/themelayer.js +1 -1
  41. package/models/xmlTypes.js +1 -1
  42. package/package.json +1 -1
  43. package/templates/iframe.html +4 -38
  44. package/templates/index.html +4 -38
  45. package/templates/public/about.json +1 -1
  46. package/templates/vite.config.js +1 -4
  47. package/tools/ordering/orderingmanager.d.ts +1 -0
  48. package/tools/ordering/orderingmanager.js +35 -8
  49. package/tools/resizewindow.js +6 -6
  50. package/tools/share/serializers/globeserializer.d.ts +4 -1
  51. package/tools/share/serializers/globeserializer.js +4 -1
  52. package/tools/state/brain/brain.d.ts +1 -0
  53. package/tools/state/brain/brain.js +30 -19
  54. package/tools/time/layertimeformatter.js +1 -1
@@ -112,10 +112,10 @@ class GirafeDraggableElement extends GirafeHTMLElement {
112
112
  const height = this.getContainerHeight();
113
113
  const left = _this.host.style.left;
114
114
  const top = _this.host.style.top;
115
- if (parseInt(left) + _this.host.offsetWidth > width) {
115
+ if (Number.parseInt(left) + _this.host.offsetWidth > width) {
116
116
  _this.host.style.left = width - _this.host.offsetWidth + 'px';
117
117
  }
118
- if (parseInt(top) + _this.host.offsetHeight > height) {
118
+ if (Number.parseInt(top) + _this.host.offsetHeight > height) {
119
119
  _this.host.style.top = height - _this.host.offsetHeight + 'px';
120
120
  }
121
121
  }
@@ -66,13 +66,13 @@ class GirafeResizableElement extends GirafeHTMLElement {
66
66
  // If there is a configured minWidth or maxWidth, we have to take care of it
67
67
  const css = getComputedStyle(this);
68
68
  const minWidth = Number.parseFloat(css.minWidth);
69
- this.minWidth = isNaN(minWidth) ? undefined : minWidth;
69
+ this.minWidth = Number.isNaN(minWidth) ? undefined : minWidth;
70
70
  const maxWidth = Number.parseFloat(css.maxWidth);
71
- this.maxWidth = isNaN(maxWidth) ? undefined : maxWidth;
71
+ this.maxWidth = Number.isNaN(maxWidth) ? undefined : maxWidth;
72
72
  const minHeight = Number.parseFloat(css.minHeight);
73
- this.minHeight = isNaN(minHeight) ? undefined : minHeight;
73
+ this.minHeight = Number.isNaN(minHeight) ? undefined : minHeight;
74
74
  const maxHeight = Number.parseFloat(css.maxHeight);
75
- this.maxHeight = isNaN(maxHeight) ? undefined : maxHeight;
75
+ this.maxHeight = Number.isNaN(maxHeight) ? undefined : maxHeight;
76
76
  }
77
77
  mousedown(e) {
78
78
  e.preventDefault();
@@ -13,7 +13,7 @@ class BasemapComponent extends GirafeHTMLElement {
13
13
  .basemap-button{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;box-shadow:var(--bx-shdw);border-width:2px;border-radius:4px;outline:0;margin:0;padding:5px;display:inline-flex}#container{flex-direction:column;width:max-content;display:inline-flex}.basemap-icon{background:var(--svg-legend-bkg);filter:var(--svg-map-filter)}.active-basemap{background-color:var(--bkg-color-grad2)!important}.opacity-slider{flex-direction:row;height:20px;padding:0 5px;display:flex}.opacity-slider img{height:16px;position:relative;top:2px}.opacity-slider input[type=range]{flex-grow:1}.basemap-container{flex-direction:column;display:flex}.basemap-container button{color:var(--text-color);background-color:#0000;border:none;flex-direction:row;flex-grow:1;display:flex}.basemap-container button img{height:2rem;margin:.3rem}.basemap-container button span{height:2rem;margin:.3rem;line-height:2rem}.basemap-container:hover{background-color:var(--bkg-color-grad1)}.basemaps-with-opacity-separator{border-top:1px solid var(--bkg-color-grad2);height:1px;margin:6px 8px}
14
14
  </style>
15
15
  <style>${this.customStyle}</style>
16
- <girafe-menu-button direction="up-right" id="basemap-menu-button"><button slot="menu-button" class="basemap-button" tip="Select basemap"><img class="basemap-icon" alt="menu-icon" src="images/button_basemaps.webp"></button><div slot="menu-content" id="container">${Object.values(this.state.basemaps).filter(basemap => basemap.opacity == -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button></div>`)}<div class="basemaps-with-opacity-separator"></div>${Object.values(this.state.basemaps).filter(basemap => basemap.opacity != -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button><div class="opacity-slider"><img alt="Control opacity" src="icons/opacity.svg"> <input type="range" min="0" max="1" step="0.01" class="gg-range" value="${basemap.opacity}" onkeydown="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onclick="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onchange="${(e) => this.changeBasemapOpacity(basemap, e)}"></div></div>`)}</div></girafe-menu-button>
16
+ <girafe-menu-button direction="up-right" id="basemap-menu-button"><button slot="menu-button" class="basemap-button" tip="Select basemap"><img class="basemap-icon" alt="menu-icon" src="images/button_basemaps.webp"></button><div slot="menu-content" id="container">${Object.values(this.state.basemaps).filter(basemap => basemap.opacity == -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button></div>`)}<div class="basemaps-with-opacity-separator"></div>${Object.values(this.state.basemaps).filter(basemap => basemap.opacity != -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button><div class="opacity-slider"><img alt="Control opacity" src="icons/opacity.svg"> <input type="range" aria-label="Opacity" min="0" max="1" step="0.01" class="gg-range" value="${basemap.opacity}" onkeydown="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onclick="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onchange="${(e) => this.changeBasemapOpacity(basemap, e)}"></div></div>`)}</div></girafe-menu-button>
17
17
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
18
18
  };
19
19
  constructor() {
@@ -23,7 +23,7 @@ class CrossSectionSettingsComponent extends GirafeHTMLElement {
23
23
  .hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
24
24
  </style>
25
25
  <style>${this.customStyle}</style>
26
- <div id="panel"><div id="content"><div class="btn-group-flex"><button id="draw-profile-btn" class="${this.crossSectionState.drawProfile ? 'gg-button active' : 'gg-button'}" tip="draw_profile_help" onclick="${() => this.toggleLineDraw()}" i18n="draw_profile">Draw</button> <button id="delete-profile-btn" class="gg-button" tip="delete_help" onclick="${() => this.deleteProfile()}" i18n="delete">Delete</button></div><div class="btn-group-flex"><label for="section-width-btn" i18n="profile_width" class="gg-label">Width [m]</label> <input id="section-width-btn" class="gg-input" type="number" value="${this.crossSectionState.sectionWidthSettings.value}" min="${this.crossSectionState.sectionWidthSettings.min}" max="${this.crossSectionState.sectionWidthSettings.max}" step="${this.crossSectionState.sectionWidthSettings.step}" onchange="${(e) => this.setSectionWidth(e.target.value)}"></div><div class="btn-group-flex"><button id="reset-zoom-btn" class="gg-button" tip="profile_reset_view_help" onclick="${() => this.resetZoom()}" i18n="profile_reset_view">Reset view</button> <button id="sync-views-btn" class="${this.crossSectionState.syncViews ? 'gg-button active' : 'gg-button'}" tip="profile_sync_view_help" onclick="${() => this.setViewSync(!this.crossSectionState.syncViews)}" i18n="profile_sync_view">Sync. views</button></div><div class="btn-group-flex"><button class="gg-icon-button gg-big" tip="profile_shift_up_help" onclick="${() => this.shiftLinestring([0.0, this.crossSectionState.linestringShift])}"><img src="icons/arrow_up.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_up_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_down_help" onclick="${() => this.shiftLinestring([0.0, -this.crossSectionState.linestringShift])}"><img src="icons/arrow_down.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_down_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_left_help" onclick="${() => this.shiftLinestring([-this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_left.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_left_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_right_help" onclick="${() => this.shiftLinestring([this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_right.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_right_help')}"></button></div><div class="btn-group-flex"><div class="cell"><label for="z-ratio-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_exaggeration')} (${this.crossSectionState.verticalExaggerationSettings.value})</label><div style="display: flex; align-items: center"><input id="z-ratio-btn" type="range" class="gg-range" min="${this.crossSectionState.verticalExaggerationSettings.min}" max="${this.crossSectionState.verticalExaggerationSettings.max}" step="${this.crossSectionState.verticalExaggerationSettings.step}" value="${this.crossSectionState.verticalExaggerationSettings.value}" oninput="${(e) => this.setVerticalExaggeration(parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="z-ratio-reset-btn" class="reset-btn" tip="profile_exaggeration_reset_help" onclick="${() => this.setVerticalExaggeration(this.crossSectionState.verticalExaggerationSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_exaggeration_reset_help')}"></button></div></div></div><div class="btn-group-flex"><div class="cell"><label for="point-size-label" class="gg-label">${this.context.i18nManager.getTranslation('profile_point_size')} (${this.crossSectionState.pointSizeSettings.value})</label><div style="display: flex; align-items: center"><input id="point-size-btn" type="range" class="gg-range" min="${this.crossSectionState.pointSizeSettings.min}" max="${this.crossSectionState.pointSizeSettings.max}" step="${this.crossSectionState.pointSizeSettings.step}" value="${this.crossSectionState.pointSizeSettings.value}" oninput="${(e) => this.setPointSize(parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="point-size-reset-btn" class="reset-btn" tip="profile_point_size_reset_help" onclick="${() => this.setPointSize(this.crossSectionState.pointSizeSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_point_size_reset_help')}"></button></div></div></div><div class="btn-group-flex"><label for="background-color-btn" i18n="profile_background_color" class="gg-label">Background color</label> <input id="background-color-btn" class="gg-input" type="color" value="${this.crossSectionState.backgroundColor}" oninput="${(e) => this.setBackgroundColor(e.target.value)}"></div><div class="btn-group-flex"><label for="sequential-color-btn" i18n="profile_colormap" class="gg-label">Colorscale</label> <select id="sequential-color-btn" class="gg-select" oninput="${(e) => this.setColorPalette(e.target.value)}"><option value="spectral" ?selected="${this.crossSectionState.colorPalette === 'spectral'}" i18n="palette_option_spectral">Spectral<option value="greys" ?selected="${this.crossSectionState.colorPalette === 'greys'}" i18n="palette_option_greys">Greys<option value="blues" ?selected="${this.crossSectionState.colorPalette === 'blues'}" i18n="palette_option_blues">Blues<option value="viridis" ?selected="${this.crossSectionState.colorPalette === 'viridis'}" i18n="palette_option_viridis">Viridis<option value="magma" ?selected="${this.crossSectionState.colorPalette === 'magma'}" i18n="palette_option_magma">Magma</select></div><div class="option"><label for="grid-btn" i18n="profile_toggle_grid" class="gg-label">Show grid</label> <input id="grid-btn" class="gg-checkbox" ?checked="${this.crossSectionState.gridVisible}" type="checkbox" onchange="${(e) => this.setGridVisibility(e.target.checked)}"></div><h3 i18n="profile_pointcloud">Pointclouds</h3><div class="btn-group-flex loader-progress"><div class="progress-wrapper" tip="profile_load_indicator_help"><progress id="load-progress" class="gg-progress" value="${this.crossSectionState.numberOfPoints}" max="${this.crossSectionState.maxNumberOfPoints}"></progress> <span class="progress-label">${(this.crossSectionState.loading) ? uHtml `<img src="icons/progress.svg" alt="Loading" class="gg-spin gg-small progress-icon">` : uHtml ``} ${this.crossSectionState.numberOfPoints} / ${this.crossSectionState.maxNumberOfPoints}</span></div></div><div>${this.crossSectionState.datasets.map(f => uHtml `<div class="dataset-row"><input type="checkbox" id="${f.id}" class="gg-checkbox" ?checked="${f.active}" onchange="${() => this.toggleVisibility(f.id)}"> <span class="dataset-name" i18n="${f.id}">${f.id}</span> <select class="gg-select" oninput="${(e) => this.setColorVariable(f.id, e.target.value)}"><option value="uniform" ?selected="${f.colorby === 'uniform'}" i18n="color_option_uniform">Uniform<option value="natural" ?selected="${f.colorby === 'natural'}" i18n="color_option_natural">Natural<option value="intensity" ?selected="${f.colorby === 'intensity'}" i18n="color_option_intensity">Intensity<option value="classification" ?selected="${f.colorby === 'classification'}" i18n="color_option_classification">Classification</select> <input id="uniform-color-btn" type="color" value="${f.color}" oninput="${(e) => this.setColor(f.id, e.target.value)}"></div>`)}</div><h3 i18n="profile_measure_and_annotate">Measurements and annotations</h3><div class="btn-group-flex"><button id="draw-measurements-btn" class="${this.crossSectionState.drawMeasurement ? 'gg-button active' : 'gg-button'}" tip="profile_measurement_help" onclick="${() => this.toggleMeasureDraw()}" i18n="profile_measurement" ?disabled="${!this.crossSectionState.enableMeasurement}">Measure</button> <button id="delete-measurements-btn" class="gg-button" tip="profile_delete_measurements_help" onclick="${() => this.deleteAllMeasurements()}" i18n="profile_delete_measurements">Delete all</button></div><div class="scrollable-table-container"><table id="measurements-table" class="scrollable-table"><thead><tr><th class="table-cell sticky-header" style="text-align: center"><th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_dist">DIST.<th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_slope">SLOPE.<th class="table-cell sticky-header" style="text-align: center"><tbody></table></div><div class="btn-group-flex"><button id="draw-markers-btn" class="${this.crossSectionState.drawMarker ? 'gg-button active' : 'gg-button'}" tip="profile_draw_markers_help" onclick="${() => this.toggleMarkerDraw()}" i18n="profile_draw_markers" ?disabled="${!this.crossSectionState.enableAnnotation}">Annotate</button> <button id="delete-markers-btn" class="gg-button" tip="profile_delete_markers_help" onclick="${() => this.deleteAllMarkers()}" i18n="profile_delete_markers">Delete all</button></div><div class="scrollable-table-container"><table id="markers-table" class="scrollable-table"><thead><tr><th class="sticky-header" style="text-align: center" i18n="profile_table_id">ID<th class="sticky-header" style="text-align: right" i18n="profile_table_coord">COORD.<th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><tbody></table></div><h3 i18n="profile_print_title">Print</h3><div class="btn-group-flex"><select id="print-profile-format-btn" class="gg-select" oninput="${(e) => this.setPrintFileFormat(e.target.value)}"><option value="svg" i18n="SVG">SVG</select> <button id="print-profile-btn" class="gg-button" tip="profile_print_help" onclick="${() => this.printPlot(this.crossSectionState.printFileFormat)}" i18n="profile_print">Print</button></div><h3 i18n="profile_download_title">Downloads</h3><div class="text-label" i18n="profile_markers_download">Markers</div><div class="btn-group-flex"><select id="download-markers-format-btn" class="gg-select" oninput="${(e) => this.setAnnotationsFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-markers-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature(this.points, 'markers', this.crossSectionState.downloadAnnotationsFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableAnnotationsDownload}">Download</button></div><div class="text-label" i18n="profile_linestring_download">Profile line</div><div class="btn-group-flex"><select id="download-linestring-format-btn" class="gg-select" oninput="${(e) => this.setLineFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-linestring-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature([this.linestring], 'linestring', this.crossSectionState.downloadLinestringFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableLinestringDownload}">Download</button></div></div></div>
26
+ <div id="panel"><div id="content"><div class="btn-group-flex"><button id="draw-profile-btn" class="${this.crossSectionState.drawProfile ? 'gg-button active' : 'gg-button'}" tip="draw_profile_help" onclick="${() => this.toggleLineDraw()}" i18n="draw_profile">Draw</button> <button id="delete-profile-btn" class="gg-button" tip="delete_help" onclick="${() => this.deleteProfile()}" i18n="delete">Delete</button></div><div class="btn-group-flex"><label for="section-width-btn" i18n="profile_width" class="gg-label">Width [m]</label> <input id="section-width-btn" class="gg-input" type="number" value="${this.crossSectionState.sectionWidthSettings.value}" min="${this.crossSectionState.sectionWidthSettings.min}" max="${this.crossSectionState.sectionWidthSettings.max}" step="${this.crossSectionState.sectionWidthSettings.step}" onchange="${(e) => this.setSectionWidth(e.target.value)}"></div><div class="btn-group-flex"><button id="reset-zoom-btn" class="gg-button" tip="profile_reset_view_help" onclick="${() => this.resetZoom()}" i18n="profile_reset_view">Reset view</button> <button id="sync-views-btn" class="${this.crossSectionState.syncViews ? 'gg-button active' : 'gg-button'}" tip="profile_sync_view_help" onclick="${() => this.setViewSync(!this.crossSectionState.syncViews)}" i18n="profile_sync_view">Sync. views</button></div><div class="btn-group-flex"><button class="gg-icon-button gg-big" tip="profile_shift_up_help" onclick="${() => this.shiftLinestring([0.0, this.crossSectionState.linestringShift])}"><img src="icons/arrow_up.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_up_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_down_help" onclick="${() => this.shiftLinestring([0.0, -this.crossSectionState.linestringShift])}"><img src="icons/arrow_down.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_down_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_left_help" onclick="${() => this.shiftLinestring([-this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_left.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_left_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_right_help" onclick="${() => this.shiftLinestring([this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_right.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_right_help')}"></button></div><div class="btn-group-flex"><div class="cell"><label for="z-ratio-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_exaggeration')} (${this.crossSectionState.verticalExaggerationSettings.value})</label><div style="display: flex; align-items: center"><input id="z-ratio-btn" type="range" class="gg-range" min="${this.crossSectionState.verticalExaggerationSettings.min}" max="${this.crossSectionState.verticalExaggerationSettings.max}" step="${this.crossSectionState.verticalExaggerationSettings.step}" value="${this.crossSectionState.verticalExaggerationSettings.value}" oninput="${(e) => this.setVerticalExaggeration(Number.parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="z-ratio-reset-btn" class="reset-btn" tip="profile_exaggeration_reset_help" onclick="${() => this.setVerticalExaggeration(this.crossSectionState.verticalExaggerationSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_exaggeration_reset_help')}"></button></div></div></div><div class="btn-group-flex"><div class="cell"><label for="point-size-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_point_size')} (${this.crossSectionState.pointSizeSettings.value})</label><div style="display: flex; align-items: center"><input id="point-size-btn" type="range" class="gg-range" min="${this.crossSectionState.pointSizeSettings.min}" max="${this.crossSectionState.pointSizeSettings.max}" step="${this.crossSectionState.pointSizeSettings.step}" value="${this.crossSectionState.pointSizeSettings.value}" oninput="${(e) => this.setPointSize(Number.parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="point-size-reset-btn" class="reset-btn" tip="profile_point_size_reset_help" onclick="${() => this.setPointSize(this.crossSectionState.pointSizeSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_point_size_reset_help')}"></button></div></div></div><div class="btn-group-flex"><label for="background-color-btn" i18n="profile_background_color" class="gg-label">Background color</label> <input id="background-color-btn" class="gg-input" type="color" value="${this.crossSectionState.backgroundColor}" oninput="${(e) => this.setBackgroundColor(e.target.value)}"></div><div class="btn-group-flex"><label for="sequential-color-btn" i18n="profile_colormap" class="gg-label">Colorscale</label> <select id="sequential-color-btn" class="gg-select" oninput="${(e) => this.setColorPalette(e.target.value)}"><option value="spectral" ?selected="${this.crossSectionState.colorPalette === 'spectral'}" i18n="palette_option_spectral">Spectral<option value="greys" ?selected="${this.crossSectionState.colorPalette === 'greys'}" i18n="palette_option_greys">Greys<option value="blues" ?selected="${this.crossSectionState.colorPalette === 'blues'}" i18n="palette_option_blues">Blues<option value="viridis" ?selected="${this.crossSectionState.colorPalette === 'viridis'}" i18n="palette_option_viridis">Viridis<option value="magma" ?selected="${this.crossSectionState.colorPalette === 'magma'}" i18n="palette_option_magma">Magma</select></div><div class="option"><label for="grid-btn" i18n="profile_toggle_grid" class="gg-label">Show grid</label> <input id="grid-btn" class="gg-checkbox" ?checked="${this.crossSectionState.gridVisible}" type="checkbox" onchange="${(e) => this.setGridVisibility(e.target.checked)}"></div><h3 i18n="profile_pointcloud">Pointclouds</h3><div class="btn-group-flex loader-progress"><div class="progress-wrapper" tip="profile_load_indicator_help"><progress id="load-progress" class="gg-progress" value="${this.crossSectionState.numberOfPoints}" max="${this.crossSectionState.maxNumberOfPoints}"></progress> <span class="progress-label">${(this.crossSectionState.loading) ? uHtml `<img src="icons/progress.svg" alt="Loading" class="gg-spin gg-small progress-icon">` : uHtml ``} ${this.crossSectionState.numberOfPoints} / ${this.crossSectionState.maxNumberOfPoints}</span></div></div><div>${this.crossSectionState.datasets.map(f => uHtml `<div class="dataset-row"><input type="checkbox" id="${f.id}" class="gg-checkbox" aria-label="Dataset ${f.id}" ?checked="${f.active}" onchange="${() => this.toggleVisibility(f.id)}"> <span class="dataset-name" i18n="${f.id}">${f.id}</span> <select class="gg-select" aria-label="Color variable" oninput="${(e) => this.setColorVariable(f.id, e.target.value)}"><option value="uniform" ?selected="${f.colorby === 'uniform'}" i18n="color_option_uniform">Uniform<option value="natural" ?selected="${f.colorby === 'natural'}" i18n="color_option_natural">Natural<option value="intensity" ?selected="${f.colorby === 'intensity'}" i18n="color_option_intensity">Intensity<option value="classification" ?selected="${f.colorby === 'classification'}" i18n="color_option_classification">Classification</select> <input id="uniform-color-btn" type="color" aria-label="Uniform color" value="${f.color}" oninput="${(e) => this.setColor(f.id, e.target.value)}"></div>`)}</div><h3 i18n="profile_measure_and_annotate">Measurements and annotations</h3><div class="btn-group-flex"><button id="draw-measurements-btn" class="${this.crossSectionState.drawMeasurement ? 'gg-button active' : 'gg-button'}" tip="profile_measurement_help" onclick="${() => this.toggleMeasureDraw()}" i18n="profile_measurement" ?disabled="${!this.crossSectionState.enableMeasurement}">Measure</button> <button id="delete-measurements-btn" class="gg-button" tip="profile_delete_measurements_help" onclick="${() => this.deleteAllMeasurements()}" i18n="profile_delete_measurements">Delete all</button></div><div class="scrollable-table-container"><table id="measurements-table" class="scrollable-table"><thead><tr><th class="table-cell sticky-header" style="text-align: center"><th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_dist">DIST.<th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_slope">SLOPE.<th class="table-cell sticky-header" style="text-align: center"><tbody></table></div><div class="btn-group-flex"><button id="draw-markers-btn" class="${this.crossSectionState.drawMarker ? 'gg-button active' : 'gg-button'}" tip="profile_draw_markers_help" onclick="${() => this.toggleMarkerDraw()}" i18n="profile_draw_markers" ?disabled="${!this.crossSectionState.enableAnnotation}">Annotate</button> <button id="delete-markers-btn" class="gg-button" tip="profile_delete_markers_help" onclick="${() => this.deleteAllMarkers()}" i18n="profile_delete_markers">Delete all</button></div><div class="scrollable-table-container"><table id="markers-table" class="scrollable-table"><thead><tr><th class="sticky-header" style="text-align: center" i18n="profile_table_id">ID<th class="sticky-header" style="text-align: right" i18n="profile_table_coord">COORD.<th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><tbody></table></div><h3 i18n="profile_print_title">Print</h3><div class="btn-group-flex"><select id="print-profile-format-btn" class="gg-select" aria-label="Print format" oninput="${(e) => this.setPrintFileFormat(e.target.value)}"><option value="svg" i18n="SVG">SVG</select> <button id="print-profile-btn" class="gg-button" tip="profile_print_help" onclick="${() => this.printPlot(this.crossSectionState.printFileFormat)}" i18n="profile_print">Print</button></div><h3 i18n="profile_download_title">Downloads</h3><div class="text-label" i18n="profile_markers_download">Markers</div><div class="btn-group-flex"><select id="download-markers-format-btn" class="gg-select" aria-label="Markers format" oninput="${(e) => this.setAnnotationsFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-markers-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature(this.points, 'markers', this.crossSectionState.downloadAnnotationsFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableAnnotationsDownload}">Download</button></div><div class="text-label" i18n="profile_linestring_download">Profile line</div><div class="btn-group-flex"><select id="download-linestring-format-btn" class="gg-select" aria-label="Profile line format" oninput="${(e) => this.setLineFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-linestring-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature([this.linestring], 'linestring', this.crossSectionState.downloadLinestringFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableLinestringDownload}">Download</button></div></div></div>
27
27
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
28
28
  };
29
29
  crossSectionState;
@@ -1028,7 +1028,7 @@ export class Scatterplot {
1028
1028
  }
1029
1029
  generateId(markers) {
1030
1030
  let id = 1;
1031
- const existingIds = new Set(markers.map((marker) => parseInt(marker.label)));
1031
+ const existingIds = new Set(markers.map((marker) => Number.parseInt(marker.label)));
1032
1032
  while (existingIds.has(id)) {
1033
1033
  id++;
1034
1034
  }
@@ -7,6 +7,10 @@ export default class DrawingComponentMobile extends DrawingComponent {
7
7
  styleUrls = null;
8
8
  template = () => {
9
9
  return uHtml `<style>
10
+ .picker_wrapper.no_alpha .picker_alpha{display:none}.picker_wrapper.no_editor .picker_editor{z-index:-1;opacity:0;position:absolute}.picker_wrapper.no_cancel .picker_cancel{display:none}.layout_default.picker_wrapper{flex-flow:wrap;justify-content:space-between;align-items:stretch;width:25em;padding:.5em;font-size:10px;display:flex}.layout_default.picker_wrapper input,.layout_default.picker_wrapper button{font-size:1rem}.layout_default.picker_wrapper>*{margin:.5em}.layout_default.picker_wrapper:before{content:"";order:1;width:100%;height:0;display:block}.layout_default .picker_slider,.layout_default .picker_selector{padding:1em}.layout_default .picker_hue{width:100%}.layout_default .picker_sl{flex:auto}.layout_default .picker_sl:before{content:"";padding-bottom:100%;display:block}.layout_default .picker_editor{order:1;width:6.5rem}.layout_default .picker_editor input{width:100%;height:100%}.layout_default .picker_sample{flex:auto;order:1}.layout_default .picker_done,.layout_default .picker_cancel{order:1}.picker_wrapper{box-sizing:border-box;cursor:default;color:#444;pointer-events:auto;background:#f2f2f2;font-family:sans-serif;box-shadow:0 0 0 1px silver}.picker_wrapper:focus{outline:none}.picker_wrapper button,.picker_wrapper input{box-sizing:border-box;border:none;outline:none;box-shadow:0 0 0 1px silver}.picker_wrapper button:focus,.picker_wrapper button:active,.picker_wrapper input:focus,.picker_wrapper input:active{box-shadow:0 0 2px 1px #1e90ff}.picker_wrapper button{cursor:pointer;background-color:#f5f5f5;background-image:linear-gradient(#0000,#dcdcdc);padding:.4em .6em}.picker_wrapper button:active{background-image:linear-gradient(#dcdcdc,#0000)}.picker_wrapper button:hover{background-color:#fff}.picker_selector{z-index:1;cursor:pointer;background:currentColor;border:2px solid #fff;border-radius:100%;display:block;position:absolute;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);box-shadow:0 0 3px 1px #67b9ff}.picker_slider .picker_selector{border-radius:2px}.picker_hue{background-image:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red);position:relative;box-shadow:0 0 0 1px silver}.picker_sl{background-image:linear-gradient(#fff,#fff0 50%),linear-gradient(#0000 50%,#000),linear-gradient(90deg,gray,#80808000);position:relative;box-shadow:0 0 0 1px silver}.picker_alpha,.picker_sample{background:linear-gradient(45deg,#d3d3d3 25%,#0000 25% 75%,#d3d3d3 75%) 0 0/2em 2em,linear-gradient(45deg,#d3d3d3 25%,#fff 25% 75%,#d3d3d3 75%) 1em 1em/2em 2em;position:relative;box-shadow:0 0 0 1px silver}.picker_alpha .picker_selector,.picker_sample .picker_selector{background:0 0}.picker_editor input{padding:.2em .4em;font-family:monospace}.picker_sample:before{content:"";background:currentColor;width:100%;height:100%;display:block;position:absolute}.picker_arrow{z-index:-1;position:absolute}.picker_wrapper.popup{z-index:2;margin:1.5em;position:absolute}.picker_wrapper.popup,.picker_wrapper.popup .picker_arrow:before,.picker_wrapper.popup .picker_arrow:after{background:#f2f2f2;box-shadow:0 0 10px 1px #0006}.picker_wrapper.popup .picker_arrow{width:3em;height:3em;margin:0}.picker_wrapper.popup .picker_arrow:before,.picker_wrapper.popup .picker_arrow:after{content:"";z-index:-99;display:block;position:absolute;top:0;left:0}.picker_wrapper.popup .picker_arrow:before{-webkit-transform-origin:0 100%;transform-origin:0 100%;width:100%;height:100%;-webkit-transform:skew(45deg);transform:skew(45deg)}.picker_wrapper.popup .picker_arrow:after{width:150%;height:150%;box-shadow:none}.popup.popup_top{bottom:100%;left:0}.popup.popup_top .picker_arrow{bottom:0;left:0;-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.popup.popup_bottom{top:100%;left:0}.popup.popup_bottom .picker_arrow{top:0;left:0;-webkit-transform:rotate(90deg)scaleY(-1);transform:rotate(90deg)scaleY(-1)}.popup.popup_left{top:0;right:100%}.popup.popup_left .picker_arrow{top:0;right:0;-webkit-transform:scaleX(-1);transform:scaleX(-1)}.popup.popup_right{top:0;left:100%}.popup.popup_right .picker_arrow{top:0;left:0}
11
+ </style><style>
12
+ .picker_wrapper,.picker_arrow:after,.picker_arrow:before{background-color:var(--bkg-color)!important}.picker_wrapper,.picker_arrow:before{box-shadow:0 0 10px 1px var(--text-color-grad1)!important}.picker_wrapper.fixedPosition{transform:translate(-260px)}.picker_arrow.fixedPosition{transform:translate(200px)rotate(90deg)scaleX(-1)!important}
13
+ </style><style>
10
14
  .hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
11
15
  </style><style>
12
16
  input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var(--bkg-color-input);padding-right:0}input:focus{border:1px solid var(--lt-color-gray-900)}button{border:solid 1px var(--bkg-color);color:var(--text-color);background-color:var(--bkg-color);cursor:pointer;padding:0}button:hover{border:solid 1px var(--text-color-grad2)}button.selected{border:solid 1px var(--text-color-grad2);background-color:var(--bkg-color-grad1);color:var(--bkg-color)}#toolbar{flex-wrap:wrap;display:flex}.label-container{flex-grow:1}.text-end{text-align:end}.icon{width:1.2rem;height:1.2rem;fill:var(--text-color);flex-shrink:0;margin:3px}.icon:hover{fill:var(--text-color-grad2)}.gg-icon-button:hover{border:none}.colorPicker{border:1px solid var(--text-color);border-radius:5px}.picker_wrapper{transform:translate(-250px)}.picker_arrow{transform:translate(200px)rotate(90deg)scaleX(-1)!important}.picker_wrapper,.picker_arrow:after,.picker_arrow:before{background-color:var(--bkg-color)!important}.picker_wrapper,.picker_arrow:before{box-shadow:0 0 10px 1px var(--text-color-grad1)!important}button:disabled,input:disabled,.disabled{pointer-events:none;opacity:.5}fieldset.field-wrapper{border:0;margin:0;padding:0}#panel{height:100%;color:var(--text-color);flex-direction:column;display:flex}#panel>div{padding:1rem}#toolParametersContainer{& .title{margin-top:.5rem;margin-bottom:.75rem;display:inline-block}}.toolParameters{flex-direction:column;justify-content:left;row-gap:.25rem;display:flex}.toolParameters>label{padding:0 5px}#drawingListContainer{flex-grow:1;overflow:hidden auto;padding-top:0!important;& .titleContainer{margin-bottom:1rem;display:flex;& .title{flex-grow:1;align-items:center;display:flex}}}#drawingList{flex-flow:column;gap:.15rem;display:flex}#drawingList .girafe{border:solid 1px var(--text-color);flex-wrap:wrap;align-items:center;padding:.3rem;display:flex;position:relative}#drawingList .girafe span{flex-grow:1;padding-left:5px}#options{box-shadow:0px -2px 3px -1px var(--text-color-grad1);z-index:100;flex-direction:column;display:flex;position:relative}#optionsTitle{text-align:center;margin-bottom:20px;font-size:1.2rem}#options hr{width:100%;margin:8px 0}#optionsTextLines,#optionsColorLine,#optionsLineLines{align-items:center;display:grid}#optionsText{margin:auto}#optionsTextLines{grid-template-columns:.825fr 2.5fr 1fr 4em .5fr .5fr}#optionsTextLines button:hover{border:none}#optionsColor,#optionsLine,#optionsExport,#optionsArrow{margin:auto}#optionsColorLine{display:flex}#optionsColorLine>div{align-items:center;width:100%;display:flex}#optionsLineLines,#optionsArrowStyle{grid-template-columns:3fr 4em 1fr auto}#optionsExportLine{grid-template-columns:60px 60px 45px 45px;gap:.2rem;display:flex}span.label{padding-left:.5rem;padding-right:.5rem;&.first{padding-left:0}}span.unit{padding-left:.5rem}
@@ -14,7 +18,7 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
14
18
  button.selected{background-color:#daebff!important;border:1px solid #54a4ff!important}#toolbar{box-sizing:border-box;grid-template-columns:repeat(5,1fr);gap:20px;width:100%;display:grid}#toolbar>button{box-sizing:border-box;filter:drop-shadow(0 4px 7px #0004382c);background-color:#fff;border-radius:8px;padding:10px}#toolbar>button>img{opacity:.7;width:100%}.icon{width:1.5rem;height:1.5rem}.gg-icon-button:hover{background-color:#0000}#panel{font-size:1.5em}#drawingList{gap:10px}#drawingList .girafe{filter:drop-shadow(0 4px 7px #0004381c);background:#fff;border:none;border-radius:8px;padding:10px}#optionsTitle{text-align:center;filter:drop-shadow(0 4px 7px #0004381c);color:#4553ff;border-radius:8px;width:100%;margin-bottom:20px;padding:10px;font-size:1.6rem}.gg-input:hover{filter:drop-shadow(0 4px 7px #4c58ff70);background-color:#fff}#optionsColorLine{flex-direction:column;display:flex}#optionsColorLine>div{text-align:end;width:100%}.selectable-label{font-size:1.3em}#optionsNameFontSize,#optionsMeasuresFontSize,#optionsStrokeWidth,#line-style,#arrow-style,#arrow-position{text-align:right;border:1px solid #e3e3e3;padding:1px;font-size:1em}.popup.popup_top{translate:15px -15px}#optionsExportLine{display:none}
15
19
  </style>
16
20
  <style>${this.customStyle}</style>
17
- <link rel="stylesheet" href="lib/vanilla-picker/vanilla-picker.csp.css"><link rel="stylesheet" href="styles/girafecolorpicker.css"><div id="panel"><div><div id="toolbar"><button id="disable" tip="Disable drawing" class="gg-icon-button gg-medium"><img alt="select icon" src="icons/arrow.svg"></button> <button id="point" tip="Point" class="gg-icon-button gg-medium"><img alt="point icon" src="icons/point.svg"></button> <button id="line" tip="Line" class="gg-icon-button gg-medium"><img alt="polyline icon" src="icons/polyline.svg"></button> <button id="polygon" tip="Polygon" class="gg-icon-button gg-medium"><img alt="polygon icon" src="icons/polygon.svg"></button> <button id="square" tip="Square" class="gg-icon-button gg-medium"><img alt="square icon" src="icons/square.svg"></button> <button id="rectangle" tip="Rectangle" class="gg-icon-button gg-medium"><img alt="rectangle icon" src="icons/rectangle.svg"></button> <button id="circle" tip="Circle" class="gg-icon-button gg-medium"><img alt="circle icon" src="icons/circle.svg"></button> <button id="freeline" tip="Freehand line" class="gg-icon-button gg-medium"><img alt="polyline-free icon" src="icons/polyline-free.svg"></button> <button id="freepolygon" tip="Freehand polygon" class="gg-icon-button gg-medium"><img alt="polygon-free icon" src="icons/polygon-free.svg"></button> <button id="text" tip="Text" class="gg-icon-button gg-medium"><img alt="text icon" src="icons/text-font.svg"></button></div><div id="toolParametersContainer"><span i18n="Settings" class="title"></span><div class="toolParameters" data-tool="Polyline,Polygon"><girafe-fixed-dimension dimensionname="length" dimension="length" id="fixedLineLength" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Square"><girafe-fixed-dimension dimensionname="side length" dimension="side" id="fixedSquareSide" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Rectangle"><girafe-fixed-dimension dimensionname="width" dimension="width" id="fixedRectangleWidth" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension><girafe-fixed-dimension dimensionname="height" dimension="height" id="fixedRectangleHeight" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Text"><label class="gg-label" for="drawingText" i18n="Text to draw">Text to draw</label> <input id="drawingText" class="gg-input" value="${this.drawingText}" oninput="${(e) => this.drawingTextChangedHandler(e)}"></div></div></div><div id="drawingListContainer"><div class="titleContainer"><span i18n="Drawing List" class="title"></span> <button class="gg-icon-button icon" tip="Delete all shapes" onclick="${() => this.deleteAllFeatures()}" ?disabled="${this.drawingState.features.length === 0}">${this.htmlUnsafe(this.trashIcon)}</button></div><div id="drawingList">${this.drawingState.features.map(feature => uHtmlFor(feature, feature.id) `<div id="${'f-' + feature.id}" class="girafe"><button id="${'f-select-' + feature.id}" class="gg-icon-button gg-small" tip="Select to change appearance" onclick="${() => this.onToggleFeatureSelection(feature)}"><div class="icon">${this.htmlUnsafe(feature.selected ? this.checkedIcon : this.noCheckedIcon)}</div></button><div class="label-container"><button class="${feature.selected ? 'selectable-label gg-icon-button gg-small gg-selected' : 'selectable-label gg-icon-button gg-small gg-opacity'}" onclick="${() => this.onToggleFeatureSelection(feature)}"><span id="${'f-name-' + feature.id}">${feature.name}</span></button></div><button class="gg-icon-button icon" tip="Center on shape" onclick="${() => this.olDrawing.centerViewOnFeature(feature)}">${this.htmlUnsafe(this.locateIcon)}</button> <button class="gg-icon-button icon" tip="Delete shape" onclick="${() => this.deleteFeature(feature)}">${this.htmlUnsafe(this.trashIcon)}</button></div>`)}</div></div><div id="options" class="${this.selectedFeatures.length > 0 ? '' : 'disabled'}"><fieldset class="field-wrapper" disabled="${this.selectedFeatures.length <= 0}"><input id="optionsTitle" value="${this.getOptionsTitle()}" class="gg-input" disabled="${this.selectedFeatures.length > 1}"><div id="optionsText"><div id="optionsTextLines"><span class="label first" i18n="Name">Name</span> <button class="gg-icon-button icon" id="visibleIconName" tip="Show or hide shape name" onclick="${() => this.toggleNameVisibility()}">${this.htmlUnsafe(this.isDisplayNameEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span class="label" i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span class="unit">pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span class="${this.isMeasureInformationEnabled() ? 'label first' : 'label first disabled'}" i18n="Measures">Measures</span> <select id="measure-information" class="gg-select" tip="${this.measureInformationTooltip}" disabled="${!this.isMeasureInformationEnabled()}" onchange="${() => this.onOptionsChange()}">${Object.entries(this.measureInformations).map((entry) => uHtml `<option selected="${this.selectedFeatureMeasureInformation === entry[0]}" value="${entry[0]}"><span i18n="${entry[1]}">${entry[0]}</span></option>`)}</select> <span class="${this.isMeasureInformationEnabled() ? 'label' : 'label disabled'}" i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" disabled="${!this.isMeasureInformationEnabled()}" oninput="${() => this.onOptionsChange()}"> <span class="${this.isMeasureInformationEnabled() ? 'unit' : 'unit disabled'}">pt</span> <button class="icon colorPicker" id="measureColorPicker" disabled="${!this.isMeasureInformationEnabled()}"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="${this.isStrokeColorEnabled() ? 'text-end' : 'text-end disabled'}" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" disabled="${!this.isStrokeColorEnabled()}" id="strokePicker"></button></div><div><span class="${this.isFillColorEnabled() ? 'text-end' : 'text-end disabled'}" id="fillPickerSpan" i18n="Fill color">Fill color</span> <button class="icon colorPicker" disabled="${!this.isFillColorEnabled()}" id="fillPicker"></button></div></div></div><hr><div id="optionsLine"><div class="${this.isLineStyleEnabled() ? '' : 'disabled'}" id="optionsLineLines"><span i18n="Line width">Line width</span> <input id="optionsStrokeWidth" type="number" class="gg-input" min="1" value="${this.selectedFeatures[0]?.strokeWidth}" oninput="${() => this.onOptionsChange()}"> <span class="unit">px</span> <select id="line-style" class="gg-select" onchange="${() => this.onOptionsChange()}">${Object.entries(this.lineStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.lineStroke === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsArrow"><div class="${this.isLineArrowEnabled() ? '' : 'disabled'}" id="optionsArrowStyles"><span i18n="Arrows style">Arrows style</span> <select id="arrow-style" class="gg-select" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowStyle === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select> <select id="arrow-position" class="gg-select" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowPositions).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowPosition === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsExport"><div id="optionsExportLine"><label for="export" class="gg-label" i18n="Export">Export</label> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('geojson')}">GeoJson</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('kml')}">KML</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('gpx')}">GPX</button></div></div></fieldset></div></div>
21
+ <div id="panel"><div><div id="toolbar"><button id="disable" tip="Disable drawing" class="gg-icon-button gg-medium"><img alt="select icon" src="icons/arrow.svg"></button> <button id="point" tip="Point" class="gg-icon-button gg-medium"><img alt="point icon" src="icons/point.svg"></button> <button id="line" tip="Line" class="gg-icon-button gg-medium"><img alt="polyline icon" src="icons/polyline.svg"></button> <button id="polygon" tip="Polygon" class="gg-icon-button gg-medium"><img alt="polygon icon" src="icons/polygon.svg"></button> <button id="square" tip="Square" class="gg-icon-button gg-medium"><img alt="square icon" src="icons/square.svg"></button> <button id="rectangle" tip="Rectangle" class="gg-icon-button gg-medium"><img alt="rectangle icon" src="icons/rectangle.svg"></button> <button id="circle" tip="Circle" class="gg-icon-button gg-medium"><img alt="circle icon" src="icons/circle.svg"></button> <button id="freeline" tip="Freehand line" class="gg-icon-button gg-medium"><img alt="polyline-free icon" src="icons/polyline-free.svg"></button> <button id="freepolygon" tip="Freehand polygon" class="gg-icon-button gg-medium"><img alt="polygon-free icon" src="icons/polygon-free.svg"></button> <button id="text" tip="Text" class="gg-icon-button gg-medium"><img alt="text icon" src="icons/text-font.svg"></button></div><div id="toolParametersContainer"><span i18n="Settings" class="title"></span><div class="toolParameters" data-tool="Polyline,Polygon"><girafe-fixed-dimension dimensionname="length" dimension="length" id="fixedLineLength" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Square"><girafe-fixed-dimension dimensionname="side length" dimension="side" id="fixedSquareSide" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Rectangle"><girafe-fixed-dimension dimensionname="width" dimension="width" id="fixedRectangleWidth" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension><girafe-fixed-dimension dimensionname="height" dimension="height" id="fixedRectangleHeight" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Text"><label class="gg-label" for="drawingText" i18n="Text to draw">Text to draw</label> <input id="drawingText" class="gg-input" value="${this.drawingText}" oninput="${(e) => this.drawingTextChangedHandler(e)}"></div></div></div><div id="drawingListContainer"><div class="titleContainer"><span i18n="Drawing List" class="title"></span> <button class="gg-icon-button icon" tip="Delete all shapes" onclick="${() => this.deleteAllFeatures()}" ?disabled="${this.drawingState.features.length === 0}">${this.htmlUnsafe(this.trashIcon)}</button></div><div id="drawingList">${this.drawingState.features.map(feature => uHtmlFor(feature, feature.id) `<div id="${'f-' + feature.id}" class="girafe"><button id="${'f-select-' + feature.id}" class="gg-icon-button gg-small" tip="Select to change appearance" onclick="${() => this.onToggleFeatureSelection(feature)}"><div class="icon">${this.htmlUnsafe(feature.selected ? this.checkedIcon : this.noCheckedIcon)}</div></button><div class="label-container"><button class="${feature.selected ? 'selectable-label gg-icon-button gg-small gg-selected' : 'selectable-label gg-icon-button gg-small gg-opacity'}" onclick="${() => this.onToggleFeatureSelection(feature)}"><span id="${'f-name-' + feature.id}">${feature.name}</span></button></div><button class="gg-icon-button icon" tip="Center on shape" onclick="${() => this.olDrawing.centerViewOnFeature(feature)}">${this.htmlUnsafe(this.locateIcon)}</button> <button class="gg-icon-button icon" tip="Delete shape" onclick="${() => this.deleteFeature(feature)}">${this.htmlUnsafe(this.trashIcon)}</button></div>`)}</div></div><div id="options" class="${this.selectedFeatures.length > 0 ? '' : 'disabled'}"><fieldset class="field-wrapper" disabled="${this.selectedFeatures.length <= 0}"><input id="optionsTitle" aria-label="Title" value="${this.getOptionsTitle()}" class="gg-input" disabled="${this.selectedFeatures.length > 1}"><div id="optionsText"><div id="optionsTextLines"><span class="label first" i18n="Name">Name</span> <button class="gg-icon-button icon" id="visibleIconName" tip="Show or hide shape name" onclick="${() => this.toggleNameVisibility()}">${this.htmlUnsafe(this.isDisplayNameEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span class="label" i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" aria-label="Name font size" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span class="unit">pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span class="${this.isMeasureInformationEnabled() ? 'label first' : 'label first disabled'}" i18n="Measures">Measures</span> <select id="measure-information" class="gg-select" aria-label="Measures information" tip="${this.measureInformationTooltip}" disabled="${!this.isMeasureInformationEnabled()}" onchange="${() => this.onOptionsChange()}">${Object.entries(this.measureInformations).map((entry) => uHtml `<option selected="${this.selectedFeatureMeasureInformation === entry[0]}" value="${entry[0]}"><span i18n="${entry[1]}">${entry[0]}</span></option>`)}</select> <span class="${this.isMeasureInformationEnabled() ? 'label' : 'label disabled'}" i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" aria-label="Measures font size" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" disabled="${!this.isMeasureInformationEnabled()}" oninput="${() => this.onOptionsChange()}"> <span class="${this.isMeasureInformationEnabled() ? 'unit' : 'unit disabled'}">pt</span> <button class="icon colorPicker" id="measureColorPicker" disabled="${!this.isMeasureInformationEnabled()}"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="${this.isStrokeColorEnabled() ? 'text-end' : 'text-end disabled'}" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" disabled="${!this.isStrokeColorEnabled()}" id="strokePicker"></button></div><div><span class="${this.isFillColorEnabled() ? 'text-end' : 'text-end disabled'}" id="fillPickerSpan" i18n="Fill color">Fill color</span> <button class="icon colorPicker" disabled="${!this.isFillColorEnabled()}" id="fillPicker"></button></div></div></div><hr><div id="optionsLine"><div class="${this.isLineStyleEnabled() ? '' : 'disabled'}" id="optionsLineLines"><span i18n="Line width">Line width</span> <input id="optionsStrokeWidth" type="number" aria-label="Line width" class="gg-input" min="1" value="${this.selectedFeatures[0]?.strokeWidth}" oninput="${() => this.onOptionsChange()}"> <span class="unit">px</span> <select id="line-style" class="gg-select" aria-label="Line style" onchange="${() => this.onOptionsChange()}">${Object.entries(this.lineStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.lineStroke === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsArrow"><div class="${this.isLineArrowEnabled() ? '' : 'disabled'}" id="optionsArrowStyles"><span i18n="Arrows style">Arrows style</span> <select id="arrow-style" class="gg-select" aria-label="Arrows style" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowStyle === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select> <select id="arrow-position" class="gg-select" aria-label="Arrow position" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowPositions).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowPosition === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsExport"><div id="optionsExportLine"><label for="export" class="gg-label" i18n="Export">Export</label> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('geojson')}">GeoJson</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('kml')}">KML</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('gpx')}">GPX</button></div></div></fieldset></div></div>
18
22
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
19
23
  };
20
24
  constructor() {
@@ -32,12 +32,16 @@ export default class DrawingComponent extends GirafeHTMLElement {
32
32
  styleUrls = null;
33
33
  template = () => {
34
34
  return uHtml `<style>
35
+ .picker_wrapper.no_alpha .picker_alpha{display:none}.picker_wrapper.no_editor .picker_editor{z-index:-1;opacity:0;position:absolute}.picker_wrapper.no_cancel .picker_cancel{display:none}.layout_default.picker_wrapper{flex-flow:wrap;justify-content:space-between;align-items:stretch;width:25em;padding:.5em;font-size:10px;display:flex}.layout_default.picker_wrapper input,.layout_default.picker_wrapper button{font-size:1rem}.layout_default.picker_wrapper>*{margin:.5em}.layout_default.picker_wrapper:before{content:"";order:1;width:100%;height:0;display:block}.layout_default .picker_slider,.layout_default .picker_selector{padding:1em}.layout_default .picker_hue{width:100%}.layout_default .picker_sl{flex:auto}.layout_default .picker_sl:before{content:"";padding-bottom:100%;display:block}.layout_default .picker_editor{order:1;width:6.5rem}.layout_default .picker_editor input{width:100%;height:100%}.layout_default .picker_sample{flex:auto;order:1}.layout_default .picker_done,.layout_default .picker_cancel{order:1}.picker_wrapper{box-sizing:border-box;cursor:default;color:#444;pointer-events:auto;background:#f2f2f2;font-family:sans-serif;box-shadow:0 0 0 1px silver}.picker_wrapper:focus{outline:none}.picker_wrapper button,.picker_wrapper input{box-sizing:border-box;border:none;outline:none;box-shadow:0 0 0 1px silver}.picker_wrapper button:focus,.picker_wrapper button:active,.picker_wrapper input:focus,.picker_wrapper input:active{box-shadow:0 0 2px 1px #1e90ff}.picker_wrapper button{cursor:pointer;background-color:#f5f5f5;background-image:linear-gradient(#0000,#dcdcdc);padding:.4em .6em}.picker_wrapper button:active{background-image:linear-gradient(#dcdcdc,#0000)}.picker_wrapper button:hover{background-color:#fff}.picker_selector{z-index:1;cursor:pointer;background:currentColor;border:2px solid #fff;border-radius:100%;display:block;position:absolute;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);box-shadow:0 0 3px 1px #67b9ff}.picker_slider .picker_selector{border-radius:2px}.picker_hue{background-image:linear-gradient(90deg,red,#ff0,#0f0,#0ff,#00f,#f0f,red);position:relative;box-shadow:0 0 0 1px silver}.picker_sl{background-image:linear-gradient(#fff,#fff0 50%),linear-gradient(#0000 50%,#000),linear-gradient(90deg,gray,#80808000);position:relative;box-shadow:0 0 0 1px silver}.picker_alpha,.picker_sample{background:linear-gradient(45deg,#d3d3d3 25%,#0000 25% 75%,#d3d3d3 75%) 0 0/2em 2em,linear-gradient(45deg,#d3d3d3 25%,#fff 25% 75%,#d3d3d3 75%) 1em 1em/2em 2em;position:relative;box-shadow:0 0 0 1px silver}.picker_alpha .picker_selector,.picker_sample .picker_selector{background:0 0}.picker_editor input{padding:.2em .4em;font-family:monospace}.picker_sample:before{content:"";background:currentColor;width:100%;height:100%;display:block;position:absolute}.picker_arrow{z-index:-1;position:absolute}.picker_wrapper.popup{z-index:2;margin:1.5em;position:absolute}.picker_wrapper.popup,.picker_wrapper.popup .picker_arrow:before,.picker_wrapper.popup .picker_arrow:after{background:#f2f2f2;box-shadow:0 0 10px 1px #0006}.picker_wrapper.popup .picker_arrow{width:3em;height:3em;margin:0}.picker_wrapper.popup .picker_arrow:before,.picker_wrapper.popup .picker_arrow:after{content:"";z-index:-99;display:block;position:absolute;top:0;left:0}.picker_wrapper.popup .picker_arrow:before{-webkit-transform-origin:0 100%;transform-origin:0 100%;width:100%;height:100%;-webkit-transform:skew(45deg);transform:skew(45deg)}.picker_wrapper.popup .picker_arrow:after{width:150%;height:150%;box-shadow:none}.popup.popup_top{bottom:100%;left:0}.popup.popup_top .picker_arrow{bottom:0;left:0;-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.popup.popup_bottom{top:100%;left:0}.popup.popup_bottom .picker_arrow{top:0;left:0;-webkit-transform:rotate(90deg)scaleY(-1);transform:rotate(90deg)scaleY(-1)}.popup.popup_left{top:0;right:100%}.popup.popup_left .picker_arrow{top:0;right:0;-webkit-transform:scaleX(-1);transform:scaleX(-1)}.popup.popup_right{top:0;left:100%}.popup.popup_right .picker_arrow{top:0;left:0}
36
+ </style><style>
37
+ .picker_wrapper,.picker_arrow:after,.picker_arrow:before{background-color:var(--bkg-color)!important}.picker_wrapper,.picker_arrow:before{box-shadow:0 0 10px 1px var(--text-color-grad1)!important}.picker_wrapper.fixedPosition{transform:translate(-260px)}.picker_arrow.fixedPosition{transform:translate(200px)rotate(90deg)scaleX(-1)!important}
38
+ </style><style>
35
39
  .hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
36
40
  </style><style>
37
41
  input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var(--bkg-color-input);padding-right:0}input:focus{border:1px solid var(--lt-color-gray-900)}button{border:solid 1px var(--bkg-color);color:var(--text-color);background-color:var(--bkg-color);cursor:pointer;padding:0}button:hover{border:solid 1px var(--text-color-grad2)}button.selected{border:solid 1px var(--text-color-grad2);background-color:var(--bkg-color-grad1);color:var(--bkg-color)}#toolbar{flex-wrap:wrap;display:flex}.label-container{flex-grow:1}.text-end{text-align:end}.icon{width:1.2rem;height:1.2rem;fill:var(--text-color);flex-shrink:0;margin:3px}.icon:hover{fill:var(--text-color-grad2)}.gg-icon-button:hover{border:none}.colorPicker{border:1px solid var(--text-color);border-radius:5px}.picker_wrapper{transform:translate(-250px)}.picker_arrow{transform:translate(200px)rotate(90deg)scaleX(-1)!important}.picker_wrapper,.picker_arrow:after,.picker_arrow:before{background-color:var(--bkg-color)!important}.picker_wrapper,.picker_arrow:before{box-shadow:0 0 10px 1px var(--text-color-grad1)!important}button:disabled,input:disabled,.disabled{pointer-events:none;opacity:.5}fieldset.field-wrapper{border:0;margin:0;padding:0}#panel{height:100%;color:var(--text-color);flex-direction:column;display:flex}#panel>div{padding:1rem}#toolParametersContainer{& .title{margin-top:.5rem;margin-bottom:.75rem;display:inline-block}}.toolParameters{flex-direction:column;justify-content:left;row-gap:.25rem;display:flex}.toolParameters>label{padding:0 5px}#drawingListContainer{flex-grow:1;overflow:hidden auto;padding-top:0!important;& .titleContainer{margin-bottom:1rem;display:flex;& .title{flex-grow:1;align-items:center;display:flex}}}#drawingList{flex-flow:column;gap:.15rem;display:flex}#drawingList .girafe{border:solid 1px var(--text-color);flex-wrap:wrap;align-items:center;padding:.3rem;display:flex;position:relative}#drawingList .girafe span{flex-grow:1;padding-left:5px}#options{box-shadow:0px -2px 3px -1px var(--text-color-grad1);z-index:100;flex-direction:column;display:flex;position:relative}#optionsTitle{text-align:center;margin-bottom:20px;font-size:1.2rem}#options hr{width:100%;margin:8px 0}#optionsTextLines,#optionsColorLine,#optionsLineLines{align-items:center;display:grid}#optionsText{margin:auto}#optionsTextLines{grid-template-columns:.825fr 2.5fr 1fr 4em .5fr .5fr}#optionsTextLines button:hover{border:none}#optionsColor,#optionsLine,#optionsExport,#optionsArrow{margin:auto}#optionsColorLine{display:flex}#optionsColorLine>div{align-items:center;width:100%;display:flex}#optionsLineLines,#optionsArrowStyle{grid-template-columns:3fr 4em 1fr auto}#optionsExportLine{grid-template-columns:60px 60px 45px 45px;gap:.2rem;display:flex}span.label{padding-left:.5rem;padding-right:.5rem;&.first{padding-left:0}}span.unit{padding-left:.5rem}
38
42
  </style>
39
43
  <style>${this.customStyle}</style>
40
- <link rel="stylesheet" href="lib/vanilla-picker/vanilla-picker.csp.css"><link rel="stylesheet" href="styles/girafecolorpicker.css"><div id="panel"><div><div id="toolbar"><button id="disable" tip="Disable drawing" class="gg-icon-button gg-medium"><img alt="select icon" src="icons/arrow.svg"></button> <button id="point" tip="Point" class="gg-icon-button gg-medium"><img alt="point icon" src="icons/point.svg"></button> <button id="line" tip="Line" class="gg-icon-button gg-medium"><img alt="polyline icon" src="icons/polyline.svg"></button> <button id="polygon" tip="Polygon" class="gg-icon-button gg-medium"><img alt="polygon icon" src="icons/polygon.svg"></button> <button id="square" tip="Square" class="gg-icon-button gg-medium"><img alt="square icon" src="icons/square.svg"></button> <button id="rectangle" tip="Rectangle" class="gg-icon-button gg-medium"><img alt="rectangle icon" src="icons/rectangle.svg"></button> <button id="circle" tip="Circle" class="gg-icon-button gg-medium"><img alt="circle icon" src="icons/circle.svg"></button> <button id="freeline" tip="Freehand line" class="gg-icon-button gg-medium"><img alt="polyline-free icon" src="icons/polyline-free.svg"></button> <button id="freepolygon" tip="Freehand polygon" class="gg-icon-button gg-medium"><img alt="polygon-free icon" src="icons/polygon-free.svg"></button> <button id="text" tip="Text" class="gg-icon-button gg-medium"><img alt="text icon" src="icons/text-font.svg"></button></div><div id="toolParametersContainer"><span i18n="Settings" class="title"></span><div class="toolParameters" data-tool="Polyline,Polygon"><girafe-fixed-dimension dimensionname="length" dimension="length" id="fixedLineLength" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Square"><girafe-fixed-dimension dimensionname="side length" dimension="side" id="fixedSquareSide" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Rectangle"><girafe-fixed-dimension dimensionname="width" dimension="width" id="fixedRectangleWidth" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension><girafe-fixed-dimension dimensionname="height" dimension="height" id="fixedRectangleHeight" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Text"><label class="gg-label" for="drawingText" i18n="Text to draw">Text to draw</label> <input id="drawingText" class="gg-input" value="${this.drawingText}" oninput="${(e) => this.drawingTextChangedHandler(e)}"></div></div></div><div id="drawingListContainer"><div class="titleContainer"><span i18n="Drawing List" class="title"></span> <button class="gg-icon-button icon" tip="Delete all shapes" onclick="${() => this.deleteAllFeatures()}" ?disabled="${this.drawingState.features.length === 0}">${this.htmlUnsafe(this.trashIcon)}</button></div><div id="drawingList">${this.drawingState.features.map(feature => uHtmlFor(feature, feature.id) `<div id="${'f-' + feature.id}" class="girafe"><button id="${'f-select-' + feature.id}" class="gg-icon-button gg-small" tip="Select to change appearance" onclick="${() => this.onToggleFeatureSelection(feature)}"><div class="icon">${this.htmlUnsafe(feature.selected ? this.checkedIcon : this.noCheckedIcon)}</div></button><div class="label-container"><button class="${feature.selected ? 'selectable-label gg-icon-button gg-small gg-selected' : 'selectable-label gg-icon-button gg-small gg-opacity'}" onclick="${() => this.onToggleFeatureSelection(feature)}"><span id="${'f-name-' + feature.id}">${feature.name}</span></button></div><button class="gg-icon-button icon" tip="Center on shape" onclick="${() => this.olDrawing.centerViewOnFeature(feature)}">${this.htmlUnsafe(this.locateIcon)}</button> <button class="gg-icon-button icon" tip="Delete shape" onclick="${() => this.deleteFeature(feature)}">${this.htmlUnsafe(this.trashIcon)}</button></div>`)}</div></div><div id="options" class="${this.selectedFeatures.length > 0 ? '' : 'disabled'}"><fieldset class="field-wrapper" disabled="${this.selectedFeatures.length <= 0}"><input id="optionsTitle" value="${this.getOptionsTitle()}" class="gg-input" disabled="${this.selectedFeatures.length > 1}"><div id="optionsText"><div id="optionsTextLines"><span class="label first" i18n="Name">Name</span> <button class="gg-icon-button icon" id="visibleIconName" tip="Show or hide shape name" onclick="${() => this.toggleNameVisibility()}">${this.htmlUnsafe(this.isDisplayNameEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span class="label" i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span class="unit">pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span class="${this.isMeasureInformationEnabled() ? 'label first' : 'label first disabled'}" i18n="Measures">Measures</span> <select id="measure-information" class="gg-select" tip="${this.measureInformationTooltip}" disabled="${!this.isMeasureInformationEnabled()}" onchange="${() => this.onOptionsChange()}">${Object.entries(this.measureInformations).map((entry) => uHtml `<option selected="${this.selectedFeatureMeasureInformation === entry[0]}" value="${entry[0]}"><span i18n="${entry[1]}">${entry[0]}</span></option>`)}</select> <span class="${this.isMeasureInformationEnabled() ? 'label' : 'label disabled'}" i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" disabled="${!this.isMeasureInformationEnabled()}" oninput="${() => this.onOptionsChange()}"> <span class="${this.isMeasureInformationEnabled() ? 'unit' : 'unit disabled'}">pt</span> <button class="icon colorPicker" id="measureColorPicker" disabled="${!this.isMeasureInformationEnabled()}"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="${this.isStrokeColorEnabled() ? 'text-end' : 'text-end disabled'}" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" disabled="${!this.isStrokeColorEnabled()}" id="strokePicker"></button></div><div><span class="${this.isFillColorEnabled() ? 'text-end' : 'text-end disabled'}" id="fillPickerSpan" i18n="Fill color">Fill color</span> <button class="icon colorPicker" disabled="${!this.isFillColorEnabled()}" id="fillPicker"></button></div></div></div><hr><div id="optionsLine"><div class="${this.isLineStyleEnabled() ? '' : 'disabled'}" id="optionsLineLines"><span i18n="Line width">Line width</span> <input id="optionsStrokeWidth" type="number" class="gg-input" min="1" value="${this.selectedFeatures[0]?.strokeWidth}" oninput="${() => this.onOptionsChange()}"> <span class="unit">px</span> <select id="line-style" class="gg-select" onchange="${() => this.onOptionsChange()}">${Object.entries(this.lineStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.lineStroke === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsArrow"><div class="${this.isLineArrowEnabled() ? '' : 'disabled'}" id="optionsArrowStyles"><span i18n="Arrows style">Arrows style</span> <select id="arrow-style" class="gg-select" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowStyle === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select> <select id="arrow-position" class="gg-select" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowPositions).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowPosition === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsExport"><div id="optionsExportLine"><label for="export" class="gg-label" i18n="Export">Export</label> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('geojson')}">GeoJson</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('kml')}">KML</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('gpx')}">GPX</button></div></div></fieldset></div></div>
44
+ <div id="panel"><div><div id="toolbar"><button id="disable" tip="Disable drawing" class="gg-icon-button gg-medium"><img alt="select icon" src="icons/arrow.svg"></button> <button id="point" tip="Point" class="gg-icon-button gg-medium"><img alt="point icon" src="icons/point.svg"></button> <button id="line" tip="Line" class="gg-icon-button gg-medium"><img alt="polyline icon" src="icons/polyline.svg"></button> <button id="polygon" tip="Polygon" class="gg-icon-button gg-medium"><img alt="polygon icon" src="icons/polygon.svg"></button> <button id="square" tip="Square" class="gg-icon-button gg-medium"><img alt="square icon" src="icons/square.svg"></button> <button id="rectangle" tip="Rectangle" class="gg-icon-button gg-medium"><img alt="rectangle icon" src="icons/rectangle.svg"></button> <button id="circle" tip="Circle" class="gg-icon-button gg-medium"><img alt="circle icon" src="icons/circle.svg"></button> <button id="freeline" tip="Freehand line" class="gg-icon-button gg-medium"><img alt="polyline-free icon" src="icons/polyline-free.svg"></button> <button id="freepolygon" tip="Freehand polygon" class="gg-icon-button gg-medium"><img alt="polygon-free icon" src="icons/polygon-free.svg"></button> <button id="text" tip="Text" class="gg-icon-button gg-medium"><img alt="text icon" src="icons/text-font.svg"></button></div><div id="toolParametersContainer"><span i18n="Settings" class="title"></span><div class="toolParameters" data-tool="Polyline,Polygon"><girafe-fixed-dimension dimensionname="length" dimension="length" id="fixedLineLength" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Square"><girafe-fixed-dimension dimensionname="side length" dimension="side" id="fixedSquareSide" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Rectangle"><girafe-fixed-dimension dimensionname="width" dimension="width" id="fixedRectangleWidth" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension><girafe-fixed-dimension dimensionname="height" dimension="height" id="fixedRectangleHeight" @fixed-dimension:value-changed="${(e) => this.fixedDimensionValueChangedHandler(e)}"></girafe-fixed-dimension></div><div class="toolParameters" data-tool="Text"><label class="gg-label" for="drawingText" i18n="Text to draw">Text to draw</label> <input id="drawingText" class="gg-input" value="${this.drawingText}" oninput="${(e) => this.drawingTextChangedHandler(e)}"></div></div></div><div id="drawingListContainer"><div class="titleContainer"><span i18n="Drawing List" class="title"></span> <button class="gg-icon-button icon" tip="Delete all shapes" onclick="${() => this.deleteAllFeatures()}" ?disabled="${this.drawingState.features.length === 0}">${this.htmlUnsafe(this.trashIcon)}</button></div><div id="drawingList">${this.drawingState.features.map(feature => uHtmlFor(feature, feature.id) `<div id="${'f-' + feature.id}" class="girafe"><button id="${'f-select-' + feature.id}" class="gg-icon-button gg-small" tip="Select to change appearance" onclick="${() => this.onToggleFeatureSelection(feature)}"><div class="icon">${this.htmlUnsafe(feature.selected ? this.checkedIcon : this.noCheckedIcon)}</div></button><div class="label-container"><button class="${feature.selected ? 'selectable-label gg-icon-button gg-small gg-selected' : 'selectable-label gg-icon-button gg-small gg-opacity'}" onclick="${() => this.onToggleFeatureSelection(feature)}"><span id="${'f-name-' + feature.id}">${feature.name}</span></button></div><button class="gg-icon-button icon" tip="Center on shape" onclick="${() => this.olDrawing.centerViewOnFeature(feature)}">${this.htmlUnsafe(this.locateIcon)}</button> <button class="gg-icon-button icon" tip="Delete shape" onclick="${() => this.deleteFeature(feature)}">${this.htmlUnsafe(this.trashIcon)}</button></div>`)}</div></div><div id="options" class="${this.selectedFeatures.length > 0 ? '' : 'disabled'}"><fieldset class="field-wrapper" disabled="${this.selectedFeatures.length <= 0}"><input id="optionsTitle" aria-label="Title" value="${this.getOptionsTitle()}" class="gg-input" disabled="${this.selectedFeatures.length > 1}"><div id="optionsText"><div id="optionsTextLines"><span class="label first" i18n="Name">Name</span> <button class="gg-icon-button icon" id="visibleIconName" tip="Show or hide shape name" onclick="${() => this.toggleNameVisibility()}">${this.htmlUnsafe(this.isDisplayNameEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span class="label" i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" aria-label="Name font size" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span class="unit">pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span class="${this.isMeasureInformationEnabled() ? 'label first' : 'label first disabled'}" i18n="Measures">Measures</span> <select id="measure-information" class="gg-select" aria-label="Measures information" tip="${this.measureInformationTooltip}" disabled="${!this.isMeasureInformationEnabled()}" onchange="${() => this.onOptionsChange()}">${Object.entries(this.measureInformations).map((entry) => uHtml `<option selected="${this.selectedFeatureMeasureInformation === entry[0]}" value="${entry[0]}"><span i18n="${entry[1]}">${entry[0]}</span></option>`)}</select> <span class="${this.isMeasureInformationEnabled() ? 'label' : 'label disabled'}" i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" aria-label="Measures font size" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" disabled="${!this.isMeasureInformationEnabled()}" oninput="${() => this.onOptionsChange()}"> <span class="${this.isMeasureInformationEnabled() ? 'unit' : 'unit disabled'}">pt</span> <button class="icon colorPicker" id="measureColorPicker" disabled="${!this.isMeasureInformationEnabled()}"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="${this.isStrokeColorEnabled() ? 'text-end' : 'text-end disabled'}" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" disabled="${!this.isStrokeColorEnabled()}" id="strokePicker"></button></div><div><span class="${this.isFillColorEnabled() ? 'text-end' : 'text-end disabled'}" id="fillPickerSpan" i18n="Fill color">Fill color</span> <button class="icon colorPicker" disabled="${!this.isFillColorEnabled()}" id="fillPicker"></button></div></div></div><hr><div id="optionsLine"><div class="${this.isLineStyleEnabled() ? '' : 'disabled'}" id="optionsLineLines"><span i18n="Line width">Line width</span> <input id="optionsStrokeWidth" type="number" aria-label="Line width" class="gg-input" min="1" value="${this.selectedFeatures[0]?.strokeWidth}" oninput="${() => this.onOptionsChange()}"> <span class="unit">px</span> <select id="line-style" class="gg-select" aria-label="Line style" onchange="${() => this.onOptionsChange()}">${Object.entries(this.lineStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.lineStroke === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsArrow"><div class="${this.isLineArrowEnabled() ? '' : 'disabled'}" id="optionsArrowStyles"><span i18n="Arrows style">Arrows style</span> <select id="arrow-style" class="gg-select" aria-label="Arrows style" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowStyles).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowStyle === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select> <select id="arrow-position" class="gg-select" aria-label="Arrow position" onchange="${() => this.onArrowsChange()}">${Object.entries(this.arrowPositions).map((entry) => uHtml `<option selected="${this.selectedFeatures[0]?.arrowPosition === entry[0]}" value="${entry[0]}"><span>${entry[1]}</span></option>`)}</select></div></div><hr><div id="optionsExport"><div id="optionsExportLine"><label for="export" class="gg-label" i18n="Export">Export</label> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('geojson')}">GeoJson</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('kml')}">KML</button> <button class="gg-button" onclick="${() => this.exportSelectedFeatures('gpx')}">GPX</button></div></div></fieldset></div></div>
41
45
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
42
46
  };
43
47
  isPanelVisible = false;
@@ -450,9 +454,9 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
450
454
  }
451
455
  }
452
456
  onOptionsChange() {
453
- const nameFontSize = parseInt(this.getById('optionsNameFontSize').value);
454
- const measureFontSize = parseInt(this.getById('optionsMeasuresFontSize').value);
455
- const strokeWidth = parseInt(this.getById('optionsStrokeWidth').value);
457
+ const nameFontSize = Number.parseInt(this.getById('optionsNameFontSize').value);
458
+ const measureFontSize = Number.parseInt(this.getById('optionsMeasuresFontSize').value);
459
+ const strokeWidth = Number.parseInt(this.getById('optionsStrokeWidth').value);
456
460
  const lineStroke = this.getById('line-style').value;
457
461
  const measureInformation = this.getById('measure-information').value;
458
462
  this.selectedFeatures.forEach((f) => (f.nameFontSize = nameFontSize));
@@ -22,7 +22,7 @@ class FixedDimensionComponent extends GirafeHTMLElement {
22
22
  :host{grid-template-columns:auto auto 60px auto;justify-content:left;align-items:center;display:grid}input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var(--bkg-color-input);padding-right:0}input:focus{border:1px solid var(--lt-color-gray-900)}button{border:solid 1px var(--bkg-color);color:var(--text-color);background-color:var(--bkg-color);cursor:pointer;padding:0}button:hover{border:solid 1px var(--text-color-grad2)}button.selected{border:solid 1px var(--text-color-grad2);background-color:var(--bkg-color-grad1);color:var(--bkg-color)}.icon{width:1.2rem;height:1.2rem;fill:var(--text-color);flex-shrink:0;margin:3px}.icon:hover{fill:var(--text-color-grad2)}.gg-icon-button:hover{border:none}button:disabled,input:disabled,.disabled{pointer-events:none;opacity:.5}label.gg-label{padding:0 5px!important;&.disabled{pointer-events:revert}}
23
23
  </style>
24
24
  <style>${this.customStyle}</style>
25
- <button class="gg-icon-button icon" onclick="${() => this.toggleFixedDimensionEnabled()}">${this.htmlUnsafe(this.fixedDimensionEnabled ? this.checkedIcon : this.notCheckedIcon)}</button> <label class="${this.fixedDimensionEnabled ? 'gg-label' : 'gg-label disabled'}" onclick="${() => this.toggleFixedDimensionEnabled()}" onkeyup="${() => this.toggleFixedDimensionEnabled()}" for="fixedValue" i18n="${'Fix ' + this.dimensionName + ' to'}"></label> <input class="gg-input" disabled="${!this.fixedDimensionEnabled}" oninput="${(e) => this.fixedValueChanged(e)}" type="number" id="fixedValue"> <select id="dimensionUnits" class="gg-select" disabled="${!this.fixedDimensionEnabled}" onchange="${(e) => this.dimensionUnitChanged(e)}">${this.units.map((unit) => uHtml `<option ?selected="${this.unit?.name === unit.name}" value="${unit.factor}">${unit.name}</option>`)}</select>
25
+ <button class="gg-icon-button icon" onclick="${() => this.toggleFixedDimensionEnabled()}">${this.htmlUnsafe(this.fixedDimensionEnabled ? this.checkedIcon : this.notCheckedIcon)}</button> <label class="${this.fixedDimensionEnabled ? 'gg-label' : 'gg-label disabled'}" onclick="${() => this.toggleFixedDimensionEnabled()}" onkeyup="${() => this.toggleFixedDimensionEnabled()}" for="fixedValue" i18n="${'Fix ' + this.dimensionName + ' to'}"></label> <input class="gg-input" disabled="${!this.fixedDimensionEnabled}" oninput="${(e) => this.fixedValueChanged(e)}" type="number" id="fixedValue"> <select id="dimensionUnits" class="gg-select" aria-label="Units" disabled="${!this.fixedDimensionEnabled}" onchange="${(e) => this.dimensionUnitChanged(e)}">${this.units.map((unit) => uHtml `<option ?selected="${this.unit?.name === unit.name}" value="${unit.factor}">${unit.name}</option>`)}</select>
26
26
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
27
27
  };
28
28
  checkedIcon = checkedIcon;
@@ -33,7 +33,7 @@ export default class EditComponent extends GirafeHTMLElement {
33
33
  #content{background:var(--bkg-color);color:var(--text-color);flex-direction:column;gap:1rem;margin:0;padding:1rem;display:flex}.girafe-prototype{color:#fff;text-align:center;background:#ec5555;font-size:1rem;font-weight:700;line-height:40px}.editing{flex-direction:column;gap:1rem;display:flex}#layer-selector{width:100%}.draw-btn{text-align:right}.current-feature{border-top:var(--app-standard-border);margin-top:2rem}.current-feature-row{align-items:center;gap:.5em;display:flex}.current-feature-row>button{margin-left:auto}.current-feature-row>div:first-child{font-weight:700}.attribute-form-btns{justify-content:flex-end;gap:.5rem;margin-top:1rem;display:flex}.btn-active{background-color:var(--bkg-color-grad2)}
34
34
  </style>
35
35
  <style>${this.customStyle}</style>
36
- <div id="content"><div class="girafe-prototype" i18n="PROTOTYPE - Work in progress">PROTOTYPE - Work in progress</div><div class="editing"><select id="layer-selector" class="gg-select" disabled="${this.feature}" onchange="${(evt) => this.onSelectLayer(evt)}">${this.editableLayersList.length === 0 && this.state.oauth.status !== 'loggedIn' ? uHtml `<option i18n="Please log in to edit layers..." ?selected="true" value="">Please log in to edit layers...</option>` : uHtml `<option i18n="Choose a layer..." ?selected="true" value="">Choose a layer...</option>`} ${this.editableLayersList.map(layer => uHtmlFor(layer, layer.collectionId) `<option value="${layer.collectionId}">${layer.displayName}</option>`)}</select> ${this.layer ? uHtml `<div class="draw-btn">${this.displayDrawingCancelButton() ? uHtml ` <button class="gg-button gg-medium-withtext btn-active" onclick="${() => this.onCancelDrawing()}"><img alt="cancel-drawing-icon" src="icons/close.svg"> <span i18n="Cancel editing">Cancel editing</span></button> ` : uHtml ` <button class="gg-button gg-medium-withtext" onclick="${() => this.onStartDrawing()}"><img alt="start-drawing-icon" src="${this.getButtonIcon()}"> <span i18n="${this.getButtonText()}">${this.getButtonText()}</span></button> `}</div>` : uHtml ``} ${this.feature ? uHtml `<div class="current-feature"><h3 i18n="Current Feature">Current Feature</h3><div class="current-feature-row"><div i18n="Feature ID">Feature ID</div><div>${this.getFeatureId()}</div><button class="${this.canDelete() ? 'gg-button gg-medium-withtext delete-btn' : 'hidden'}" onclick="${() => this.onDelete()}"><img alt="delete-icon" src="icons/trash.svg"> <span i18n="delete">Delete</span></button></div></div>` : uHtml ``}<girafe-edit-form id="edit-form"></girafe-edit-form>${this.feature ? uHtml `<div class="attribute-form-btns"><button class="gg-button" disabled="${!this.isValidForm()}" onclick="${() => this.onSave()}"><span i18n="Save">Save</span></button> <button class="gg-button" onclick="${() => this.onDiscard()}"><span i18n="Discard">Discard</span></button></div>` : uHtml ``}</div></div>
36
+ <div id="content"><div class="girafe-prototype" i18n="PROTOTYPE - Work in progress">PROTOTYPE - Work in progress</div><div class="editing"><select id="layer-selector" class="gg-select" aria-label="Layer to edit" disabled="${this.feature}" onchange="${(evt) => this.onSelectLayer(evt)}">${this.editableLayersList.length === 0 && this.state.oauth.status !== 'loggedIn' ? uHtml `<option i18n="Please log in to edit layers..." ?selected="true" value="">Please log in to edit layers...</option>` : uHtml `<option i18n="Choose a layer..." ?selected="true" value="">Choose a layer...</option>`} ${this.editableLayersList.map(layer => uHtmlFor(layer, layer.collectionId) `<option value="${layer.collectionId}">${layer.displayName}</option>`)}</select> ${this.layer ? uHtml `<div class="draw-btn">${this.displayDrawingCancelButton() ? uHtml ` <button class="gg-button gg-medium-withtext btn-active" onclick="${() => this.onCancelDrawing()}"><img alt="cancel-drawing-icon" src="icons/close.svg"> <span i18n="Cancel editing">Cancel editing</span></button> ` : uHtml ` <button class="gg-button gg-medium-withtext" onclick="${() => this.onStartDrawing()}"><img alt="start-drawing-icon" src="${this.getButtonIcon()}"> <span i18n="${this.getButtonText()}">${this.getButtonText()}</span></button> `}</div>` : uHtml ``} ${this.feature ? uHtml `<div class="current-feature"><h3 i18n="Current Feature">Current Feature</h3><div class="current-feature-row"><div i18n="Feature ID">Feature ID</div><div>${this.getFeatureId()}</div><button class="${this.canDelete() ? 'gg-button gg-medium-withtext delete-btn' : 'hidden'}" onclick="${() => this.onDelete()}"><img alt="delete-icon" src="icons/trash.svg"> <span i18n="delete">Delete</span></button></div></div>` : uHtml ``}<girafe-edit-form id="edit-form"></girafe-edit-form>${this.feature ? uHtml `<div class="attribute-form-btns"><button class="gg-button" disabled="${!this.isValidForm()}" onclick="${() => this.onSave()}"><span i18n="Save">Save</span></button> <button class="gg-button" onclick="${() => this.onDiscard()}"><span i18n="Discard">Discard</span></button></div>` : uHtml ``}</div></div>
37
37
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
38
38
  };
39
39
  isPanelVisible = false;
@@ -56,7 +56,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
56
56
  const formField = this.getById(`form-${attrName}`);
57
57
  let formValue = formField.value;
58
58
  if (this.featureSchema.isNumericProperty(attrName)) {
59
- if (formValue === '' || isNaN(Number(formValue))) {
59
+ if (formValue === '' || Number.isNaN(Number(formValue))) {
60
60
  formValue = null;
61
61
  }
62
62
  else {
@@ -18,7 +18,7 @@ class ExternalLayersComponent extends GirafeHTMLElement {
18
18
  #panel{background:var(--bkg-color);height:100%;color:var(--text-color);flex-direction:column;padding:0 1rem;display:flex}#content{flex-direction:column;flex-grow:1;margin:0;display:flex}header{background-color:var(--bkg-color);margin:0;position:sticky;top:-5px}h4{margin-bottom:.5rem}ul{margin-top:0;margin-left:0;padding-left:2rem;line-height:1.3rem;list-style-type:disc}.clearable-input{background-color:var(--bkg-color);border:1px solid #cfd6dd;border-radius:4px;flex-direction:row;margin-bottom:.1rem;display:flex}.scan-button{float:right}.layers{border-top:1px solid #ccc;flex-direction:column;flex-grow:1;margin-top:1rem;padding-top:.5rem;display:flex;overflow:hidden}ul.results{border:none;margin-bottom:.5rem;padding:0;list-style:none;overflow-y:auto}.result{height:1.6rem;display:flex}.result>button>span{text-align:left;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}#panel>div{padding:1rem}#layers li{margin-top:.3rem;margin-bottom:.3rem}#layers li button{text-align:left;overflow-wrap:anywhere;text-wrap-style:balance}#loading-icon{flex-grow:1;align-self:center;width:3rem}.title{margin-top:0}.filter-buttons{flex-direction:row;margin:2px;display:flex}.filter-buttons span{flex-grow:1;align-self:center}.clearable-input-field{width:90%;color:var(--text-color);background:0 0;border:0;outline:none;flex:auto;padding:0;font-size:1rem}.filter-icon,.delete-icon{width:16px;color:var(--text-color);padding:0 .5rem}.delete-button{cursor:pointer;background-color:#0000;border:none;padding:0}#file-selector{flex-direction:column;display:flex;position:relative}#file{color:var(--text-color);cursor:pointer}#file::file-selector-button{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);min-height:calc(var(--app-standard-height) / 1.5);font:inherit;cursor:pointer;border-radius:.25em;outline:0;margin:0 .5rem 0 0;padding:0 .5rem}#file::file-selector-button:hover{background-color:var(--bkg-color-grad1)}.file-loaded-message{box-sizing:border-box;background-color:var(--success-color);border-radius:.25em;width:100%;margin:.5rem 0 0;padding:.5em;position:absolute;top:100%;left:0}
19
19
  </style>
20
20
  <style>${this.customStyle}</style>
21
- <div id="panel"><header class="gg-tabs"><button class="${this.selectedTab === 'wms_wmts' ? 'gg-tab active' : 'gg-tab'}" onclick="${() => this.setSelectedTab('wms_wmts')}" i18n="wms_wmts"></button> <button class="${this.selectedTab === 'file' ? 'gg-tab active' : 'gg-tab'}" onclick="${() => this.setSelectedTab('file')}" i18n="local file"></button></header><section class="${(this.selectedTab === 'wms_wmts') ? 'group' : 'hidden'}"><h4 class="title" i18n="Suggestions" ?hidden="${!this.hasPredefinedWmsWmtsSources}">Suggestions</h4><ul class="suggestions" ?hidden="${!this.hasPredefinedWmsWmtsSources}">${this.predefinedWmsWmtsSources.map(source => uHtmlFor(source, source.label) `<li><a href="javascript:void(0)" onclick="${() => this.scanSource(source.url, source.type)}">${source.label}</a></li>`)}</ul><h4 class="title" i18n="Custom service URL">Custom service URL</h4><div class="clearable-input"><input id="url" class="gg-input clearable-input-field" oninput="${() => this.typeUrl()}"><br><button id="clear-url" class="delete-button hidden" onclick="${() => this.clearUrl()}"><img class="delete-icon" alt="delete-button-icon" tip="Reset filter" i18n="Reset filter" src="icons/trash.svg"></button></div><button i18n="Scan Source" class="gg-button scan-button" onclick="${() => this.scanSource()}">Scan Source</button></section><section class="${(this.selectedTab === 'file') ? 'group' : 'hidden'}"><div id="file-selector"><label for="file" class="gg-label" i18n="Choose local file">Choose local file</label> <input type="file" accept=".gpx,.kml,.geojson,.json" id="file" onchange="${() => this.loadFile()}"><p class="${this.fileLoaded ? 'file-loaded-message' : 'hidden'}" i18n="File loaded in the layer tree">File loaded in the layer tree</div></section><section class="${(this.selectedTab === 'wms_wmts' && this.externalLayers.length > 0) || this.loading ? 'layers' : 'hidden'}"><h4 class="title" i18n="Layers (from Capabilities)">Layers (from Capabilities)</h4><div class="clearable-input"><img class="filter-icon" alt="filter-button-icon" src="icons/filter.svg"> <input id="layer-search-field" class="gg-input clearable-input-field" placeholder="${this.context.i18nManager.getTranslation('Filter external layers...')}" i18n="Filter external layers..." autocomplete="off" autocorrect="off" oninput="${(e) => this.filterLayers(e.target.value)}"> <button class="${this.isFiltered ? 'delete-button' : 'hidden'}" onclick="${() => this.clearFilter()}"><img class="delete-icon" alt="delete-button-icon" tip="Reset filter" i18n="Reset filter" src="icons/trash.svg"></button></div><div class="filter-buttons"><span>${Object.values(this.externalLayers).filter(layer => layer.isSelected).length.toString()} ${this.context.i18nManager.getTranslation('layers selected')} </span><button class="gg-button" tip="Select all filtered layers" onclick="${() => this.selectVisible()}">+</button> <button class="gg-button" tip="Unselect all filtered layers" onclick="${() => this.deselectVisible()}">-</button> <button class="gg-button" tip="Select none" onclick="${() => this.deselectAll()}">--</button></div><img id="loading-icon" alt="loading-icon" src="icons/loading.svg" class="${this.loading ? 'gg-spin' : 'hidden'}"><ul class="results">${this.filteredLayers.map(layer => uHtmlFor(layer, layer.treeItemId) `<li class="result"><button class="${layer.isSelected ? 'gg-icon-button gg-small gg-selected' : 'gg-icon-button gg-small gg-opacity'}" tip="Activate / Deactivate" onclick="${() => this.selectLayer(layer)}"><img class="${layer.isSelected ? 'gg-checkbox' : 'hidden'}" alt="Expand/Collapse button" src="icons/checked-full.svg"> <img class="${!layer.isSelected ? 'gg-checkbox' : 'hidden'}" alt="Expand/Collapse button" src="icons/checked-no.svg"></button> <button class="${layer.isSelected ? 'gg-icon-button gg-small gg-selected' : 'gg-icon-button gg-small gg-opacity'}" onclick="${() => this.selectLayer(layer)}"><span i18n="${layer.name}" class="gg-tree-label">${layer.name}</span></button></li>`)}</ul><button id="add" tip="Add selected" i18n="Add selected" class="gg-button" onclick="${() => this.addSelectedLayers()}">Add selected</button></section></div>
21
+ <div id="panel"><header class="gg-tabs"><button class="${this.selectedTab === 'wms_wmts' ? 'gg-tab active' : 'gg-tab'}" onclick="${() => this.setSelectedTab('wms_wmts')}" i18n="wms_wmts"></button> <button class="${this.selectedTab === 'file' ? 'gg-tab active' : 'gg-tab'}" onclick="${() => this.setSelectedTab('file')}" i18n="local file"></button></header><section class="${(this.selectedTab === 'wms_wmts') ? 'group' : 'hidden'}"><h4 class="title" i18n="Suggestions" ?hidden="${!this.hasPredefinedWmsWmtsSources}">Suggestions</h4><ul class="suggestions" ?hidden="${!this.hasPredefinedWmsWmtsSources}">${this.predefinedWmsWmtsSources.map(source => uHtmlFor(source, source.label) `<li><a href="javascript:void(0)" onclick="${() => this.scanSource(source.url, source.type)}">${source.label}</a></li>`)}</ul><h4 class="title" i18n="Custom service URL">Custom service URL</h4><div class="clearable-input"><input id="url" aria-label="Custom service URL" class="gg-input clearable-input-field" oninput="${() => this.typeUrl()}"><br><button id="clear-url" class="delete-button hidden" onclick="${() => this.clearUrl()}"><img class="delete-icon" alt="delete-button-icon" tip="Reset filter" i18n="Reset filter" src="icons/trash.svg"></button></div><button i18n="Scan Source" class="gg-button scan-button" onclick="${() => this.scanSource()}">Scan Source</button></section><section class="${(this.selectedTab === 'file') ? 'group' : 'hidden'}"><div id="file-selector"><label for="file" class="gg-label" i18n="Choose local file">Choose local file</label> <input type="file" accept=".gpx,.kml,.geojson,.json" id="file" onchange="${() => this.loadFile()}"><p class="${this.fileLoaded ? 'file-loaded-message' : 'hidden'}" i18n="File loaded in the layer tree">File loaded in the layer tree</div></section><section class="${(this.selectedTab === 'wms_wmts' && this.externalLayers.length > 0) || this.loading ? 'layers' : 'hidden'}"><h4 class="title" i18n="Layers (from Capabilities)">Layers (from Capabilities)</h4><div class="clearable-input"><img class="filter-icon" alt="filter-button-icon" src="icons/filter.svg"> <input id="layer-search-field" class="gg-input clearable-input-field" aria-label="Filter external layers" placeholder="${this.context.i18nManager.getTranslation('Filter external layers...')}" i18n="Filter external layers..." autocomplete="off" autocorrect="off" oninput="${(e) => this.filterLayers(e.target.value)}"> <button class="${this.isFiltered ? 'delete-button' : 'hidden'}" onclick="${() => this.clearFilter()}"><img class="delete-icon" alt="delete-button-icon" tip="Reset filter" i18n="Reset filter" src="icons/trash.svg"></button></div><div class="filter-buttons"><span>${Object.values(this.externalLayers).filter(layer => layer.isSelected).length.toString()} ${this.context.i18nManager.getTranslation('layers selected')} </span><button class="gg-button" tip="Select all filtered layers" onclick="${() => this.selectVisible()}">+</button> <button class="gg-button" tip="Unselect all filtered layers" onclick="${() => this.deselectVisible()}">-</button> <button class="gg-button" tip="Select none" onclick="${() => this.deselectAll()}">--</button></div><img id="loading-icon" alt="loading-icon" src="icons/loading.svg" class="${this.loading ? 'gg-spin' : 'hidden'}"><ul class="results">${this.filteredLayers.map(layer => uHtmlFor(layer, layer.treeItemId) `<li class="result"><button class="${layer.isSelected ? 'gg-icon-button gg-small gg-selected' : 'gg-icon-button gg-small gg-opacity'}" tip="Activate / Deactivate" onclick="${() => this.selectLayer(layer)}"><img class="${layer.isSelected ? 'gg-checkbox' : 'hidden'}" alt="Expand/Collapse button" src="icons/checked-full.svg"> <img class="${!layer.isSelected ? 'gg-checkbox' : 'hidden'}" alt="Expand/Collapse button" src="icons/checked-no.svg"></button> <button class="${layer.isSelected ? 'gg-icon-button gg-small gg-selected' : 'gg-icon-button gg-small gg-opacity'}" onclick="${() => this.selectLayer(layer)}"><span i18n="${layer.name}" class="gg-tree-label">${layer.name}</span></button></li>`)}</ul><button id="add" tip="Add selected" i18n="Add selected" class="gg-button" onclick="${() => this.addSelectedLayers()}">Add selected</button></section></div>
22
22
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
23
23
  };
24
24
  isPanelVisible = false;
@@ -51,7 +51,7 @@ export default class Map2dComponent extends GirafeHTMLElement {
51
51
  #container,#ol-map{background-color:var(--bkg-color);width:100%;height:100%;position:relative}#ol-map.darkmap canvas{filter:invert()hue-rotate(180deg)}.hidden{display:none}.ol-control{background-color:#0000;border:none;box-shadow:0 1px 4px #0000004d;right:2rem!important;left:unset!important}.ol-zoom{top:2rem!important}.mobile-map .ol-zoom{display:none!important}.ol-rotate{top:11.6rem!important}.ol-fullscreen{top:7rem!important}.ol-location{top:9.3rem!important}.img-location,.img-disable-location,.img-fullscreen{width:55%;height:auto}.ol-zoom-in,.ol-zoom-out,.btn-location,.btn-disable-location,.btn-fullscreen,.btn-exit-fullscreen,.ol-rotate-reset{cursor:pointer;background-color:var(--bkg-color)!important;width:2rem!important;height:2rem!important;color:var(--text-color)!important;font-size:1.2rem!important}.ol-scale-line{bottom:.5rem!important;right:1rem!important;left:unset!important}#swiper{width:100%;height:0;margin:0;display:none;position:absolute;top:50%}input[type=range]{-webkit-appearance:none;width:100%}input[type=range]::-webkit-slider-runnable-track{height:0}input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;background:var(--bkg-color);cursor:ew-resize;border:2px solid #444;width:6px;height:0;margin-top:-1000px;padding-top:1000px;padding-bottom:1000px}input[type=range]::-moz-range-thumb{background:var(--bkg-color);cursor:ew-resize;border:2px solid #444;width:3px;height:0;padding-top:1000px;padding-bottom:1000px}.close-swiper{--button-size:2rem;transform:translateX(calc(-1 * var(--button-size) / 2));width:var(--button-size);height:var(--button-size);background-color:var(--bkg-color);color:var(--text-color);cursor:pointer;border-width:1px;border-radius:4px;display:none;position:absolute;top:0}.close-swiper:hover,.close-swiper:focus{outline:1px solid var(--text-color);color:var(--text-color-grad1)}.ol-viewport .tooltip{color:#fff;opacity:.7;white-space:nowrap;background:#00000080;border-radius:0;padding:.32rem .62rem;position:relative}@media screen and (hover:none){.ol-zoom,.ol-rotate,.ol-location,.ol-fullscreen{display:none!important}}.contextmenu{background-color:var(--bkg-color);color:var(--text-color);border:1px solid #ccc;box-shadow:1px 3px 4px #0006;& .hidden{display:none}& .menu-entry{cursor:pointer;padding:10px}& .menu-entry:hover{background-color:var(--bkg-color-grad1)}& .menu-entry[aria-disabled=true]{pointer-events:none;color:var(--text-color-grad1)}}
52
52
  </style>
53
53
  <style>${this.customStyle}</style>
54
- <div id="container"><div id="ol-map" class="${this.onMobile ? 'mobile-map' : ''}"></div><div class="${this.onMobile ? 'hidden' : 'ol-fullscreen ol-unselectable ol-control'}"><button id="fullscreen-enter-button" onclick="${() => this.toggleFullscreen()}" tip="fullscreen-on" class="btn-fullscreen"><img class="img-fullscreen" alt="fullscreen-icon" src="icons/fullscreen.svg"></button> <button id="fullscreen-exit-button" onclick="${() => this.toggleFullscreen()}" tip="fullscreen-off" class="btn-exit-fullscreen hidden"><img class="img-fullscreen" alt="fullscreen-exit-icon" src="icons/fullscreen-exit.svg"></button></div><div class="${this.onMobile ? 'hidden' : 'ol-location ol-unselectable ol-control'}"><button onclick="${() => this.locateUser()}" class="btn-location" tip="Locate user"><img class="img-location" alt="location-icon" src="icons/adjust.svg"></button> <button id="disable-location" onclick="${() => this.disableLocateUser()}" tip="Disable locate user" class="btn-disable-location hidden"><img class="img-disable-location" alt="disable-location-icon" src="icons/adjust-disable.svg"></button></div><input id="swiper" type="range" min="0" max="1000" step="1"> <button tip="Hide Swiper" id="close-swiper" class="close-swiper">×</button></div>
54
+ <div id="container"><div id="ol-map" class="${this.onMobile ? 'mobile-map' : ''}"></div><div class="${this.onMobile ? 'hidden' : 'ol-fullscreen ol-unselectable ol-control'}"><button id="fullscreen-enter-button" onclick="${() => this.toggleFullscreen()}" tip="fullscreen-on" class="btn-fullscreen"><img class="img-fullscreen" alt="fullscreen-icon" src="icons/fullscreen.svg"></button> <button id="fullscreen-exit-button" onclick="${() => this.toggleFullscreen()}" tip="fullscreen-off" class="btn-exit-fullscreen hidden"><img class="img-fullscreen" alt="fullscreen-exit-icon" src="icons/fullscreen-exit.svg"></button></div><div class="${this.onMobile ? 'hidden' : 'ol-location ol-unselectable ol-control'}"><button onclick="${() => this.locateUser()}" class="btn-location" tip="Locate user"><img class="img-location" alt="location-icon" src="icons/adjust.svg"></button> <button id="disable-location" onclick="${() => this.disableLocateUser()}" tip="Disable locate user" class="btn-disable-location hidden"><img class="img-disable-location" alt="disable-location-icon" src="icons/adjust-disable.svg"></button></div><input id="swiper" type="range" aria-label="Map swiper" min="0" max="1000" step="1"> <button tip="Hide Swiper" id="close-swiper" class="close-swiper">×</button></div>
55
55
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
56
56
  };
57
57
  olMap;
@@ -18,7 +18,7 @@ class SwipeManager {
18
18
  if (!maxVal) {
19
19
  throw new Error('The Attribute <max> on the swiper is not defined !');
20
20
  }
21
- this.swiperMaxVal = parseInt(maxVal);
21
+ this.swiperMaxVal = Number.parseInt(maxVal);
22
22
  this.wmtsManager = wmtsManager;
23
23
  this.wmsManager = wmsManager;
24
24
  this.localFileManager = localFileManager;
@@ -139,7 +139,7 @@ class SwipeManager {
139
139
  throw new Error('The size of the map is null !');
140
140
  }
141
141
  const mapSize = size;
142
- const width = mapSize[0] * (parseInt(this.swiper.value) / this.swiperMaxVal);
142
+ const width = mapSize[0] * (Number.parseInt(this.swiper.value) / this.swiperMaxVal);
143
143
  let tl;
144
144
  let tr;
145
145
  let bl;
@@ -11,7 +11,7 @@ class ModalsComponent extends GirafeHTMLElement {
11
11
  #content{z-index:10000;background-color:#000000a6;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal{background:var(--bkg-color);border:var(--app-standard-border);border-radius:10px;width:300px;min-height:400px;box-shadow:5px 5px 10px #0003}.wide{width:auto;max-width:480px}header{background:var(--app-color-grey);border-top-left-radius:10px;border-top-right-radius:10px;justify-content:center;height:100px;padding:2rem;display:flex}section{text-align:center;flex-direction:column;padding:30px;display:flex}span{margin-bottom:1rem;font-size:1.2rem;display:inline-block}.confirm-buttons{flex-direction:row;justify-content:center;gap:1rem;margin-top:2rem;display:flex}.confirm-buttons button{width:7rem}h2,span{color:var(--text-color)}.choices{grid-template-columns:1fr 1fr;gap:1rem;margin-top:1rem;display:grid}.choice{height:4rem}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div id="content" class="${this.visible ? '' : 'hidden'}"><div class="${this.boxType == 'info' ? 'modal wide' : 'modal'}"><header><img alt="question-icon" src="icons/help.svg" class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'hidden' : ''}"> <img alt="error-icon" src="icons/error.svg" class="${this.boxType === 'alert' ? '' : 'hidden'}"> <img alt="info-icon" src="icons/info.svg" class="${this.boxType === 'info' ? '' : 'hidden'}"></header><section><h2>${this.boxTitle}</h2><span>${this.htmlUnsafe(this.boxMessage)}</span> <input id="input-text" class="${this.boxType === 'prompt' ? 'gg-input' : 'hidden'}" placeholder="${this.boxPlaceholder}"><div class="${this.boxType === 'choice' ? 'choices' : 'hidden'}">${this.boxChoices.map(option => uHtml ` <button class="gg-button choice" onclick="${() => this.choiceOk(option)}">${option}</button> `)}</div><div class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Ok">Ok</button></div><div class="${this.boxType === 'confirm' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Yes">Yes</button> <button class="gg-button" onclick="${() => this.nok()}" i18n="No">No</button></div><div class="${this.boxType === 'prompt' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptOk()}" i18n="Ok">Ok</button> <button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div><div class="${this.boxType === 'choice' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div></section></div></div>
14
+ <div id="content" class="${this.visible ? '' : 'hidden'}"><div class="${this.boxType == 'info' ? 'modal wide' : 'modal'}"><header><img alt="question-icon" src="icons/help.svg" class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'hidden' : ''}"> <img alt="error-icon" src="icons/error.svg" class="${this.boxType === 'alert' ? '' : 'hidden'}"> <img alt="info-icon" src="icons/info.svg" class="${this.boxType === 'info' ? '' : 'hidden'}"></header><section><h2>${this.boxTitle}</h2><span>${this.htmlUnsafe(this.boxMessage)}</span> <input id="input-text" aria-label="Input" class="${this.boxType === 'prompt' ? 'gg-input' : 'hidden'}" placeholder="${this.boxPlaceholder}"><div class="${this.boxType === 'choice' ? 'choices' : 'hidden'}">${this.boxChoices.map(option => uHtml ` <button class="gg-button choice" onclick="${() => this.choiceOk(option)}">${option}</button> `)}</div><div class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Ok">Ok</button></div><div class="${this.boxType === 'confirm' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Yes">Yes</button> <button class="gg-button" onclick="${() => this.nok()}" i18n="No">No</button></div><div class="${this.boxType === 'prompt' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptOk()}" i18n="Ok">Ok</button> <button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div><div class="${this.boxType === 'choice' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div></section></div></div>
15
15
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
16
16
  };
17
17
  visible = false;