@geogirafe/lib-geoportal 1.1.0-dev.2433737633 → 1.1.0-dev.2438378072

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.
@@ -70,9 +70,11 @@
70
70
  "Define time restriction on group": "Zeitliche Begrenzung für Gruppe definieren",
71
71
  "Define time restriction on layer": "Zeitliche Begrenzung für Layer definieren",
72
72
  "delete": "Löschen",
73
+ "Delete all shapes": "Alle Formen löschen",
73
74
  "Delete bookmark": "Lesezeichen löschen",
74
75
  "Delete Feature": "Funktion löschen",
75
76
  "Delete feature": "Objekt löschen",
77
+ "Delete Features": "Objekte löschen",
76
78
  "Delete shape": "Form löschen",
77
79
  "Delete Theme": "Thema löschen",
78
80
  "delete_help": "Profil-Linie löschen",
@@ -85,6 +87,7 @@
85
87
  "Do you want to delete this theme?": "Möchten Sie dieses Thema löschen?",
86
88
  "Do you want to logout ?": "Möchten Sie sich abmelden?",
87
89
  "Do you want to remove \"${feature.name}\" ?": "Möchten Sie \"${feature.name}\" entfernen?",
90
+ "Do you want to remove all features?": "Möchten Sie alle Objekte entfernen?",
88
91
  "Documentation": "Dokumentation",
89
92
  "does not contain": "enthält nicht",
90
93
  "does not equal": "ungleich",
@@ -102,6 +105,7 @@
102
105
  "Draw polygons": "Polygone zeichnen",
103
106
  "draw_profile": "Profil-Linie zeichnen",
104
107
  "draw_profile_help": "Profil-Linien-Zeichnen auf der Karte umschalten",
108
+ "Drawing List": "Zeichnungsliste",
105
109
  "drawing-panel": "Zeichnen & messen",
106
110
  "drawingFillColor": "Zeichnen Füllfarbe",
107
111
  "Drawings": "Zeichnungen",
@@ -142,7 +146,10 @@
142
146
  "Filter layer": "Layer filtern",
143
147
  "Filter layer tree...": "Layerliste filtern...",
144
148
  "Filtering deactivated: layers in layergroup don't have identical attributes.": "Filterung deaktiviert: Layer in der Layergruppe haben nicht identische Attribute.",
149
+ "Fix height to": "Höhe festlegen auf",
145
150
  "Fix length to": "Länge festlegen auf",
151
+ "Fix side length to": "Seitenlänge festlegen auf",
152
+ "Fix width to": "Breite festlegen auf",
146
153
  "Font": "Schriftart",
147
154
  "Format": "Format",
148
155
  "fr": "Französisch",
@@ -378,6 +385,7 @@
378
385
  "selectStrokeColor": "Auswahl Strichfarbe",
379
386
  "Send": "Senden",
380
387
  "Send message": "Nachricht senden",
388
+ "Settings": "Einstellungen",
381
389
  "Shadows": "Schatten",
382
390
  "Share this map": "Diese Karte teilen",
383
391
  "share-panel": "Karte teilen oder einbetten",
@@ -73,6 +73,8 @@
73
73
  "Delete bookmark": "Delete bookmark",
74
74
  "Delete Feature": "Delete Feature",
75
75
  "Delete feature": "Delete feature",
76
+ "Delete Features": "Delete Features",
77
+ "Delete all shapes": "Delete all shapes",
76
78
  "Delete shape": "Delete shape",
77
79
  "Delete Theme": "Delete Theme",
78
80
  "delete_help": "Delete profile line",
@@ -85,6 +87,7 @@
85
87
  "Do you want to delete this theme?": "Do you want to delete this theme?",
86
88
  "Do you want to logout ?": "Do you want to logout?",
87
89
  "Do you want to remove \"${feature.name}\" ?": "Do you want to remove \"${feature.name}\"?",
90
+ "Do you want to remove all features?": "Do you want to remove all features?",
88
91
  "Documentation": "Documentation",
89
92
  "does not contain": "does not contain",
90
93
  "does not equal": "does not equal",
@@ -102,6 +105,7 @@
102
105
  "Draw polygons": "Draw polygons",
103
106
  "draw_profile": "Draw profile line",
104
107
  "draw_profile_help": "Toggle profile line drawing on map",
108
+ "Drawing List": "Drawings List",
105
109
  "drawing-panel": "Draw & measure",
106
110
  "drawingFillColor": "Drawing fill color",
107
111
  "Drawings": "Drawings",
@@ -143,7 +147,10 @@
143
147
  "Filter layer": "Filter layer",
144
148
  "Filter layer tree...": "Filter layer tree...",
145
149
  "Filtering deactivated: layers in layergroup don't have identical attributes.": "Filtering deactivated: layers in layergroup don't have identical attributes.",
150
+ "Fix height to": "Fix height to",
146
151
  "Fix length to": "Fix length to",
152
+ "Fix side length to": "Fix side length to",
153
+ "Fix width to": "Fix width to",
147
154
  "Font": "Font",
148
155
  "Format": "Format",
149
156
  "fr": "French",
@@ -379,6 +386,7 @@
379
386
  "selectStrokeColor": "Selection stroke color",
380
387
  "Send": "Send",
381
388
  "Send message": "Send message",
389
+ "Settings": "Settings",
382
390
  "Shadows": "Shadows",
383
391
  "Share this map": "Share this map",
384
392
  "share-panel": "Share or embed map",
@@ -70,9 +70,11 @@
70
70
  "Define time restriction on group": "Définir la restriction temporelle pour le groupe",
71
71
  "Define time restriction on layer": "Définir la restriction temporelle sur la couche",
72
72
  "delete": "Supprimer",
73
+ "Delete all shapes": "Supprimer toutes les formes",
73
74
  "Delete bookmark": "Supprimer le favori",
74
75
  "Delete Feature": "Supprimer la fonctionnalité",
75
76
  "Delete feature": "Suppression de l'entité",
77
+ "Delete Features": "Supprimer les objets",
76
78
  "Delete shape": "Supprimer la forme",
77
79
  "Delete Theme": "Supprimer le thème",
78
80
  "delete_help": "Supprimer la ligne de profil",
@@ -85,6 +87,7 @@
85
87
  "Do you want to delete this theme?": "Voulez-vous supprimer ce thème ?",
86
88
  "Do you want to logout ?": "Voulez-vous vous déconnecter ?",
87
89
  "Do you want to remove \"${feature.name}\" ?": "Voulez-vous supprimer \"${feature.name}\" ?",
90
+ "Do you want to remove all features?": "Voulez-vous supprimer tous les objets ?",
88
91
  "Documentation": "Documentation",
89
92
  "does not contain": "ne contient pas",
90
93
  "does not equal": "n'est pas égal à",
@@ -102,6 +105,7 @@
102
105
  "Draw polygons": "Tracer des polygones",
103
106
  "draw_profile": "Dessiner",
104
107
  "draw_profile_help": "Activer/désactiver le dessin de la ligne de profil sur la carte",
108
+ "Drawing List": "Liste des dessins",
105
109
  "drawing-panel": "Dessiner & mesurer",
106
110
  "drawingFillColor": "Couleur de remplissage du dessin",
107
111
  "Drawings": "Dessins",
@@ -142,7 +146,10 @@
142
146
  "Filter layer": "Filtrer la couche",
143
147
  "Filter layer tree...": "Filtrer les couches...",
144
148
  "Filtering deactivated: layers in layergroup don't have identical attributes.": "Filtrage désactivé : les couches dans le groupe de couches n'ont pas d'attributs identiques.",
149
+ "Fix height to": "Fixer la hauteur à",
145
150
  "Fix length to": "Fixer la longueur à",
151
+ "Fix side length to": "Fixer la longueur du côté à",
152
+ "Fix width to": "Fixer la largeur à",
146
153
  "Font": "Police",
147
154
  "Format": "Format",
148
155
  "fr": "Français",
@@ -378,6 +385,7 @@
378
385
  "selectStrokeColor": "Couleur du trait de sélection",
379
386
  "Send": "Envoyer",
380
387
  "Send message": "Envoyer un message",
388
+ "Settings": "Paramètres",
381
389
  "Shadows": "Ombres",
382
390
  "Share this map": "Partager cette carte",
383
391
  "share-panel": "Partager ou intégrer la carte",
@@ -70,9 +70,11 @@
70
70
  "Define time restriction on group": "Definire la restrizione temporale del gruppo",
71
71
  "Define time restriction on layer": "Definire la restrizione temporale del livello",
72
72
  "delete": "Elimina",
73
+ "Delete all shapes": "Elimina tutte le forme",
73
74
  "Delete bookmark": "Elimina segnalibro",
74
75
  "Delete Feature": "Elimina funzionalità",
75
76
  "Delete feature": "Eliminare l'elemento",
77
+ "Delete Features": "Elimina oggetti",
76
78
  "Delete shape": "Elimina forma",
77
79
  "Delete Theme": "Elimina tema",
78
80
  "delete_help": "Elimina la linea di profilo",
@@ -85,6 +87,7 @@
85
87
  "Do you want to delete this theme?": "Vuoi eliminare questo tema?",
86
88
  "Do you want to logout ?": "Vuoi disconnetterti?",
87
89
  "Do you want to remove \"${feature.name}\" ?": "Vuoi rimuovere \"${feature.name}\"?",
90
+ "Do you want to remove all features?": "Vuoi rimuovere tutti gli oggetti?",
88
91
  "Documentation": "Documentazione",
89
92
  "does not contain": "non contiene",
90
93
  "does not equal": "diverso da",
@@ -102,6 +105,7 @@
102
105
  "Draw polygons": "Disegnare un poligono",
103
106
  "draw_profile": "Disegna linea di profilo",
104
107
  "draw_profile_help": "Attiva/disattiva il disegno della linea di profilo sulla mappa",
108
+ "Drawing List": "Elenco dei disegni",
105
109
  "drawing-panel": "Disegna e misura",
106
110
  "drawingFillColor": "Colore di riempimento del disegno",
107
111
  "Drawings": "Disegni",
@@ -142,7 +146,10 @@
142
146
  "Filter layer": "Filtra layer",
143
147
  "Filter layer tree...": "Albero dei livelli di filtraggio...",
144
148
  "Filtering deactivated: layers in layergroup don't have identical attributes.": "Filtro disattivato: i layer nel gruppo non hanno attributi identici.",
149
+ "Fix height to": "Fissa l’altezza a",
145
150
  "Fix length to": "Fissa la lunghezza a",
151
+ "Fix side length to": "Fissare la lunghezza del lato a",
152
+ "Fix width to": "Fissa la larghezza a",
146
153
  "Font": "Carattere",
147
154
  "Format": "Formato",
148
155
  "fr": "Francese",
@@ -378,6 +385,7 @@
378
385
  "selectStrokeColor": "Colore del tratto di selezione",
379
386
  "Send": "Invia",
380
387
  "Send message": "Invia messaggio",
388
+ "Settings": "Impostazioni",
381
389
  "Shadows": "Ombre",
382
390
  "Share this map": "Condividi questa mappa",
383
391
  "share-panel": "Condividi o incorpora la mappa",
@@ -9,7 +9,7 @@ declare abstract class GirafeHTMLElement extends HTMLElement {
9
9
  protected template: Hole | (() => Hole);
10
10
  readonly name: string;
11
11
  protected shadow: ShadowRoot;
12
- private displayStyle?;
12
+ protected displayStyle?: string;
13
13
  private timeoutId?;
14
14
  protected rendered: boolean;
15
15
  private readonly callbacks;
File without changes
@@ -11,13 +11,13 @@ export default class CesiumDrawing {
11
11
  scene: Cesium.Scene | undefined;
12
12
  handler: Cesium.ScreenSpaceEventHandler | undefined;
13
13
  entities: Cesium.EntityCollection | undefined;
14
- fixedLength: number;
14
+ fixedLineLength: number;
15
15
  private readonly context;
16
16
  private get state();
17
17
  private get drawingState();
18
18
  private get config();
19
19
  constructor(map: MapComponent, toolName: string, context: IGirafeContext);
20
- setFixedLength(length: number): void;
20
+ setFixedLineLength(length: number): void;
21
21
  activateTool(tool: DrawingShape): void;
22
22
  deactivateTool(): void;
23
23
  pickOnGlobe(position: Cartesian2): Cesium.Cartesian3 | undefined;
@@ -13,7 +13,7 @@ export default class CesiumDrawing {
13
13
  scene = undefined;
14
14
  handler = undefined;
15
15
  entities = undefined;
16
- fixedLength = 0;
16
+ fixedLineLength = 0;
17
17
  context;
18
18
  get state() {
19
19
  return this.context.stateManager.state;
@@ -36,8 +36,8 @@ export default class CesiumDrawing {
36
36
  }
37
37
  });
38
38
  }
39
- setFixedLength(length) {
40
- this.fixedLength = Number.isNaN(length) ? 0 : length;
39
+ setFixedLineLength(length) {
40
+ this.fixedLineLength = Number.isNaN(length) ? 0 : length;
41
41
  }
42
42
  activateTool(tool) {
43
43
  if (!this.canExecute('globe.draw')) {
@@ -124,7 +124,7 @@ export default class CesiumDrawing {
124
124
  this.activeShapePoints = [];
125
125
  }
126
126
  fixLastLength(tool, length, coord) {
127
- if (this.fixedLength > 0 && tool != DrawingShape.Rectangle) {
127
+ if (this.fixedLineLength > 0 && tool != DrawingShape.Rectangle) {
128
128
  const factor = tool == DrawingShape.Square ? Math.SQRT2 / 2 : 1;
129
129
  const pointCarto = new EllipsoidGeodesic(Cartographic.fromCartesian(coord[coord.length - 2]), Cartographic.fromCartesian(coord[coord.length - 1])).interpolateUsingSurfaceDistance(length * factor);
130
130
  coord[coord.length - 1] = Cartographic.toCartesian(pointCarto);
@@ -140,7 +140,7 @@ export default class CesiumDrawing {
140
140
  }
141
141
  else {
142
142
  this.activeShapePoints[this.activeShapePoints.length - 1] = newPosition;
143
- this.fixLastLength(tool, this.fixedLength, this.activeShapePoints);
143
+ this.fixLastLength(tool, this.fixedLineLength, this.activeShapePoints);
144
144
  }
145
145
  this.activeShapes.forEach((e) => this.entities.remove(e));
146
146
  this.activeShapes = this.getShapes(tool, this.activeShapePoints, new DrawingFeature(tool, this.drawingState, this.config.drawing));
@@ -7,11 +7,11 @@ export default class DrawingComponentMobile extends DrawingComponent {
7
7
  return uHtml `<style>
8
8
  *{font-family:Arial,sans-serif}.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}.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);width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad2);background-color:var(--text-color-grad2);color:var(--bkg-color)}.gg-button:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3;border:none}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3}.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,.gg-select:hover,.gg-input:hover,.gg-textarea:hover,.gg-icon-button:hover{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}
9
9
  </style><style>
10
- 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}.toolParameters{grid-template-columns:auto auto 60px auto;justify-content:left;align-items:center;margin-top:10px;display:grid}.toolParameters>label{padding:0 5px}#drawingListContainer{flex-grow:1;overflow:hidden auto}#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:2fr 2fr 1fr 4em 1fr 1fr}#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}
10
+ 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:2fr 2fr 1fr 4em 1fr 1fr}#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}
11
11
  </style><style>
12
12
  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}
13
13
  </style>
14
- <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></div><div class="toolParameters"><button id="fixedLengthEnabled" class="gg-icon-button icon" disabled="${!this.fixedLengthOptionAllowed()}" onclick="${() => this.onToggleFixedLength()}">${this.htmlUnsafe(this.fixedLengthEnabled ? this.checkedIcon : this.noCheckedIcon)}</button> <label class="${this.fixedLengthEnabled && this.fixedLengthOptionAllowed() ? 'gg-label' : 'gg-label disabled'}" for="fixedLengthValue" i18n="Fix length to">Fix length to</label> <input class="gg-input" disabled="${!(this.fixedLengthEnabled && this.fixedLengthOptionAllowed())}" type="number" id="fixedLengthValue"> <label class="${this.fixedLengthEnabled && this.fixedLengthOptionAllowed() ? 'gg-label' : 'gg-label disabled'}" disabled="${!(this.fixedLengthEnabled && this.fixedLengthOptionAllowed())}" for="fixedLengthValue" i18n="meters">meters</label></div></div><div id="drawingListContainer"><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 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 i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span i18n="Measures">Measures</span> <button class="gg-icon-button icon" id="visibleIconMeasure" tip="Show or hide measure information" onclick="${() => this.toggleMeasureVisibility()}">${this.htmlUnsafe(this.isDisplayMeasureEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="measureColorPicker"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="text-end" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" 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 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>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.isLineStyleEnabled() ? '' : '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>`;
14
+ <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></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></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 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 i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span i18n="Measures">Measures</span> <button class="gg-icon-button icon" id="visibleIconMeasure" tip="Show or hide measure information" onclick="${() => this.toggleMeasureVisibility()}">${this.htmlUnsafe(this.isDisplayMeasureEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="measureColorPicker"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="text-end" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" 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 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>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.isLineStyleEnabled() ? '' : '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>`;
15
15
  };
16
16
  constructor() {
17
17
  super('drawing-mobile');
@@ -1,5 +1,5 @@
1
1
  import { Color } from 'vanilla-picker';
2
- import DrawingFeature, { DrawingState, DrawingShape, ArrowStyle, ArrowPosition } from './drawingFeature.js';
2
+ import DrawingFeature, { ArrowPosition, ArrowStyle, DrawingShape, DrawingState } from './drawingFeature.js';
3
3
  import OlDrawing from './olDrawing.js';
4
4
  import CesiumDrawing from './cesiumDrawing.js';
5
5
  import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
@@ -42,24 +42,25 @@ export default class DrawingComponent extends GirafeHTMLElement implements IGira
42
42
  unregisterEvents(): void;
43
43
  addColorPicker(id: string, set: (c: Color) => unknown, get: () => string): void;
44
44
  setTool(tool?: DrawingShape | null): void;
45
- fixedLengthOptionAllowed(): boolean;
45
+ showToolParameters(tool?: DrawingShape | null): void;
46
+ protected fixedDimensionValueChangedHandler(e: CustomEvent): void;
46
47
  protected connectedCallback(): void;
47
48
  togglePanel(visible: boolean): void;
48
49
  get selectedFeatures(): DrawingFeature[];
49
50
  deselectAllFeatures(): void;
50
51
  onFeaturesChanged(oldFeatures: DrawingFeature[], newFeatures: DrawingFeature[]): void;
51
52
  onProjectionChanged(oldProj: string, newProj: string): void;
52
- onToggleBatchMode(): void;
53
- onToggleFixedLength(): void;
53
+ protected onToggleBatchMode(): void;
54
54
  onToggleFeatureSelection(feature: DrawingFeature): void;
55
55
  activateLayerInTreeAndMap(layerName?: string): void;
56
56
  deactivateLayerInTreeAnMap(): void;
57
- getOptionsTitle(): string;
58
- isDisplayNameEnabled(): boolean;
59
- isDisplayMeasureEnabled(): boolean;
60
- isLineStyleEnabled(): boolean;
61
- isFillColorEnabled(): boolean;
57
+ protected getOptionsTitle(): string;
58
+ protected isDisplayNameEnabled(): boolean;
59
+ protected isDisplayMeasureEnabled(): boolean;
60
+ protected isLineStyleEnabled(): boolean;
61
+ protected isFillColorEnabled(): boolean;
62
62
  deleteFeature(feature: DrawingFeature): Promise<void>;
63
+ deleteAllFeatures(): Promise<void>;
63
64
  onOptionsChange(): void;
64
65
  onArrowsChange(): void;
65
66
  toggleNameVisibility(): void;
@@ -1,10 +1,16 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
1
7
  import { htmlFor as uHtmlFor } from 'uhtml/keyed';
2
8
  import { html as uHtml } from 'uhtml';
3
9
  import { v4 as uuidv4 } from 'uuid';
4
10
  import DrawingFeature, { DrawingShape } from './drawingFeature.js';
5
11
  import OlDrawing from './olDrawing.js';
6
12
  import CesiumDrawing from './cesiumDrawing.js';
7
- import { KML, GeoJSON, GPX } from 'ol/format.js';
13
+ import { GeoJSON, GPX, KML } from 'ol/format.js';
8
14
  import { Polygon } from 'ol/geom.js';
9
15
  import Feature from 'ol/Feature.js';
10
16
  import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
@@ -18,14 +24,15 @@ import locateIcon from './assets/locate.svg?raw';
18
24
  import visibleIcon from './assets/visible.svg?raw';
19
25
  import notVisibleIcon from './assets/notVisible.svg?raw';
20
26
  import LayerDrawing from '../../models/layers/layerdrawing.js';
27
+ import { UsedInTemplateOnly } from '../../decorators.js';
21
28
  export default class DrawingComponent extends GirafeHTMLElement {
22
29
  template = () => {
23
30
  return uHtml `<style>
24
31
  *{font-family:Arial,sans-serif}.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}.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);width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad2);background-color:var(--text-color-grad2);color:var(--bkg-color)}.gg-button:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3;border:none}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3}.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,.gg-select:hover,.gg-input:hover,.gg-textarea:hover,.gg-icon-button:hover{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}
25
32
  </style><style>
26
- 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}.toolParameters{grid-template-columns:auto auto 60px auto;justify-content:left;align-items:center;margin-top:10px;display:grid}.toolParameters>label{padding:0 5px}#drawingListContainer{flex-grow:1;overflow:hidden auto}#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:2fr 2fr 1fr 4em 1fr 1fr}#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}
33
+ 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:2fr 2fr 1fr 4em 1fr 1fr}#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}
27
34
  </style>
28
- <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></div><div class="toolParameters"><button id="fixedLengthEnabled" class="gg-icon-button icon" disabled="${!this.fixedLengthOptionAllowed()}" onclick="${() => this.onToggleFixedLength()}">${this.htmlUnsafe(this.fixedLengthEnabled ? this.checkedIcon : this.noCheckedIcon)}</button> <label class="${this.fixedLengthEnabled && this.fixedLengthOptionAllowed() ? 'gg-label' : 'gg-label disabled'}" for="fixedLengthValue" i18n="Fix length to">Fix length to</label> <input class="gg-input" disabled="${!(this.fixedLengthEnabled && this.fixedLengthOptionAllowed())}" type="number" id="fixedLengthValue"> <label class="${this.fixedLengthEnabled && this.fixedLengthOptionAllowed() ? 'gg-label' : 'gg-label disabled'}" disabled="${!(this.fixedLengthEnabled && this.fixedLengthOptionAllowed())}" for="fixedLengthValue" i18n="meters">meters</label></div></div><div id="drawingListContainer"><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 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 i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span i18n="Measures">Measures</span> <button class="gg-icon-button icon" id="visibleIconMeasure" tip="Show or hide measure information" onclick="${() => this.toggleMeasureVisibility()}">${this.htmlUnsafe(this.isDisplayMeasureEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="measureColorPicker"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="text-end" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" 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 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>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.isLineStyleEnabled() ? '' : '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>`;
35
+ <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></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></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 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 i18n="Font">Font</span> <input id="optionsNameFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.nameFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="nameColorPicker"></button> <span i18n="Measures">Measures</span> <button class="gg-icon-button icon" id="visibleIconMeasure" tip="Show or hide measure information" onclick="${() => this.toggleMeasureVisibility()}">${this.htmlUnsafe(this.isDisplayMeasureEnabled() ? this.visibleIcon : this.notVisibleIcon)}</button> <span i18n="Font">Font</span> <input id="optionsMeasuresFontSize" class="gg-input" type="number" min="1" value="${this.selectedFeatures[0]?.measureFontSize}" oninput="${() => this.onOptionsChange()}"> <span>pt</span> <button class="icon colorPicker" id="measureColorPicker"></button></div></div><hr><div id="optionsColor"><div id="optionsColorLine"><div><span class="text-end" i18n="Stroke color">Stroke color</span> <button class="icon colorPicker" 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 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>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.isLineStyleEnabled() ? '' : '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>`;
29
36
  };
30
37
  isPanelVisible = false;
31
38
  panelTitle = 'drawing-panel';
@@ -111,24 +118,6 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
111
118
  this.selectedFeatures[0].name = e.target.value;
112
119
  this.refreshRender();
113
120
  };
114
- this.getById('fixedLengthValue').oninput = (e) => {
115
- const val = parseFloat(e.target.value);
116
- this.olDrawing.setFixedLength(val);
117
- this.cesiumDrawing.setFixedLength(val);
118
- };
119
- this.getById('fixedLengthEnabled').onchange = (e) => {
120
- const elements = Array.from(this.shadowRoot.querySelectorAll('.fixedLengthElement'));
121
- const option = e.target;
122
- if (!option.disabled && option.checked) {
123
- elements.forEach((e) => e.classList.remove('disabled'));
124
- this.getById('fixedLengthValue').dispatchEvent(new Event('input'));
125
- }
126
- else {
127
- elements.forEach((e) => e.classList.add('disabled'));
128
- this.olDrawing.setFixedLength(0);
129
- this.cesiumDrawing.setFixedLength(0);
130
- }
131
- };
132
121
  this.setTool();
133
122
  }
134
123
  this.warnWhenInWebMercator();
@@ -172,16 +161,39 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
172
161
  this.toolSelected = this.getById(this.buttons.find((x) => x.tool == tool).id);
173
162
  this.toolSelected.classList.add('selected');
174
163
  this.drawingState.activeTool = tool;
175
- }
176
- fixedLengthOptionAllowed() {
177
- // Enable / disable fix length checkbox based on current tool
178
- return ![
179
- null,
180
- DrawingShape.Point,
181
- DrawingShape.Rectangle,
182
- DrawingShape.FreehandPolyline,
183
- DrawingShape.FreehandPolygon
184
- ].includes(this.drawingState.activeTool);
164
+ this.showToolParameters(tool);
165
+ }
166
+ showToolParameters(tool = null) {
167
+ const toolName = tool ? DrawingShape[tool] : 'Pointer';
168
+ const toolParametersList = this.shadowRoot.querySelectorAll('.toolParameters');
169
+ let hasParameters = false;
170
+ toolParametersList.forEach((toolParameters) => {
171
+ const isParametersForTool = toolParameters.dataset.tool?.includes(toolName) ?? false;
172
+ toolParameters.style.display = isParametersForTool ? 'flex' : 'none';
173
+ hasParameters ||= isParametersForTool;
174
+ });
175
+ this.shadow.querySelector('#toolParametersContainer span.title').style.display = hasParameters
176
+ ? 'inline-block'
177
+ : 'none';
178
+ }
179
+ fixedDimensionValueChangedHandler(e) {
180
+ const details = e.detail;
181
+ switch (details.id) {
182
+ case 'fixedLineLength':
183
+ this.olDrawing.setFixedLineLength(details.value);
184
+ break;
185
+ case 'fixedSquareSide':
186
+ this.olDrawing.setFixedSquareSide(details.value);
187
+ break;
188
+ case 'fixedRectangleWidth':
189
+ this.olDrawing.setFixedRectangleWidth(details.value);
190
+ break;
191
+ case 'fixedRectangleHeight':
192
+ this.olDrawing.setFixedRectangleHeight(details.value);
193
+ break;
194
+ default:
195
+ console.debug('Value changed for unknown Dimension with id', details.id);
196
+ }
185
197
  }
186
198
  connectedCallback() {
187
199
  super.connectedCallback();
@@ -287,20 +299,12 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
287
299
  }
288
300
  }
289
301
  onToggleBatchMode() {
290
- // Currently not used, will possibly be part of advanced editing/drawing tools
291
302
  this.batchCreateMode = !this.batchCreateMode;
292
303
  if (this.batchCreateMode) {
293
304
  this.deselectAllFeatures();
294
305
  }
295
306
  this.refreshRender();
296
307
  }
297
- onToggleFixedLength() {
298
- this.fixedLengthEnabled = !this.fixedLengthEnabled;
299
- const val = this.fixedLengthEnabled ? parseFloat(this.getById('fixedLengthValue').value) : 0;
300
- this.olDrawing.setFixedLength(val);
301
- this.cesiumDrawing.setFixedLength(val);
302
- this.refreshRender();
303
- }
304
308
  onToggleFeatureSelection(feature) {
305
309
  this.setTool(null);
306
310
  feature.selected = !feature.selected;
@@ -349,6 +353,13 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
349
353
  }
350
354
  }
351
355
  }
356
+ async deleteAllFeatures() {
357
+ const confirm = await window.gConfirm('Do you want to remove all features?', 'Delete Features');
358
+ if (confirm) {
359
+ this.drawingState.features = [];
360
+ this.refreshRender();
361
+ }
362
+ }
352
363
  onOptionsChange() {
353
364
  const nameFontSize = parseInt(this.getById('optionsNameFontSize').value);
354
365
  const measureFontSize = parseInt(this.getById('optionsMeasuresFontSize').value);
@@ -413,3 +424,24 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
413
424
  }
414
425
  }
415
426
  }
427
+ __decorate([
428
+ UsedInTemplateOnly()
429
+ ], DrawingComponent.prototype, "fixedDimensionValueChangedHandler", null);
430
+ __decorate([
431
+ UsedInTemplateOnly('Currently not used, will possibly be part of advanced editing/drawing tools')
432
+ ], DrawingComponent.prototype, "onToggleBatchMode", null);
433
+ __decorate([
434
+ UsedInTemplateOnly()
435
+ ], DrawingComponent.prototype, "getOptionsTitle", null);
436
+ __decorate([
437
+ UsedInTemplateOnly()
438
+ ], DrawingComponent.prototype, "isDisplayNameEnabled", null);
439
+ __decorate([
440
+ UsedInTemplateOnly()
441
+ ], DrawingComponent.prototype, "isDisplayMeasureEnabled", null);
442
+ __decorate([
443
+ UsedInTemplateOnly()
444
+ ], DrawingComponent.prototype, "isLineStyleEnabled", null);
445
+ __decorate([
446
+ UsedInTemplateOnly()
447
+ ], DrawingComponent.prototype, "isFillColorEnabled", null);
@@ -1,6 +1,6 @@
1
1
  import { Style } from 'ol/style.js';
2
2
  import type { IBrainSerializable } from '../../tools/state/brain/decorators.js';
3
- import type { Geometry } from 'ol/geom.js';
3
+ import type { Circle as CircleGeom, Geometry } from 'ol/geom.js';
4
4
  import type Feature from 'ol/Feature.js';
5
5
  import IGirafeContext from '../../tools/context/icontext.js';
6
6
  export declare enum DrawingShape {
@@ -99,6 +99,7 @@ export default class DrawingFeature {
99
99
  getLengthText(length: number): string;
100
100
  getAreaText(area: number): string;
101
101
  getCoordText(coord: number[]): string;
102
+ getAzimuthText(circle: CircleGeom): string;
102
103
  isPointOrPolyline(): boolean;
103
104
  getVertexStyle(activeNode?: boolean): Style;
104
105
  static deserialize(serializedFeature: SerializedFeature, context: IGirafeContext): DrawingFeature;
@@ -3,7 +3,7 @@ import { v4 as uuidv4 } from 'uuid';
3
3
  import { Fill, RegularShape, Stroke, Style } from 'ol/style.js';
4
4
  import { toRadians } from 'ol/math.js';
5
5
  import GeoJSON from 'ol/format/GeoJSON.js';
6
- import { getAreaAsMetricText, getLengthAsMetricText } from '../../tools/utils/olutils.js';
6
+ import { getAreaAsMetricText, getAzimuthAsText, getLengthAsMetricText } from '../../tools/utils/olutils.js';
7
7
  export var DrawingShape;
8
8
  (function (DrawingShape) {
9
9
  DrawingShape[DrawingShape["Point"] = 0] = "Point";
@@ -203,6 +203,9 @@ export default class DrawingFeature {
203
203
  }
204
204
  return 'E ' + coord[0].toFixed(2) + '\nN ' + coord[1].toFixed(2);
205
205
  }
206
+ getAzimuthText(circle) {
207
+ return getAzimuthAsText(this.displayMeasure ? circle.getProperties()['azimuth'] ?? undefined : undefined);
208
+ }
206
209
  isPointOrPolyline() {
207
210
  return (this.type === DrawingShape.Point ||
208
211
  this.type === DrawingShape.Polyline ||
@@ -259,12 +262,17 @@ export default class DrawingFeature {
259
262
  static geojsonFromOlFeature(olFeature, shapeType) {
260
263
  if (shapeType === DrawingShape.Disk) {
261
264
  const disk = olFeature.getGeometry();
265
+ const center = disk.getCenter();
266
+ const radius = disk.getRadius();
267
+ const pointer = disk.getProperties()['pointer'] ?? [center[0] + radius, center[1]];
262
268
  return {
263
269
  type: 'Feature',
264
270
  geometry: {
265
271
  type: 'Disk',
266
- center: disk.getCenter(),
267
- radius: disk.getRadius()
272
+ center: center,
273
+ radius: radius,
274
+ azimuth: disk.getProperties()['azimuth'] ?? 0,
275
+ pointer: pointer,
268
276
  }
269
277
  };
270
278
  }
@@ -0,0 +1,39 @@
1
+ import GirafeHTMLElement from '../../../base/GirafeHTMLElement.js';
2
+ export type FixedDimensionValueChangedEventDetails = {
3
+ id: string;
4
+ dimension: string;
5
+ value: number;
6
+ };
7
+ export type DimensionUnit = {
8
+ name: string;
9
+ factor: number;
10
+ };
11
+ declare class FixedDimensionComponent extends GirafeHTMLElement {
12
+ static readonly observedAttributes: string[];
13
+ template: () => import("uhtml").Hole;
14
+ checkedIcon: string;
15
+ notCheckedIcon: string;
16
+ dimensionName: string;
17
+ dimension: string;
18
+ dimensionUnits: string;
19
+ onChange: string;
20
+ fixedDimensionEnabled: boolean;
21
+ renderedOnce: boolean;
22
+ lastValue: string;
23
+ units: DimensionUnit[];
24
+ unit: DimensionUnit | undefined;
25
+ constructor(name?: string);
26
+ render(): void;
27
+ private renderComponent;
28
+ protected connectedCallback(): void;
29
+ private refreshDimensionName;
30
+ private refreshDimension;
31
+ private refreshDimensionUnits;
32
+ private refreshOnChange;
33
+ toggleFixedDimensionEnabled(): void;
34
+ fixedValueChanged(e: InputEvent): void;
35
+ dimensionUnitChanged(e: Event): void;
36
+ dispatchFixedDimensionValueChangedEvent(valueAsString: string): void;
37
+ protected attributeChangedCallback(name: string, _oldValue: string, newValue: string): void;
38
+ }
39
+ export default FixedDimensionComponent;
@@ -0,0 +1,123 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { html as uHtml } from 'uhtml';
8
+ import GirafeHTMLElement from '../../../base/GirafeHTMLElement.js';
9
+ import checkedIcon from '../../../assets/icons/checked-full.svg?raw';
10
+ import checkedNoIcon from '../../../assets/icons/checked-no.svg?raw';
11
+ import { UsedInTemplateOnly } from '../../../decorators.js';
12
+ const defaultUnits = 'm:1;km:1000';
13
+ class FixedDimensionComponent extends GirafeHTMLElement {
14
+ static observedAttributes = ['dimensionName', 'dimension', 'dimensionUnits', 'onChange'];
15
+ template = () => {
16
+ return uHtml `<style>
17
+ *{font-family:Arial,sans-serif}.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}.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);width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad2);background-color:var(--text-color-grad2);color:var(--bkg-color)}.gg-button:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3;border:none}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3}.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,.gg-select:hover,.gg-input:hover,.gg-textarea:hover,.gg-icon-button:hover{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}
18
+ </style><style>
19
+ :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}}
20
+ </style>
21
+ <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>`;
22
+ };
23
+ checkedIcon = checkedIcon;
24
+ notCheckedIcon = checkedNoIcon;
25
+ dimensionName = 'dimension';
26
+ dimension = 'dimension';
27
+ dimensionUnits = defaultUnits;
28
+ onChange = '';
29
+ fixedDimensionEnabled = false;
30
+ renderedOnce = false;
31
+ lastValue = '0';
32
+ units = [];
33
+ unit = undefined;
34
+ constructor(name = 'fixed-dimension') {
35
+ super(name);
36
+ this.displayStyle = 'grid';
37
+ }
38
+ render() {
39
+ super.render();
40
+ this.refreshDimensionName();
41
+ this.refreshDimension();
42
+ this.refreshDimensionUnits();
43
+ this.refreshOnChange();
44
+ this.renderComponent();
45
+ super.girafeTranslate();
46
+ }
47
+ renderComponent() {
48
+ this.show();
49
+ if (!this.renderedOnce) {
50
+ this.renderedOnce = true;
51
+ }
52
+ }
53
+ connectedCallback() {
54
+ super.connectedCallback();
55
+ this.render();
56
+ }
57
+ refreshDimensionName() {
58
+ this.dimensionName = this.getAttribute('dimensionName') ?? 'dimension';
59
+ this.refreshRender();
60
+ }
61
+ refreshDimension() {
62
+ this.dimension = this.getAttribute('dimension') ?? 'dimension';
63
+ }
64
+ refreshDimensionUnits(dimensionUnits = defaultUnits) {
65
+ console.log(`Refreshing dimension units for ${this.dimension} with units ${dimensionUnits}`);
66
+ this.dimensionUnits = dimensionUnits ?? this.getAttribute('dimensionUnits') ?? defaultUnits;
67
+ this.units = this.dimensionUnits.split(';').map((unit) => {
68
+ const [name, factor] = unit.split(':');
69
+ return { name, factor: Number.parseFloat(factor) };
70
+ });
71
+ this.unit = this.units[0];
72
+ this.refreshRender();
73
+ }
74
+ refreshOnChange() {
75
+ this.onChange = this.getAttribute('onChange') ?? '';
76
+ console.log(`Refreshing onChange for ${this.dimension} with onChange ${this.onChange}`);
77
+ }
78
+ toggleFixedDimensionEnabled() {
79
+ this.fixedDimensionEnabled = !this.fixedDimensionEnabled;
80
+ this.dispatchFixedDimensionValueChangedEvent(this.fixedDimensionEnabled ? this.lastValue : '0');
81
+ this.refreshRender();
82
+ }
83
+ fixedValueChanged(e) {
84
+ this.lastValue = e.target.value;
85
+ this.dispatchFixedDimensionValueChangedEvent(this.lastValue);
86
+ this.htmlUnsafe(this.onChange);
87
+ }
88
+ dimensionUnitChanged(e) {
89
+ const selectedUnitFactor = Number.parseFloat(e.target.value);
90
+ this.unit = this.units.find((unit) => unit.factor == selectedUnitFactor);
91
+ this.dispatchFixedDimensionValueChangedEvent(this.lastValue);
92
+ }
93
+ dispatchFixedDimensionValueChangedEvent(valueAsString) {
94
+ const value = Number.parseFloat(valueAsString);
95
+ this.dispatchEvent(new CustomEvent('fixed-dimension:value-changed', {
96
+ bubbles: true,
97
+ cancelable: true,
98
+ detail: {
99
+ id: this.id,
100
+ dimension: this.dimension,
101
+ value: value * (this.unit?.factor ?? 1)
102
+ }
103
+ }));
104
+ }
105
+ attributeChangedCallback(name, _oldValue, newValue) {
106
+ if (name === 'dimensionName') {
107
+ this.dimensionName = newValue;
108
+ }
109
+ else if (name === 'dimension') {
110
+ this.dimension = newValue;
111
+ }
112
+ else if (name === 'dimensionUnits') {
113
+ this.refreshDimensionUnits(newValue);
114
+ }
115
+ else if (name === 'onChange') {
116
+ this.onChange = newValue;
117
+ }
118
+ }
119
+ }
120
+ __decorate([
121
+ UsedInTemplateOnly('attributeChangedCallback is not used in this component, but it is required by the HTMLElement interface.')
122
+ ], FixedDimensionComponent.prototype, "attributeChangedCallback", null);
123
+ export default FixedDimensionComponent;
@@ -24,7 +24,10 @@ export default class OlDrawing {
24
24
  snap: Snap | null;
25
25
  editContextMenu: ContextMenu | null;
26
26
  currentShape: DrawingShape | null;
27
- fixedLength: number;
27
+ fixedLineLength: number;
28
+ fixedSquareSide: number;
29
+ fixedRectangleWidth: number;
30
+ fixedRectangleHeight: number;
28
31
  drawingSource: VectorSource;
29
32
  drawingLayer: VectorLayer;
30
33
  lastClosestFeature: Feature | null;
@@ -97,11 +100,15 @@ export default class OlDrawing {
97
100
  private getOlFeatureFromDrawingSource;
98
101
  private isOlFeatureInState;
99
102
  createOlFeature(dFeature: DrawingFeature): Feature<Geometry>;
100
- setFixedLength(length: number): void;
103
+ setFixedLineLength(length: number): void;
104
+ setFixedSquareSide(length: number): void;
105
+ setFixedRectangleWidth(width: number): void;
106
+ setFixedRectangleHeight(height: number): void;
101
107
  createLineStringFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry): SimpleGeometry;
102
108
  createSquareFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry, proj: Projection): SimpleGeometry;
103
109
  createPolygonFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry): SimpleGeometry;
104
110
  createDiskFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry): SimpleGeometry;
111
+ createRectangleFixedSides(coordinates: SketchCoordType, geom: SimpleGeometry, proj: Projection): SimpleGeometry;
105
112
  addDrawInteraction(tool: DrawingShape): void;
106
113
  centerViewOnFeature(drawingFeature: DrawingFeature): void;
107
114
  getStyle(dFeature: DrawingFeature, olFeature: Feature<Geometry>): Style[];
@@ -59,7 +59,10 @@ export default class OlDrawing {
59
59
  snap = null;
60
60
  editContextMenu = null;
61
61
  currentShape = null;
62
- fixedLength = 0;
62
+ fixedLineLength = 0;
63
+ fixedSquareSide = 0;
64
+ fixedRectangleWidth = 0;
65
+ fixedRectangleHeight = 0;
63
66
  drawingSource;
64
67
  drawingLayer;
65
68
  lastClosestFeature = null;
@@ -138,6 +141,25 @@ export default class OlDrawing {
138
141
  pixelTolerance: this.map.pixelTolerance
139
142
  });
140
143
  this.map.olMap.addInteraction(this.modify);
144
+ this.modify.on('modifystart', (e) => {
145
+ e.features.forEach((olFeature) => {
146
+ olFeature.on('change', (e) => {
147
+ const geometry = e.target.getGeometry();
148
+ if (geometry && geometry.getType() == 'Circle') {
149
+ const circle = geometry;
150
+ const newRadius = circle.getRadius();
151
+ const properties = circle.getProperties();
152
+ const { pointer } = properties;
153
+ const oldRadiusLine = new LineString([circle.getCenter(), pointer]);
154
+ oldRadiusLine.scale(newRadius / oldRadiusLine.getLength());
155
+ circle.setProperties({
156
+ ...properties,
157
+ pointer: oldRadiusLine.getLastCoordinate()
158
+ });
159
+ }
160
+ });
161
+ });
162
+ });
141
163
  // Update the modified geometries in the state
142
164
  this.modify.on('modifyend', (e) => {
143
165
  e.features.forEach((olFeature) => this.updateGeometryInState(olFeature)); //NOSONAR(typescript:S7728) Collection<?> is a custom Implementation with custom forEach
@@ -434,7 +456,12 @@ export default class OlDrawing {
434
456
  const geometry = dFeature.geojson.geometry;
435
457
  let olFeature;
436
458
  if (geometry.type == 'Disk') {
437
- olFeature = new Feature(new CircleGeom(geometry.center, geometry.radius));
459
+ const geom = new CircleGeom(geometry.center, geometry.radius);
460
+ geom.setProperties({
461
+ azimuth: geometry.azimuth,
462
+ pointer: geometry.pointer
463
+ });
464
+ olFeature = new Feature(geom);
438
465
  }
439
466
  else {
440
467
  olFeature = new Feature(new GeoJSON().readFeatures(dFeature.geojson)[0].getGeometry());
@@ -443,33 +470,91 @@ export default class OlDrawing {
443
470
  olFeature.setStyle((f) => this.getStyle(dFeature, f));
444
471
  return olFeature;
445
472
  }
446
- setFixedLength(length) {
447
- this.fixedLength = Number.isNaN(length) ? 0 : length;
473
+ setFixedLineLength(length) {
474
+ this.fixedLineLength = Number.isNaN(length) ? 0 : length;
475
+ }
476
+ setFixedSquareSide(length) {
477
+ this.fixedSquareSide = Number.isNaN(length) ? 0 : length;
478
+ }
479
+ setFixedRectangleWidth(width) {
480
+ this.fixedRectangleWidth = Number.isNaN(width) ? 0 : width;
481
+ }
482
+ setFixedRectangleHeight(height) {
483
+ this.fixedRectangleHeight = Number.isNaN(height) ? 0 : height;
448
484
  }
449
485
  createLineStringFixedLength(coordinates, geom) {
450
- this.fixLastLength(this.fixedLength, coordinates);
486
+ this.fixLastLength(this.fixedLineLength, coordinates);
451
487
  geom = geom ?? new LineString(coordinates);
452
488
  geom.setCoordinates(coordinates);
453
489
  return geom;
454
490
  }
455
491
  createSquareFixedLength(coordinates, geom, proj) {
456
- this.fixLastLength(this.fixedLength, coordinates, Math.SQRT2);
457
- return createRegularPolygon(4)(coordinates, geom, proj);
492
+ this.fixLastLength(this.fixedSquareSide, coordinates, Math.SQRT2);
493
+ const poly = createRegularPolygon(4)(coordinates, geom, proj);
494
+ console.log('createSquareFixedLength ' + JSON.stringify(poly.getCoordinates()));
495
+ return poly;
458
496
  }
459
497
  createPolygonFixedLength(coordinates, geom) {
460
498
  const coord = coordinates[0];
461
- this.fixLastLength(this.fixedLength, coord);
499
+ this.fixLastLength(this.fixedLineLength, coord);
462
500
  geom = geom ?? new Polygon([coord]);
463
501
  geom.setCoordinates([coord]);
464
502
  return geom;
465
503
  }
466
504
  createDiskFixedLength(coordinates, geom) {
467
505
  const coord = coordinates;
468
- this.fixLastLength(this.fixedLength, coord);
506
+ this.fixLastLength(this.fixedLineLength, coord);
469
507
  geom = geom ?? new CircleGeom(coord[0], getDistance(coord, this.state.projection));
470
508
  geom.setCenterAndRadius(coord[0], getDistance(coord, this.state.projection));
509
+ geom.setProperties({
510
+ azimuth: ((90 - (Math.atan2(coord[1][1] - coord[0][1], coord[1][0] - coord[0][0]) * (180 / Math.PI)) + 360) % 360),
511
+ pointer: coord[1]
512
+ });
471
513
  return geom;
472
514
  }
515
+ createRectangleFixedSides(coordinates, geom, proj) {
516
+ if (coordinates.length < 2) {
517
+ geom = geom ?? createBox()(coordinates, geom, proj);
518
+ return geom;
519
+ }
520
+ // If no fixed dimensions are set, behave like the normal box drawing.
521
+ if (this.fixedRectangleWidth <= 0 && this.fixedRectangleHeight <= 0) {
522
+ geom = geom ?? createBox()(coordinates, geom, proj);
523
+ return createBox()(coordinates, geom, proj);
524
+ }
525
+ const coords = coordinates;
526
+ const start = coords[0];
527
+ const pointer = coords[1];
528
+ // Decide in which quadrant the user is dragging.
529
+ const signX = pointer[0] >= start[0] ? 1 : -1;
530
+ const signY = pointer[1] >= start[1] ? 1 : -1;
531
+ // Convert "meters" (or whatever your getDistance returns) to map units along X and Y.
532
+ const xUnit = [start[0] + 1, start[1]];
533
+ const yUnit = [start[0], start[1] + 1];
534
+ const metersPerMapUnitX = getDistance([start, xUnit], this.state.projection);
535
+ const metersPerMapUnitY = getDistance([start, yUnit], this.state.projection);
536
+ // Guard against division by 0 in weird edge cases.
537
+ if (metersPerMapUnitX <= 0 || metersPerMapUnitY <= 0) {
538
+ geom = geom ?? createBox()(coordinates, geom, proj);
539
+ return createBox()(coordinates, geom, proj);
540
+ }
541
+ const dxMapUnits = (this.fixedRectangleWidth / metersPerMapUnitX) * signX;
542
+ const dyMapUnits = (this.fixedRectangleHeight / metersPerMapUnitY) * signY;
543
+ if (dxMapUnits != 0 && dyMapUnits != 0) {
544
+ // Overwrite width and height
545
+ coords[1] = [start[0] + dxMapUnits, start[1] + dyMapUnits];
546
+ }
547
+ else if (dxMapUnits != 0) {
548
+ // Overwrite only width
549
+ coords[1] = [start[0] + dxMapUnits, pointer[1]];
550
+ }
551
+ else if (dyMapUnits != 0) {
552
+ // Overwrite only height
553
+ coords[1] = [pointer[0], start[1] + dyMapUnits];
554
+ }
555
+ geom = geom ?? createBox()(coords, geom, proj);
556
+ return createBox()(coords, geom, proj);
557
+ }
473
558
  addDrawInteraction(tool) {
474
559
  this.removeDrawInteraction();
475
560
  // Block feature selection while drawing by registering 'map.select' exclusively
@@ -499,7 +584,7 @@ export default class OlDrawing {
499
584
  break;
500
585
  case DrawingShape.Rectangle:
501
586
  olTool = 'Circle';
502
- geomFunction = createBox();
587
+ geomFunction = this.createRectangleFixedSides.bind(this);
503
588
  break;
504
589
  case DrawingShape.FreehandPolyline:
505
590
  olTool = 'LineString';
@@ -661,12 +746,13 @@ export default class OlDrawing {
661
746
  addLabel(polygon.getInteriorPoint(), dFeature.getAreaText(getAreaOfPolygon(polygon, this.state.projection)));
662
747
  }
663
748
  else if (dFeature.type == DrawingShape.Disk) {
664
- const radiusDataForCircle = getRadiusDataForCircle(geometry, defaultStyle, new Stroke({ color: measureColor, width: dFeature.strokeWidth }));
665
- if (!dFeature.displayMeasure) {
666
- radiusDataForCircle.style.setGeometry(new LineString([]));
749
+ if (dFeature.displayMeasure) {
750
+ const radiusDataForCircle = getRadiusDataForCircle(geometry, defaultStyle, new Stroke({ color: measureColor, width: dFeature.strokeWidth }));
751
+ styles.push(radiusDataForCircle.style);
752
+ const lengthText = dFeature.getLengthText(radiusDataForCircle.radius);
753
+ const azimuthText = dFeature.getAzimuthText(geometry);
754
+ addLabel(getHalfPoint(radiusDataForCircle.radiusLine), `${lengthText}, ${azimuthText}`);
667
755
  }
668
- styles.push(radiusDataForCircle.style);
669
- addLabel(getHalfPoint(radiusDataForCircle.radiusLine), dFeature.getLengthText(radiusDataForCircle.radius));
670
756
  }
671
757
  else if (dFeature.type == DrawingShape.FreehandPolygon) {
672
758
  const polygon = geometry;
@@ -12,6 +12,8 @@ export { default as CrossSectionViewComponent } from './cross-section/cross-sect
12
12
  export { default as DisplayMenuButtonMobile } from './displaymenubutton-mobile/component.js';
13
13
  export { default as DisplaySelectorButtonMobile } from './displayselectorbutton-mobile/component.js';
14
14
  export { default as DrawingComponent } from './drawing/component.js';
15
+ export type { FixedDimensionValueChangedEventDetails, DimensionUnit } from './drawing/fixed-dimension/component.js';
16
+ export { default as FixedDimensionComponent } from './drawing/fixed-dimension/component.js';
15
17
  export { default as DrawingContainerMobile } from './drawing-container-mobile/component.js';
16
18
  export { default as EditComponent } from './edit/component.js';
17
19
  export { default as EditFromComponent } from './edit/editform/component.js';
@@ -12,6 +12,7 @@ export { default as CrossSectionViewComponent } from './cross-section/cross-sect
12
12
  export { default as DisplayMenuButtonMobile } from './displaymenubutton-mobile/component.js';
13
13
  export { default as DisplaySelectorButtonMobile } from './displayselectorbutton-mobile/component.js';
14
14
  export { default as DrawingComponent } from './drawing/component.js';
15
+ export { default as FixedDimensionComponent } from './drawing/fixed-dimension/component.js';
15
16
  export { default as DrawingContainerMobile } from './drawing-container-mobile/component.js';
16
17
  export { default as EditComponent } from './edit/component.js';
17
18
  export { default as EditFromComponent } from './edit/editform/component.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Use this Decorator to mark a Method that seems unused but is used in the HTML Template.
3
+ * @constructor
4
+ */
5
+ export declare function UsedInTemplateOnly(_reason?: string): (_target: object, _propertyKey: string, _descriptor: PropertyDescriptor) => void;
package/decorators.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Use this Decorator to mark a Method that seems unused but is used in the HTML Template.
3
+ * @constructor
4
+ */
5
+ export function UsedInTemplateOnly(_reason = 'Method is used in HTML Template') {
6
+ return function (_target, _propertyKey, _descriptor) { };
7
+ }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geomapfish.dev"
7
7
  },
8
- "version": "1.1.0-dev.2433737633",
8
+ "version": "1.1.0-dev.2438378072",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -1 +1 @@
1
- {"version":"1.1.0-dev.2433737633", "build":"2433737633", "date":"07/04/2026"}
1
+ {"version":"1.1.0-dev.2438378072", "build":"2438378072", "date":"08/04/2026"}
@@ -47,6 +47,7 @@ import { DrawingState } from '../../components/drawing/drawingFeature.js';
47
47
  import DrawingSerializer from '../../components/drawing/drawingSerializer.js';
48
48
  import { ShareState, ShareStateSerializer } from '../../components/share/sharestate.js';
49
49
  import SelectionToolComponent from '../../components/selectiontool/component.js';
50
+ import FixedDimensionComponent from '../../components/drawing/fixed-dimension/component.js';
50
51
  export default class GeoGirafeApp {
51
52
  readyPromise;
52
53
  resolveReady;
@@ -138,6 +139,7 @@ export default class GeoGirafeApp {
138
139
  customElements.define('girafe-tree-view-theme', TreeViewThemeComponent);
139
140
  customElements.define('girafe-user-preferences', UserPreferencesComponent);
140
141
  customElements.define('girafe-video-record', VideoRecordComponent);
142
+ customElements.define('girafe-fixed-dimension', FixedDimensionComponent);
141
143
  }
142
144
  async initializeServiceWorker() {
143
145
  try {
package/tools/main.d.ts CHANGED
@@ -106,7 +106,7 @@ export { default as UserDataManager } from './userdata/userdatamanager.js';
106
106
  export { default as ColumnAliasHelper } from './utils/aliases.js';
107
107
  export { debounce } from './utils/debounce.js';
108
108
  export { default as GirafeColorPicker } from './utils/girafecolorpicker.js';
109
- export { unByKeyAll, getOlayerByName, removeUnwantedOlParams, polygonFromCircle, getDistance, getAreaOfPolygon, getAreaOfCircle, isCoordinateInDegrees, getSelectionBoxFromMapClick, reprojectGeometry, ensurePolygonIsProperlyClosed, getHalfPoint, getLabelStyle, getRadiusDataForCircle, getLengthAsMetricText, getAreaAsMetricText } from './utils/olutils.js';
109
+ export { unByKeyAll, getOlayerByName, removeUnwantedOlParams, polygonFromCircle, getDistance, getAreaOfPolygon, getAreaOfCircle, isCoordinateInDegrees, getSelectionBoxFromMapClick, reprojectGeometry, ensurePolygonIsProperlyClosed, getHalfPoint, getLabelStyle, getRadiusDataForCircle, getLengthAsMetricText, getAreaAsMetricText, getAzimuthAsText } from './utils/olutils.js';
110
110
  export { getPropertyByPath, setPropertyByPath, createObjectFromPath, deletePropertyByPath, mergeObjects } from './utils/pathUtils.js';
111
111
  export { generateQrCode } from './utils/qrcode.js';
112
112
  export { default as ServiceWorkerHelper } from './utils/swhelper.js';
package/tools/main.js CHANGED
@@ -81,7 +81,7 @@ export { default as UserDataManager } from './userdata/userdatamanager.js';
81
81
  export { default as ColumnAliasHelper } from './utils/aliases.js';
82
82
  export { debounce } from './utils/debounce.js';
83
83
  export { default as GirafeColorPicker } from './utils/girafecolorpicker.js';
84
- export { unByKeyAll, getOlayerByName, removeUnwantedOlParams, polygonFromCircle, getDistance, getAreaOfPolygon, getAreaOfCircle, isCoordinateInDegrees, getSelectionBoxFromMapClick, reprojectGeometry, ensurePolygonIsProperlyClosed, getHalfPoint, getLabelStyle, getRadiusDataForCircle, getLengthAsMetricText, getAreaAsMetricText } from './utils/olutils.js';
84
+ export { unByKeyAll, getOlayerByName, removeUnwantedOlParams, polygonFromCircle, getDistance, getAreaOfPolygon, getAreaOfCircle, isCoordinateInDegrees, getSelectionBoxFromMapClick, reprojectGeometry, ensurePolygonIsProperlyClosed, getHalfPoint, getLabelStyle, getRadiusDataForCircle, getLengthAsMetricText, getAreaAsMetricText, getAzimuthAsText } from './utils/olutils.js';
85
85
  export { getPropertyByPath, setPropertyByPath, createObjectFromPath, deletePropertyByPath, mergeObjects } from './utils/pathUtils.js';
86
86
  export { generateQrCode } from './utils/qrcode.js';
87
87
  export { default as ServiceWorkerHelper } from './utils/swhelper.js';
@@ -48,3 +48,4 @@ export declare const getRadiusDataForCircle: (circle: Circle, defaultStyle: Styl
48
48
  };
49
49
  export declare const getLengthAsMetricText: (length?: number) => string;
50
50
  export declare const getAreaAsMetricText: (area?: number) => string;
51
+ export declare const getAzimuthAsText: (azimuth?: number) => string;
@@ -148,7 +148,8 @@ export const getLabelStyle = (position, text, labelStyle) => {
148
148
  export const getRadiusDataForCircle = (circle, defaultStyle, stroke) => {
149
149
  const radius = circle.getRadius();
150
150
  const center = circle.getCenter();
151
- const radiusLine = [center, [center[0] + radius, center[1]]];
151
+ const pointer = circle.getProperties()['pointer'] ?? [center[0] + radius, center[1]];
152
+ const radiusLine = [center, pointer];
152
153
  const radiusLineStyle = defaultStyle.clone();
153
154
  radiusLineStyle.setStroke(stroke);
154
155
  radiusLineStyle.getText().setText('');
@@ -173,3 +174,9 @@ export const getAreaAsMetricText = (area) => {
173
174
  }
174
175
  return '';
175
176
  };
177
+ export const getAzimuthAsText = (azimuth) => {
178
+ if (azimuth) {
179
+ return `${azimuth.toFixed(0)}°`;
180
+ }
181
+ return '';
182
+ };