@geogirafe/lib-geoportal 1.1.0-dev.2533501910 → 1.1.0-dev.2545448597

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/api/apigeogirafeapp.d.ts +1 -0
  2. package/api/apigeogirafeapp.js +42 -11
  3. package/components/drawing/component.d.ts +5 -3
  4. package/components/drawing/component.js +10 -9
  5. package/components/main.d.ts +1 -1
  6. package/components/main.js +1 -1
  7. package/components/map/component.js +9 -8
  8. package/package.json +1 -1
  9. package/templates/api.html +16 -1
  10. package/templates/public/about.json +1 -1
  11. package/tools/app/geogirafeapp.js +4 -4
  12. package/tools/drawing/cesiumDrawing.d.ts +42 -0
  13. package/{components → tools}/drawing/cesiumDrawing.js +11 -10
  14. package/{components → tools}/drawing/drawingFeature.d.ts +6 -11
  15. package/{components → tools}/drawing/drawingFeature.js +6 -11
  16. package/{components → tools}/drawing/drawingSerializer.d.ts +4 -4
  17. package/{components → tools}/drawing/drawingSerializer.js +9 -7
  18. package/tools/drawing/drawingState.d.ts +7 -0
  19. package/tools/drawing/drawingState.js +5 -0
  20. package/{components → tools}/drawing/olDrawing.d.ts +35 -42
  21. package/{components → tools}/drawing/olDrawing.js +21 -20
  22. package/tools/main.d.ts +8 -1
  23. package/tools/main.js +7 -1
  24. package/tools/state/brain/serialize.d.ts +1 -1
  25. package/tools/state/brain/serialize.js +1 -1
  26. package/tools/state/mapposition.d.ts +2 -0
  27. package/tools/state/mapposition.js +3 -1
  28. package/tools/url/permalinkmanager.d.ts +5 -0
  29. package/tools/url/permalinkmanager.js +55 -27
  30. package/tools/utils/utils.d.ts +5 -0
  31. package/tools/utils/utils.js +10 -0
  32. package/components/drawing/cesiumDrawing.d.ts +0 -45
  33. /package/{components → tools}/drawing/shapeConstraints.d.ts +0 -0
  34. /package/{components → tools}/drawing/shapeConstraints.js +0 -0
@@ -26,6 +26,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
26
26
  private manageCrosshairAttribute;
27
27
  private manageTooltipAttribute;
28
28
  private manageMarkersAttribute;
29
+ private markerStringToMapMarker;
29
30
  private initialize;
30
31
  private injectConfigMetaTags;
31
32
  }
@@ -10,6 +10,7 @@ import MenuButtonComponent from '../components/menubutton/component.js';
10
10
  import MapCustomContextMenuComponent from '../components/context-menu/custom-context-menu/component.js';
11
11
  import SearchComponent from '../components/search/component.js';
12
12
  import SelectionWindowComponent from '../components/selectionwindow/component.js';
13
+ import { splitTrimAndConvertToNumber } from '../tools/utils/utils.js';
13
14
  export default class GeoGirafeApi extends GirafeHTMLElement {
14
15
  templateUrl = null;
15
16
  styleUrls = null;
@@ -245,17 +246,10 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
245
246
  const markers = this.getAttributeFromConfig('markers');
246
247
  if (markers) {
247
248
  const markerValues = markers.split(';');
248
- for (const makerValue of markerValues) {
249
- const content = makerValue.split('|');
250
- const coords = content[0].split(',');
251
- const x = Number(coords[0].trim());
252
- const y = Number(coords[1].trim());
253
- if (!Number.isNaN(x) && !Number.isNaN(y)) {
254
- const imageUrl = content[1].trim();
255
- this.context.stateManager.state.position.markers.push({
256
- position: [x, y],
257
- imageUrl: imageUrl
258
- });
249
+ for (const markerValue of markerValues) {
250
+ const marker = this.markerStringToMapMarker(markerValue);
251
+ if (marker) {
252
+ this.context.stateManager.state.position.markers.push(marker);
259
253
  }
260
254
  else {
261
255
  console.warn('Invalid marker coordinates');
@@ -263,6 +257,43 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
263
257
  }
264
258
  }
265
259
  }
260
+ markerStringToMapMarker(markerValue) {
261
+ console.log('markerStringToMapMarker', markerValue);
262
+ const contentParts = markerValue.split('|');
263
+ const needToGuessThirdParameter = contentParts.length == 3;
264
+ if (needToGuessThirdParameter) {
265
+ console.warn(`Marker has only 3 Parameters! Guessing if third Parameter '${contentParts[2]}' is Size or Offset`);
266
+ }
267
+ const coords = contentParts[0].split(',');
268
+ const x = Number(coords[0].trim());
269
+ const y = Number(coords[1].trim());
270
+ if (!Number.isNaN(x) && !Number.isNaN(y)) {
271
+ const imageUrl = contentParts[1].trim();
272
+ let size;
273
+ let offset;
274
+ if (needToGuessThirdParameter) {
275
+ if (contentParts[2].match(/[+-]+/gm)) {
276
+ offset = splitTrimAndConvertToNumber(contentParts[2]);
277
+ }
278
+ else {
279
+ size = splitTrimAndConvertToNumber(contentParts[2]);
280
+ }
281
+ }
282
+ else if (contentParts.length > 2) {
283
+ size = splitTrimAndConvertToNumber(contentParts[2]);
284
+ offset = splitTrimAndConvertToNumber(contentParts[3]);
285
+ }
286
+ return {
287
+ position: [x, y],
288
+ imageUrl: imageUrl,
289
+ size: size,
290
+ offset: offset
291
+ };
292
+ }
293
+ else {
294
+ return undefined;
295
+ }
296
+ }
266
297
  async initialize() {
267
298
  await this.context.initialize();
268
299
  // Register Coordinate Reference Systems (CRS) definitions in PROJ4
@@ -1,11 +1,13 @@
1
1
  import { Color } from 'vanilla-picker';
2
- import DrawingFeature, { ArrowPosition, ArrowStyle, DrawingShape, DrawingState } from './drawingFeature.js';
3
- import OlDrawing from './olDrawing.js';
4
- import CesiumDrawing from './cesiumDrawing.js';
2
+ import DrawingFeature, { ArrowPosition, ArrowStyle, DrawingShape } from '../../tools/drawing/drawingFeature.js';
3
+ import DrawingState from '../../tools/drawing/drawingState.js';
4
+ import OlDrawing from '../../tools/drawing/olDrawing.js';
5
+ import CesiumDrawing from '../../tools/drawing/cesiumDrawing.js';
5
6
  import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
6
7
  import GirafeColorPicker from '../../tools/utils/girafecolorpicker.js';
7
8
  import LayerDrawing from '../../models/layers/layerdrawing.js';
8
9
  import IGirafePanel from '../../tools/state/igirafepanel.js';
10
+ export declare const DrawingStateLocation = "drawing";
9
11
  export default class DrawingComponent extends GirafeHTMLElement implements IGirafePanel {
10
12
  protected templateUrl: string | null;
11
13
  protected styleUrls: string[] | null;
@@ -7,9 +7,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  import { htmlFor as uHtmlFor } from 'uhtml/keyed';
8
8
  import { html as uHtml } from 'uhtml';
9
9
  import { v4 as uuidv4 } from 'uuid';
10
- import DrawingFeature, { DrawingShape } from './drawingFeature.js';
11
- import OlDrawing from './olDrawing.js';
12
- import CesiumDrawing from './cesiumDrawing.js';
10
+ import DrawingFeature, { DrawingShape } from '../../tools/drawing/drawingFeature.js';
11
+ import OlDrawing from '../../tools/drawing/olDrawing.js';
12
+ import CesiumDrawing from '../../tools/drawing/cesiumDrawing.js';
13
13
  import { GeoJSON, GPX, KML } from 'ol/format.js';
14
14
  import { Polygon } from 'ol/geom.js';
15
15
  import Feature from 'ol/Feature.js';
@@ -25,6 +25,7 @@ import visibleIcon from './assets/visible.svg?raw';
25
25
  import notVisibleIcon from './assets/notVisible.svg?raw';
26
26
  import LayerDrawing from '../../models/layers/layerdrawing.js';
27
27
  import { UsedInTemplateOnly } from '../../decorators.js';
28
+ export const DrawingStateLocation = 'drawing';
28
29
  export default class DrawingComponent extends GirafeHTMLElement {
29
30
  templateUrl = null;
30
31
  styleUrls = null;
@@ -200,20 +201,20 @@ input{border:1px solid var(--bkg-color-grad1);width:inherit;background-color:var
200
201
  }
201
202
  connectedCallback() {
202
203
  super.connectedCallback();
203
- if (!this.state.extendedState.drawing) {
204
- throw new Error('ExtendedState has to be defined in main typescript file.');
204
+ if (!this.state.extendedState[DrawingStateLocation]) {
205
+ throw new Error(`ExtendedState '${DrawingStateLocation}' has to be defined in main typescript file.`);
205
206
  }
206
- this.drawingState = this.state.extendedState.drawing;
207
+ this.drawingState = this.state.extendedState[DrawingStateLocation];
207
208
  const map = this.context.componentManager.getComponents(MapComponent)[0];
208
- this.olDrawing = new OlDrawing(map, this.name, this.context, (featureId) => {
209
+ this.olDrawing = new OlDrawing(map, DrawingStateLocation, this.context, (featureId) => {
209
210
  const drawingFeature = this.drawingState.features.find((drawingFeature) => drawingFeature.id === featureId);
210
211
  if (drawingFeature) {
211
212
  this.deleteFeature(drawingFeature);
212
213
  }
213
214
  });
214
- this.cesiumDrawing = new CesiumDrawing(map, this.name, this.context);
215
+ this.cesiumDrawing = new CesiumDrawing(map, DrawingStateLocation, this.context);
215
216
  this.render();
216
- this.subscribe('extendedState.drawing.features', (olds, news) => this.onFeaturesChanged(olds, news));
217
+ this.subscribe(`extendedState.${DrawingStateLocation}.features`, (olds, news) => this.onFeaturesChanged(olds, news));
217
218
  this.subscribe('projection', (olds, news) => this.onProjectionChanged(olds, news));
218
219
  this.subscribe('globe.loaded', () => {
219
220
  if (this.state.globe.loaded && this.isPanelVisible) {
@@ -12,7 +12,7 @@ export { default as CrossSectionSettingsComponent } from './cross-section/cross-
12
12
  export { default as CrossSectionViewComponent } from './cross-section/cross-section-viewer/component.js';
13
13
  export { default as DisplayMenuButtonMobile } from './displaymenubutton-mobile/component.js';
14
14
  export { default as DisplaySelectorButtonMobile } from './displayselectorbutton-mobile/component.js';
15
- export { default as DrawingComponent } from './drawing/component.js';
15
+ export { default as DrawingComponent, DrawingStateLocation } from './drawing/component.js';
16
16
  export type { FixedDimensionValueChangedEventDetails, DimensionUnit } from './drawing/fixed-dimension/component.js';
17
17
  export { default as FixedDimensionComponent } from './drawing/fixed-dimension/component.js';
18
18
  export { default as DrawingContainerMobile } from './drawing-container-mobile/component.js';
@@ -12,7 +12,7 @@ export { default as CrossSectionSettingsComponent } from './cross-section/cross-
12
12
  export { default as CrossSectionViewComponent } from './cross-section/cross-section-viewer/component.js';
13
13
  export { default as DisplayMenuButtonMobile } from './displaymenubutton-mobile/component.js';
14
14
  export { default as DisplaySelectorButtonMobile } from './displayselectorbutton-mobile/component.js';
15
- export { default as DrawingComponent } from './drawing/component.js';
15
+ export { default as DrawingComponent, DrawingStateLocation } from './drawing/component.js';
16
16
  export { default as FixedDimensionComponent } from './drawing/fixed-dimension/component.js';
17
17
  export { default as DrawingContainerMobile } from './drawing-container-mobile/component.js';
18
18
  export { default as EditComponent } from './edit/component.js';
@@ -135,7 +135,7 @@ export default class MapComponent extends GirafeHTMLElement {
135
135
  this.subscribe('position.markers', () => {
136
136
  this.clearAllMarkers();
137
137
  for (const marker of this.state.position.markers) {
138
- this.addMarker(marker.position, marker.imageUrl);
138
+ this.addMarker(marker);
139
139
  }
140
140
  });
141
141
  this.subscribe('globe.display', async () => {
@@ -177,7 +177,7 @@ export default class MapComponent extends GirafeHTMLElement {
177
177
  }
178
178
  this.showCrosshair(this.state.position);
179
179
  for (const marker of this.state.position.markers) {
180
- this.addMarker(marker.position, marker.imageUrl);
180
+ this.addMarker(marker);
181
181
  }
182
182
  }
183
183
  });
@@ -1017,23 +1017,24 @@ export default class MapComponent extends GirafeHTMLElement {
1017
1017
  this.state.position = position;
1018
1018
  if (position.markers.length > 0) {
1019
1019
  // Add marker to the map
1020
- this.addMarker(position.markers[0].position, position.markers[0].imageUrl);
1020
+ this.addMarker(position.markers[0]);
1021
1021
  }
1022
1022
  }
1023
1023
  }
1024
1024
  clearAllMarkers() {
1025
1025
  this.markerSource.clear();
1026
1026
  }
1027
- addMarker(position, imageUrl) {
1027
+ addMarker(mapMarker) {
1028
1028
  const iconStyle = new Style({
1029
1029
  image: new Icon({
1030
- //anchor: [0.5, 1], // Point d'ancrage (centre en bas)
1031
- src: imageUrl
1032
- //scale: 0.5, // Ajustez la taille si nécessaire
1030
+ displacement: mapMarker.offset,
1031
+ src: mapMarker.imageUrl,
1032
+ width: mapMarker.size ? mapMarker.size[0] : undefined,
1033
+ height: mapMarker.size ? mapMarker.size[1] : undefined
1033
1034
  })
1034
1035
  });
1035
1036
  const marker = new Feature({
1036
- geometry: new Point(position)
1037
+ geometry: new Point(mapMarker.position)
1037
1038
  });
1038
1039
  marker.setStyle(iconStyle);
1039
1040
  this.markerSource.addFeature(marker);
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.2533501910",
8
+ "version": "1.1.0-dev.2545448597",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -290,6 +290,21 @@
290
290
  </div>
291
291
  </section>
292
292
 
293
+ <!-- Multiple markers with size and/or offset -->
294
+ <h2>Add multiple markers with size and/or offset on the map</h2>
295
+ <p class="descr">Add multiple markers at the defined coordinates. You can specify size and offset. If you only
296
+ specify three parameters, the third parameter can be the size if you <strong>don't</strong> include a sign
297
+ (e.g. <code>24,24</code>) or the offset if you <strong>do</strong> include a sign (e.g. <code>+2,-6</code>).
298
+ </p>
299
+ <section>
300
+ <div class="row">
301
+ <div class="left">
302
+ <geogirafe-map markers="api.demo.markersWithSizeAndOrOffset" />
303
+ </div>
304
+ <div class="right"></div>
305
+ </div>
306
+ </section>
307
+
293
308
  <!-- Layers -->
294
309
  <h2>Add a layer to the map</h2>
295
310
  <p class="descr">Add a layer to the map. The layer name must be defined in the themes.json file.</p>
@@ -302,7 +317,7 @@
302
317
  </div>
303
318
  </section>
304
319
 
305
- <!-- Mulaiple layers -->
320
+ <!-- Multiple layers -->
306
321
  <h2>Add multiple layers to the map</h2>
307
322
  <p class="descr">Add multiple layers to the map. The layer names must be defined in the themes.json file.</p>
308
323
  <section>
@@ -1 +1 @@
1
- {"version":"1.1.0-dev.2533501910", "build":"2533501910", "date":"18/05/2026"}
1
+ {"version":"1.1.0-dev.2545448597", "build":"2545448597", "date":"22/05/2026"}
@@ -9,7 +9,7 @@ import MapDefaultContextMenuComponent from '../../components/context-menu/defaul
9
9
  import MapCustomContextMenuComponent from '../../components/context-menu/custom-context-menu/component.js';
10
10
  import CrossSectionSettingsComponent from '../../components/cross-section/cross-section-settings/component.js';
11
11
  import CrossSectionViewComponent from '../../components/cross-section/cross-section-viewer/component.js';
12
- import DrawingComponent from '../../components/drawing/component.js';
12
+ import DrawingComponent, { DrawingStateLocation } from '../../components/drawing/component.js';
13
13
  import EditComponent from '../../components/edit/component.js';
14
14
  import EditFromComponent from '../../components/edit/editform/component.js';
15
15
  import HelpComponent from '../../components/help/component.js';
@@ -43,8 +43,8 @@ import TreeViewRootComponent from '../../components/treeview/treeviewroot/compon
43
43
  import TreeViewThemeComponent from '../../components/treeview/treeviewtheme/component.js';
44
44
  import UserPreferencesComponent from '../../components/userpreferences/component.js';
45
45
  import VideoRecordComponent from '../../components/videorecord/component.js';
46
- import { DrawingState } from '../../components/drawing/drawingFeature.js';
47
- import DrawingSerializer from '../../components/drawing/drawingSerializer.js';
46
+ import DrawingState from '../drawing/drawingState.js';
47
+ import DrawingSerializer from '../drawing/drawingSerializer.js';
48
48
  import { ShareState, ShareStateSerializer } from '../../components/share/sharestate.js';
49
49
  import SelectionToolComponent from '../../components/selectiontool/component.js';
50
50
  import AdvancedFilterComponent from '../../components/advancedfilter/component.js';
@@ -92,7 +92,7 @@ export default class GeoGirafeApp {
92
92
  }
93
93
  addCustomSerializers() {
94
94
  // Add custom state and serializers (need to be done early, because the shared state will need them)
95
- this.context.stateManager.state.extendedState.drawing = new DrawingState();
95
+ this.context.stateManager.state.extendedState[DrawingStateLocation] = new DrawingState();
96
96
  this.context.stateSerializer.addSerializer(DrawingState, new DrawingSerializer(this.context));
97
97
  this.context.stateManager.state.extendedState.share = new ShareState();
98
98
  this.context.stateSerializer.addSerializer(ShareState, new ShareStateSerializer(this.context, this.isIframe));
@@ -0,0 +1,42 @@
1
+ import MapComponent from '../../components/map/component.js';
2
+ import IGirafeContext from '../context/icontext.js';
3
+ export default class CesiumDrawing {
4
+ private readonly stateLocation;
5
+ private activeShapePoints;
6
+ private activeShapes;
7
+ private floatingPoint;
8
+ private scene;
9
+ private handler;
10
+ private entities;
11
+ private fixedLineLength;
12
+ private readonly context;
13
+ private get state();
14
+ private get drawingState();
15
+ private get config();
16
+ constructor(map: MapComponent, stateLocation: string, context: IGirafeContext);
17
+ setFixedLineLength(length: number): void;
18
+ private activateTool;
19
+ private deactivateTool;
20
+ private pickOnGlobe;
21
+ private removeLastPointAndTerminateShape;
22
+ private terminateShape;
23
+ private fixLastLength;
24
+ private updateShape;
25
+ private addPoint;
26
+ private leveledCenterToMouse;
27
+ private makeRectangle;
28
+ private makeRegularPolygon;
29
+ private getShapes;
30
+ registerInteractions(): void;
31
+ unregisterInteractions(): void;
32
+ private canExecute;
33
+ private getPosition;
34
+ private getLength;
35
+ private createLabel;
36
+ private createPoint;
37
+ private getPolygonCenter;
38
+ private getPolyLineLabels;
39
+ private getPolygonArea;
40
+ private getPolyline;
41
+ private getPolygonEntity;
42
+ }
@@ -6,7 +6,8 @@ import DrawingFeature, { DrawingShape } from './drawingFeature.js';
6
6
  import proj4 from 'proj4';
7
7
  const CLAMP_TO_GROUND = Cesium.HeightReference.CLAMP_TO_GROUND;
8
8
  export default class CesiumDrawing {
9
- toolName;
9
+ // Writes drawn features into the specified location in the extended state
10
+ stateLocation;
10
11
  activeShapePoints = [];
11
12
  activeShapes = [];
12
13
  floatingPoint = undefined;
@@ -19,20 +20,20 @@ export default class CesiumDrawing {
19
20
  return this.context.stateManager.state;
20
21
  }
21
22
  get drawingState() {
22
- return this.state.extendedState.drawing;
23
+ return this.state.extendedState[this.stateLocation];
23
24
  }
24
25
  get config() {
25
26
  return this.context.configManager.Config;
26
27
  }
27
- constructor(map, toolName, context) {
28
- this.toolName = toolName;
28
+ constructor(map, stateLocation, context) {
29
+ this.stateLocation = stateLocation;
29
30
  this.context = context;
30
31
  map.subscribe('globe.loaded', () => {
31
32
  if (this.state.globe.loaded) {
32
33
  this.scene = map.map3d.getCesiumScene();
33
34
  this.handler = new Cesium.ScreenSpaceEventHandler(this.scene.canvas);
34
35
  this.entities = map.map3d.getDataSourceDisplay().defaultDataSource.entities;
35
- map.subscribe('extendedState.drawing.activeTool', (_oldTool, newTool) => newTool === null ? this.deactivateTool() : this.activateTool(newTool));
36
+ map.subscribe(`extendedState.${this.stateLocation}.activeTool`, (_oldTool, newTool) => newTool === null ? this.deactivateTool() : this.activateTool(newTool));
36
37
  }
37
38
  });
38
39
  }
@@ -305,16 +306,16 @@ export default class CesiumDrawing {
305
306
  }
306
307
  }
307
308
  registerInteractions() {
308
- this.context.userInteractionManager.registerListener('globe.select', true, this.toolName);
309
- this.context.userInteractionManager.registerListener('globe.draw', true, this.toolName);
309
+ this.context.userInteractionManager.registerListener('globe.select', true, this.stateLocation);
310
+ this.context.userInteractionManager.registerListener('globe.draw', true, this.stateLocation);
310
311
  }
311
312
  unregisterInteractions() {
312
313
  this.deactivateTool();
313
- this.context.userInteractionManager.unregisterListener('globe.select', this.toolName);
314
- this.context.userInteractionManager.unregisterListener('globe.draw', this.toolName);
314
+ this.context.userInteractionManager.unregisterListener('globe.select', this.stateLocation);
315
+ this.context.userInteractionManager.unregisterListener('globe.draw', this.stateLocation);
315
316
  }
316
317
  canExecute(event) {
317
- return this.context.userInteractionManager.canListenerExecute(event, this.toolName);
318
+ return this.context.userInteractionManager.canListenerExecute(event, this.stateLocation);
318
319
  }
319
320
  getPosition(p) {
320
321
  const carto = Cartographic.fromCartesian(p);
@@ -1,8 +1,8 @@
1
1
  import { Style } from 'ol/style.js';
2
- import type { IBrainSerializable } from '../../tools/state/brain/decorators.js';
3
2
  import type { Circle as CircleGeom, Geometry } from 'ol/geom.js';
4
3
  import type Feature from 'ol/Feature.js';
5
- import IGirafeContext from '../../tools/context/icontext.js';
4
+ import IGirafeContext from '../context/icontext.js';
5
+ import DrawingState from './drawingState.js';
6
6
  export declare enum DrawingShape {
7
7
  Point = 0,
8
8
  Polyline = 1,
@@ -16,11 +16,6 @@ export declare enum DrawingShape {
16
16
  export type ArrowStyle = 'none' | 'start' | 'end' | 'both';
17
17
  export type ArrowPosition = 'whole' | 'each' | 'mid';
18
18
  export type LineStroke = 'full' | 'dash' | 'dot' | 'double';
19
- export declare class DrawingState implements IBrainSerializable {
20
- isBrainSerializable: boolean;
21
- activeTool: DrawingShape | null;
22
- features: DrawingFeature[];
23
- }
24
19
  export type SerializedFeature = {
25
20
  n: string;
26
21
  sc: string;
@@ -102,13 +97,13 @@ export default class DrawingFeature {
102
97
  getAzimuthText(circle: CircleGeom): string;
103
98
  isPointOrPolyline(): boolean;
104
99
  getVertexStyle(activeNode?: boolean): Style;
105
- static deserialize(serializedFeature: SerializedFeature, context: IGirafeContext): DrawingFeature;
100
+ static deserialize(serializedFeature: SerializedFeature, context: IGirafeContext, drawingState: DrawingState): DrawingFeature;
106
101
  static circleToPolygon(center: number[], radius: number, nbEdges?: number): number[][];
107
102
  static geojsonFromOlFeature(olFeature: Feature<Geometry>, shapeType: DrawingShape): object;
108
103
  /**
109
- * Finds an name composed of the shape type and a number.
110
- * The number starts from how many shape of the same type type are already in the state +1.
111
- * Then checks if such candidate name already exists and increments if so.
104
+ * Finds a name composed of the shape type and a number.
105
+ * The number starts from how many shapes of the same type are already in the state +1.
106
+ * Then checks if such a candidate name already exists and increments if so.
112
107
  * @param geometryTypename
113
108
  * @returns
114
109
  */
@@ -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, getAzimuthAsText, getLengthAsMetricText } from '../../tools/utils/olutils.js';
6
+ import { getAreaAsMetricText, getAzimuthAsText, getLengthAsMetricText } from '../utils/olutils.js';
7
7
  export var DrawingShape;
8
8
  (function (DrawingShape) {
9
9
  DrawingShape[DrawingShape["Point"] = 0] = "Point";
@@ -15,11 +15,6 @@ export var DrawingShape;
15
15
  DrawingShape[DrawingShape["FreehandPolyline"] = 6] = "FreehandPolyline";
16
16
  DrawingShape[DrawingShape["FreehandPolygon"] = 7] = "FreehandPolygon";
17
17
  })(DrawingShape || (DrawingShape = {}));
18
- export class DrawingState {
19
- isBrainSerializable = true;
20
- activeTool = null;
21
- features = [];
22
- }
23
18
  export default class DrawingFeature {
24
19
  _tool;
25
20
  _name;
@@ -230,9 +225,9 @@ export default class DrawingFeature {
230
225
  })
231
226
  });
232
227
  }
233
- static deserialize(serializedFeature, context) {
228
+ static deserialize(serializedFeature, context, drawingState) {
234
229
  console.log(serializedFeature);
235
- const newFeature = new DrawingFeature(serializedFeature.t, context.stateManager.state.extendedState.drawing, context.configManager.Config.drawing);
230
+ const newFeature = new DrawingFeature(serializedFeature.t, drawingState, context.configManager.Config.drawing);
236
231
  newFeature.geojson = serializedFeature.g;
237
232
  newFeature.name = serializedFeature.n;
238
233
  newFeature.strokeColor = serializedFeature.sc;
@@ -279,9 +274,9 @@ export default class DrawingFeature {
279
274
  return JSON.parse(new GeoJSON().writeFeature(olFeature));
280
275
  }
281
276
  /**
282
- * Finds an name composed of the shape type and a number.
283
- * The number starts from how many shape of the same type type are already in the state +1.
284
- * Then checks if such candidate name already exists and increments if so.
277
+ * Finds a name composed of the shape type and a number.
278
+ * The number starts from how many shapes of the same type are already in the state +1.
279
+ * Then checks if such a candidate name already exists and increments if so.
285
280
  * @param geometryTypename
286
281
  * @returns
287
282
  */
@@ -1,10 +1,10 @@
1
- import IGirafeContext from '../../tools/context/icontext.js';
2
- import type { IBrainSerializer } from '../../tools/state/brain/serialize.js';
3
- import { DrawingState } from './drawingFeature.js';
1
+ import IGirafeContext from '../context/icontext.js';
2
+ import type { IBrainSerializer } from '../state/brain/serialize.js';
3
+ import DrawingState from './drawingState.js';
4
4
  export default class DrawingSerializer implements IBrainSerializer<DrawingState> {
5
5
  private readonly context;
6
6
  constructor(context: IGirafeContext);
7
7
  private get state();
8
8
  brainSerialize(drawingState: DrawingState): string;
9
- brainDeserialize(str: string): void;
9
+ brainDeserialize(str: string, stateLocation: string): void;
10
10
  }
@@ -1,4 +1,5 @@
1
- import DrawingFeature, { DrawingState } from './drawingFeature.js';
1
+ import DrawingFeature from './drawingFeature.js';
2
+ import DrawingState from './drawingState.js';
2
3
  export default class DrawingSerializer {
3
4
  context;
4
5
  constructor(context) {
@@ -14,22 +15,23 @@ export default class DrawingSerializer {
14
15
  }
15
16
  return JSON.stringify(serializedDrawings);
16
17
  }
17
- brainDeserialize(str) {
18
+ brainDeserialize(str, stateLocation) {
18
19
  const serializedFeatures = JSON.parse(str);
19
20
  if (serializedFeatures) {
20
- if (this.state.extendedState.drawing) {
21
+ let drawingState = new DrawingState();
22
+ if (this.state.extendedState[stateLocation]) {
21
23
  // First, delete existing drawing features in the state before adding new ones.
22
24
  // This will trigger removal of the ol features in the map.
23
- const drawingState = this.state.extendedState.drawing;
25
+ drawingState = this.state.extendedState[stateLocation];
24
26
  drawingState.features.splice(0, drawingState.features.length);
25
27
  }
26
28
  else {
27
- this.state.extendedState.drawing = new DrawingState();
29
+ this.state.extendedState[stateLocation] = drawingState;
28
30
  }
29
- serializedFeatures.forEach((f) => DrawingFeature.deserialize(f, this.context));
31
+ serializedFeatures.forEach((f) => DrawingFeature.deserialize(f, this.context, drawingState));
30
32
  }
31
33
  else {
32
- throw new Error(`Cannot deserialize drawings`);
34
+ throw new Error(`Cannot deserialize the drawing state for ${stateLocation}`);
33
35
  }
34
36
  }
35
37
  }
@@ -0,0 +1,7 @@
1
+ import type { IBrainSerializable } from '../state/brain/decorators.js';
2
+ import DrawingFeature, { DrawingShape } from './drawingFeature.js';
3
+ export default class DrawingState implements IBrainSerializable {
4
+ isBrainSerializable: boolean;
5
+ activeTool: DrawingShape | null;
6
+ features: DrawingFeature[];
7
+ }
@@ -0,0 +1,5 @@
1
+ export default class DrawingState {
2
+ isBrainSerializable = true;
3
+ activeTool = null;
4
+ features = [];
5
+ }
@@ -1,45 +1,38 @@
1
- import DrawingFeature, { DrawingShape } from './drawingFeature.js';
2
- import MapComponent from '../map/component.js';
3
- import { Collection, Feature } from 'ol';
4
- import { Geometry, SimpleGeometry } from 'ol/geom.js';
5
- import { SketchCoordType } from 'ol/interaction/Draw.js';
6
- import { Style } from 'ol/style.js';
7
- import { Draw, Modify, Snap, Translate } from 'ol/interaction.js';
8
- import VectorSource, { VectorSourceEvent } from 'ol/source/Vector.js';
1
+ import DrawingFeature from './drawingFeature.js';
2
+ import MapComponent from '../../components/map/component.js';
3
+ import { Feature } from 'ol';
4
+ import { Geometry } from 'ol/geom.js';
5
+ import VectorSource from 'ol/source/Vector.js';
9
6
  import VectorLayer from 'ol/layer/Vector.js';
10
- import { Projection } from 'ol/proj.js';
11
- import { Coordinate } from 'ol/coordinate.js';
12
- import { ContextMenu } from '../map/tools/contextmenu.js';
13
- import IGirafeContext from '../../tools/context/icontext.js';
7
+ import IGirafeContext from '../context/icontext.js';
14
8
  import { StyleFunction } from 'ol/style/Style.js';
15
- import Transform from 'ol-ext/interaction/Transform.js';
16
9
  export default class OlDrawing {
17
10
  private readonly map;
18
- private readonly toolName;
11
+ private readonly stateLocation;
19
12
  private readonly context;
20
13
  private readonly deleteHandler;
21
- modifiableFeatures: Collection<Feature>;
22
- draw: Draw | null;
23
- modify: Modify | null;
24
- snap: Snap | null;
25
- editContextMenu: ContextMenu | null;
26
- currentShape: DrawingShape | null;
27
- fixedLineLength: number;
28
- fixedSquareSide: number;
29
- fixedRectangleWidth: number;
30
- fixedRectangleHeight: number;
31
- drawingSource: VectorSource;
32
- drawingLayer: VectorLayer;
33
- lastClosestFeature: Feature | null;
34
- translate: Translate | null;
35
- transform: Transform | null;
14
+ private readonly modifiableFeatures;
15
+ private draw;
16
+ private modify;
17
+ private snap;
18
+ private editContextMenu;
19
+ private currentShape;
20
+ private fixedLineLength;
21
+ private fixedSquareSide;
22
+ private fixedRectangleWidth;
23
+ private fixedRectangleHeight;
24
+ readonly drawingSource: VectorSource;
25
+ readonly drawingLayer: VectorLayer;
26
+ private lastClosestFeature;
27
+ private translate;
28
+ private transform;
36
29
  private readonly modifyFeatureChangeListeners;
37
30
  defaultStyle: StyleFunction | undefined;
38
31
  private readonly updateGeometryInState;
39
32
  private get state();
40
33
  private get drawingState();
41
34
  private get config();
42
- constructor(map: MapComponent, toolName: string, context: IGirafeContext, deleteHandler: (featureId: string) => void);
35
+ constructor(mapComponent: MapComponent, stateLocation: string, context: IGirafeContext, deleteHandler: (featureId: string) => void);
43
36
  private addModifyInteraction;
44
37
  private addSnapInteraction;
45
38
  private addTranslateInteraction;
@@ -51,15 +44,15 @@ export default class OlDrawing {
51
44
  * when the user does an alternate click ( = context event) on or near a vertex of a modifiable feature.
52
45
  */
53
46
  private addEditContextMenu;
54
- addEditInteractions(): void;
55
- removeEditInteractions(): void;
47
+ private addEditInteractions;
48
+ private removeEditInteractions;
56
49
  private readonly prepareMenuEntriesForVertex;
57
50
  private readonly prepareMenuEntriesForShape;
58
51
  /**
59
52
  Check if there is a vertex of a selected (=editable) feature within the pixel tolerance of the clicked coordinates.
60
53
  */
61
- hasEditableVertexAtCoordinate(coordinate: Coordinate): boolean;
62
- hasEditableShapeAtCoordinate(coordinate: Coordinate): boolean;
54
+ private hasEditableVertexAtCoordinate;
55
+ private hasEditableShapeAtCoordinate;
63
56
  /**
64
57
  Returns the closest vertex and feature to a coordinate from the drawing source.
65
58
  The feature source can be pre-filtered via an optional filter function.
@@ -97,7 +90,7 @@ export default class OlDrawing {
97
90
  *
98
91
  * @param {VectorSourceEvent} e - The add-feature event.
99
92
  */
100
- onFeatureAdded(e: VectorSourceEvent): void;
93
+ private onFeatureAdded;
101
94
  private getOlFeatureFromDrawingSource;
102
95
  private isOlFeatureInState;
103
96
  createOlFeature(dFeature: DrawingFeature): Feature<Geometry>;
@@ -105,14 +98,14 @@ export default class OlDrawing {
105
98
  setFixedSquareSide(length: number): void;
106
99
  setFixedRectangleWidth(width: number): void;
107
100
  setFixedRectangleHeight(height: number): void;
108
- createLineStringFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry): SimpleGeometry;
109
- createSquareFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry, proj: Projection): SimpleGeometry;
110
- createPolygonFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry): SimpleGeometry;
111
- createDiskFixedLength(coordinates: SketchCoordType, geom: SimpleGeometry): SimpleGeometry;
112
- createRectangleFixedSides(coordinates: SketchCoordType, geom: SimpleGeometry, proj: Projection): SimpleGeometry;
113
- addDrawInteraction(tool: DrawingShape): void;
101
+ private createLineStringFixedLength;
102
+ private createSquareFixedLength;
103
+ private createPolygonFixedLength;
104
+ private createDiskFixedLength;
105
+ private createRectangleFixedSides;
106
+ private addDrawInteraction;
114
107
  centerViewOnFeature(drawingFeature: DrawingFeature): void;
115
- getStyle(dFeature: DrawingFeature, olFeature: Feature<Geometry>): Style[];
108
+ private getStyle;
116
109
  private removeDrawInteraction;
117
110
  private removeModifyInteraction;
118
111
  private getDrawingShapeType;
@@ -10,11 +10,11 @@ import VectorLayer from 'ol/layer/Vector.js';
10
10
  import GeoJSON from 'ol/format/GeoJSON.js';
11
11
  import { getPointResolution } from 'ol/proj.js';
12
12
  import { always, never, primaryAction } from 'ol/events/condition.js';
13
- import { ensurePolygonIsProperlyClosed, getAreaOfPolygon, getDistance, getHalfPoint, getLabelStyle, getRadiusDataForCircle, unByKeyAll } from '../../tools/utils/olutils.js';
14
- import { ContextMenu, EntryInteractionType } from '../map/tools/contextmenu.js';
15
- import { formatCoordinates } from '../../tools/geometrytools.js';
13
+ import { ensurePolygonIsProperlyClosed, getAreaOfPolygon, getDistance, getHalfPoint, getLabelStyle, getRadiusDataForCircle, unByKeyAll } from '../utils/olutils.js';
14
+ import { ContextMenu, EntryInteractionType } from '../../components/map/tools/contextmenu.js';
15
+ import { formatCoordinates } from '../geometrytools.js';
16
16
  import { v4 as uuidv4 } from 'uuid';
17
- import { isAlternateMouseClick, isPrimaryPointerAction } from '../../tools/state/userinteractionevent.js';
17
+ import { isAlternateMouseClick, isPrimaryPointerAction } from '../state/userinteractionevent.js';
18
18
  import { calculateCenterAndMinRadius, createScaledAndRotatedGeometry, getGeometryForRendering, shouldAllowVertexInsertionForShape } from './shapeConstraints.js';
19
19
  import Transform from 'ol-ext/interaction/Transform.js';
20
20
  function getLineStroke(strokeType, lineWidth) {
@@ -51,7 +51,8 @@ function extractVerticesFromGeometry(geometry) {
51
51
  }
52
52
  export default class OlDrawing {
53
53
  map;
54
- toolName;
54
+ // Writes drawn features into the specified location in the extended state
55
+ stateLocation;
55
56
  context;
56
57
  deleteHandler;
57
58
  modifiableFeatures = new Collection([]);
@@ -82,14 +83,14 @@ export default class OlDrawing {
82
83
  return this.context.stateManager.state;
83
84
  }
84
85
  get drawingState() {
85
- return this.state.extendedState.drawing;
86
+ return this.state.extendedState[this.stateLocation];
86
87
  }
87
88
  get config() {
88
89
  return this.context.configManager.Config;
89
90
  }
90
- constructor(map, toolName, context, deleteHandler) {
91
- this.map = map;
92
- this.toolName = toolName;
91
+ constructor(mapComponent, stateLocation, context, deleteHandler) {
92
+ this.map = mapComponent;
93
+ this.stateLocation = stateLocation;
93
94
  this.context = context;
94
95
  this.deleteHandler = deleteHandler;
95
96
  this.drawingSource = new VectorSource({ features: new Collection() });
@@ -103,7 +104,7 @@ export default class OlDrawing {
103
104
  }
104
105
  });
105
106
  this.defaultStyle = new Modify({ source: this.drawingSource }).getOverlay().getStyleFunction();
106
- this.map.subscribe('extendedState.drawing.activeTool', (_oldTool, newTool) => newTool === null ? this.removeDrawInteraction() : this.addDrawInteraction(newTool));
107
+ this.map.subscribe(`extendedState.${this.stateLocation}.activeTool`, (_oldTool, newTool) => newTool === null ? this.removeDrawInteraction() : this.addDrawInteraction(newTool));
107
108
  // Could be useful logic if we decide that the mobile UI should rely use a dedicated button
108
109
  // to remove a selected vetex from a polygon/line (rather than using a longpress context menu)
109
110
  // this.map.olMap.on("click", (e) => {
@@ -116,7 +117,7 @@ export default class OlDrawing {
116
117
  // console.log("Map Coordinate:", mapCoordinate, e.pixel, hasEditableVertex);
117
118
  // }
118
119
  // })
119
- this.map.subscribe(/extendedState.drawing.features.*\.selected/, (_old, _new) => this.updateModifiableFeatures());
120
+ this.map.subscribe(new RegExp(String.raw `extendedState.${this.stateLocation}.features.*\.selected`, 'g'), (_old, _new) => this.updateModifiableFeatures());
120
121
  // OlCesium duplicates drawn shapes when 3D view is open if its eventListener is not removed
121
122
  this.map.subscribe('globe.loaded', () => {
122
123
  if (this.state.globe.loaded) {
@@ -595,7 +596,7 @@ export default class OlDrawing {
595
596
  addDrawInteraction(tool) {
596
597
  this.removeDrawInteraction();
597
598
  // Block feature selection while drawing by registering 'map.select' exclusively
598
- this.context.userInteractionManager.registerListener('map.select', true, this.toolName);
599
+ this.context.userInteractionManager.registerListener('map.select', true, this.stateLocation);
599
600
  this.currentShape = tool;
600
601
  let geomFunction = undefined;
601
602
  let olTool;
@@ -836,7 +837,7 @@ export default class OlDrawing {
836
837
  this.draw = null;
837
838
  }
838
839
  // Reactivate feature selection by unregistering 'map.select'
839
- this.context.userInteractionManager.unregisterListener('map.select', this.toolName);
840
+ this.context.userInteractionManager.unregisterListener('map.select', this.stateLocation);
840
841
  }
841
842
  removeModifyInteraction() {
842
843
  this.clearModifyFeatureChangeListeners();
@@ -925,19 +926,19 @@ export default class OlDrawing {
925
926
  }
926
927
  }
927
928
  registerInteractions() {
928
- this.context.userInteractionManager.registerListener('map.draw', true, this.toolName);
929
- this.context.userInteractionManager.registerListener('map.modify', true, this.toolName);
930
- this.context.userInteractionManager.registerListener('map.snap', true, this.toolName);
929
+ this.context.userInteractionManager.registerListener('map.draw', true, this.stateLocation);
930
+ this.context.userInteractionManager.registerListener('map.modify', true, this.stateLocation);
931
+ this.context.userInteractionManager.registerListener('map.snap', true, this.stateLocation);
931
932
  }
932
933
  unregisterInteractions() {
933
934
  this.removeDrawInteraction();
934
935
  this.removeEditInteractions();
935
- this.context.userInteractionManager.unregisterListener('map.draw', this.toolName);
936
- this.context.userInteractionManager.unregisterListener('map.modify', this.toolName);
937
- this.context.userInteractionManager.unregisterListener('map.snap', this.toolName);
936
+ this.context.userInteractionManager.unregisterListener('map.draw', this.stateLocation);
937
+ this.context.userInteractionManager.unregisterListener('map.modify', this.stateLocation);
938
+ this.context.userInteractionManager.unregisterListener('map.snap', this.stateLocation);
938
939
  }
939
940
  canExecute(event) {
940
- return this.context.userInteractionManager.canListenerExecute(event, this.toolName);
941
+ return this.context.userInteractionManager.canListenerExecute(event, this.stateLocation);
941
942
  }
942
943
  fixLastLength(length, coordinates, scale = 1) {
943
944
  const coord = coordinates;
package/tools/main.d.ts CHANGED
@@ -12,6 +12,13 @@ export { default as ConfigManager } from './configuration/configmanager.js';
12
12
  export { default as GirafeConfig } from './configuration/girafeconfig.js';
13
13
  export { default as GirafeContext } from './context/context.js';
14
14
  export type { default as IGirafeContext } from './context/icontext.js';
15
+ export { default as CesiumDrawing } from './drawing/cesiumDrawing.js';
16
+ export type { DrawingShape, ArrowStyle, ArrowPosition, LineStroke, SerializedFeature } from './drawing/drawingFeature.js';
17
+ export { default as DrawingFeature } from './drawing/drawingFeature.js';
18
+ export { default as DrawingSerializer } from './drawing/drawingSerializer.js';
19
+ export { default as DrawingState } from './drawing/drawingState.js';
20
+ export { default as OlDrawing } from './drawing/olDrawing.js';
21
+ export { calculateCenterAndMinRadius, createScaledAndRotatedGeometry, getGeometryForRendering, shouldAllowVertexInsertionForShape } from './drawing/shapeConstraints.js';
15
22
  export { default as ErrorManager } from './error/errormanager.js';
16
23
  export { default as CsvManager } from './export/csvmanager.js';
17
24
  export { download } from './export/download.js';
@@ -113,7 +120,7 @@ export { unByKeyAll, getOlayerByName, removeUnwantedOlParams, polygonFromCircle,
113
120
  export { getPropertyByPath, setPropertyByPath, createObjectFromPath, deletePropertyByPath, mergeObjects } from './utils/pathUtils.js';
114
121
  export { generateQrCode } from './utils/qrcode.js';
115
122
  export { default as ServiceWorkerHelper } from './utils/swhelper.js';
116
- export { systemIsInDarkMode, isSafari, isFirefox, getValidIndex, minMax, hexToRgbaArray, rgbStrToRgbaArray, colorToRgbaArray, isValidEmail, applyOpacityToLayers, applyFeaturesToSelection, linkify, applyDefaultPrefixToUrl } from './utils/utils.js';
123
+ export { systemIsInDarkMode, isSafari, isFirefox, getValidIndex, minMax, hexToRgbaArray, rgbStrToRgbaArray, colorToRgbaArray, isValidEmail, applyOpacityToLayers, applyFeaturesToSelection, linkify, applyDefaultPrefixToUrl, splitTrimAndConvertToNumber } from './utils/utils.js';
117
124
  export { default as VendorSpecificOgcServerManager } from './vendorspecificogcservermanager.js';
118
125
  export type { WfsClientOptions, WfsClientOptionalOptions, QueryableLayerWms, GetFeatureOptionsPartial } from './wfs/wfsclient.js';
119
126
  export { default as WfsClient, WfsClientMapServer, WfsClientQgis, WfsClientGeorama, WfsClientDefault, WfsClientGeoServer } from './wfs/wfsclient.js';
package/tools/main.js CHANGED
@@ -11,6 +11,12 @@ export { default as PluginManager } from './auth/pluginmanager.js';
11
11
  export { default as ConfigManager } from './configuration/configmanager.js';
12
12
  export { default as GirafeConfig } from './configuration/girafeconfig.js';
13
13
  export { default as GirafeContext } from './context/context.js';
14
+ export { default as CesiumDrawing } from './drawing/cesiumDrawing.js';
15
+ export { default as DrawingFeature } from './drawing/drawingFeature.js';
16
+ export { default as DrawingSerializer } from './drawing/drawingSerializer.js';
17
+ export { default as DrawingState } from './drawing/drawingState.js';
18
+ export { default as OlDrawing } from './drawing/olDrawing.js';
19
+ export { calculateCenterAndMinRadius, createScaledAndRotatedGeometry, getGeometryForRendering, shouldAllowVertexInsertionForShape } from './drawing/shapeConstraints.js';
14
20
  export { default as ErrorManager } from './error/errormanager.js';
15
21
  export { default as CsvManager } from './export/csvmanager.js';
16
22
  export { download } from './export/download.js';
@@ -88,7 +94,7 @@ export { unByKeyAll, getOlayerByName, removeUnwantedOlParams, polygonFromCircle,
88
94
  export { getPropertyByPath, setPropertyByPath, createObjectFromPath, deletePropertyByPath, mergeObjects } from './utils/pathUtils.js';
89
95
  export { generateQrCode } from './utils/qrcode.js';
90
96
  export { default as ServiceWorkerHelper } from './utils/swhelper.js';
91
- export { systemIsInDarkMode, isSafari, isFirefox, getValidIndex, minMax, hexToRgbaArray, rgbStrToRgbaArray, colorToRgbaArray, isValidEmail, applyOpacityToLayers, applyFeaturesToSelection, linkify, applyDefaultPrefixToUrl } from './utils/utils.js';
97
+ export { systemIsInDarkMode, isSafari, isFirefox, getValidIndex, minMax, hexToRgbaArray, rgbStrToRgbaArray, colorToRgbaArray, isValidEmail, applyOpacityToLayers, applyFeaturesToSelection, linkify, applyDefaultPrefixToUrl, splitTrimAndConvertToNumber } from './utils/utils.js';
92
98
  export { default as VendorSpecificOgcServerManager } from './vendorspecificogcservermanager.js';
93
99
  export { default as WfsClient, WfsClientMapServer, WfsClientQgis, WfsClientGeorama, WfsClientDefault, WfsClientGeoServer } from './wfs/wfsclient.js';
94
100
  export { default as WfsFilter } from './wfs/wfsfilter.js';
@@ -1,7 +1,7 @@
1
1
  export type Constructor<T> = new (...args: any[]) => T;
2
2
  export interface IBrainSerializer<T> {
3
3
  brainSerialize(obj: T): string;
4
- brainDeserialize(str: string): void;
4
+ brainDeserialize(str: string, stateLocation?: string): void;
5
5
  }
6
6
  export default class BrainSerializer<T extends Record<string | symbol, any>> {
7
7
  private readonly registry;
@@ -37,7 +37,7 @@ export default class BrainSerializer {
37
37
  const serializer = this.getSerializer(state[key]);
38
38
  if (serializer) {
39
39
  console.debug(`Deserializing ${key} with custom serializer`);
40
- serializer.brainDeserialize(serializedState[key]);
40
+ serializer.brainDeserialize(serializedState[key], key);
41
41
  }
42
42
  else {
43
43
  console.debug(`Deserializing ${key} with default serializer`);
@@ -2,6 +2,8 @@ import { Coordinate } from 'ol/coordinate.js';
2
2
  export type MapMarker = {
3
3
  imageUrl: string;
4
4
  position: Coordinate;
5
+ size?: number[];
6
+ offset?: number[];
5
7
  };
6
8
  declare class MapPosition {
7
9
  center: Coordinate;
@@ -31,7 +31,9 @@ class MapPosition {
31
31
  for (const marker of this.markers) {
32
32
  position.markers.push({
33
33
  imageUrl: marker.imageUrl,
34
- position: marker.position
34
+ position: marker.position,
35
+ size: marker.size,
36
+ offset: marker.offset
35
37
  });
36
38
  }
37
39
  return position;
@@ -21,7 +21,12 @@ export default class PermalinkManager extends GirafeSingleton {
21
21
  hasMapPosition(): boolean | "" | null;
22
22
  private hasToolTip;
23
23
  private hasMarker;
24
+ private hasMarkerSize;
25
+ private hasMarkerOffset;
24
26
  getMapPosition(targetProjection: Projection): MapPosition | undefined;
27
+ private addCenter;
28
+ private addTooltip;
29
+ private addMarker;
25
30
  hasSearch(): boolean;
26
31
  getSearchTerm(): string;
27
32
  hasThemes(): boolean;
@@ -5,6 +5,7 @@ import MapPosition from '../state/mapposition.js';
5
5
  import { get as getProjection, transform } from 'ol/proj.js';
6
6
  import { isCoordinateInDegrees } from '../utils/olutils.js';
7
7
  import { BASEMAP_VISIBLE_PARAMETER, SEARCH_VISIBLE_PARAMETER } from './permalinkmanager-constants.js';
8
+ import { splitTrimAndConvertToNumber } from '../utils/utils.js';
8
9
  export default class PermalinkManager extends GirafeSingleton {
9
10
  urlParamKeys = [
10
11
  'map_x',
@@ -13,6 +14,8 @@ export default class PermalinkManager extends GirafeSingleton {
13
14
  'map_crosshair',
14
15
  'map_tooltip',
15
16
  'map_marker',
17
+ 'map_marker_size',
18
+ 'map_marker_offset',
16
19
  'search',
17
20
  'basemap',
18
21
  'themes',
@@ -83,46 +86,71 @@ export default class PermalinkManager extends GirafeSingleton {
83
86
  hasMarker() {
84
87
  return this.params['map_marker'] !== null;
85
88
  }
89
+ hasMarkerSize() {
90
+ return this.params['map_marker_size'] !== null;
91
+ }
92
+ hasMarkerOffset() {
93
+ return this.params['map_marker_offset'] !== null;
94
+ }
86
95
  getMapPosition(targetProjection) {
87
96
  if (this.hasMapPosition()) {
88
97
  const position = new MapPosition();
89
- let center = [Number.parseFloat(this.params['map_x']), Number.parseFloat(this.params['map_y'])];
90
- // Transform position to the target projection by making an educated guess about the current CRS
91
- // of the permalink map position
92
- const defaultProjection = this.context.configManager.getDefaultConfigValue('map.srid');
93
- const projectionInUrl = getProjection(isCoordinateInDegrees(position.center) ? 'EPSG:4326' : defaultProjection);
94
- if (projectionInUrl.getCode() !== this.state.projection) {
95
- center = transform(center, projectionInUrl, targetProjection);
96
- }
97
- position.center = center;
98
+ this.addCenter(position, targetProjection);
98
99
  const defaultZoom = this.context.configManager.getDefaultConfigValue('map.startZoom');
99
100
  position.zoom = Number.parseInt(this.params['map_zoom'] ?? defaultZoom);
100
101
  if (this.params['map_crosshair'] === 'true') {
101
- position.crosshair = center;
102
- }
103
- if (this.hasToolTip()) {
104
- const content = DOMPurify.sanitize(this.params['map_tooltip'], {
105
- ALLOWED_TAGS: ['br', 'b', 'div', 'em', 'i', 'p', 'strong'],
106
- ALLOWED_ATTR: []
107
- });
108
- position.tooltip = {
109
- content: content,
110
- position: center
111
- };
112
- }
113
- if (this.hasMarker()) {
114
- const imageUrl = DOMPurify.sanitize(this.params['map_marker']);
115
- position.markers.push({
116
- imageUrl: imageUrl,
117
- position: center
118
- });
102
+ position.crosshair = position.center;
119
103
  }
104
+ this.addTooltip(position);
105
+ this.addMarker(position);
120
106
  if (position.isValid) {
121
107
  return position;
122
108
  }
123
109
  }
124
110
  return undefined;
125
111
  }
112
+ addCenter(position, targetProjection) {
113
+ let center = [Number.parseFloat(this.params['map_x']), Number.parseFloat(this.params['map_y'])];
114
+ // Transform position to the target projection by making an educated guess about the current CRS
115
+ // of the permalink map position
116
+ const defaultProjection = this.context.configManager.getDefaultConfigValue('map.srid');
117
+ const projectionInUrl = getProjection(isCoordinateInDegrees(position.center) ? 'EPSG:4326' : defaultProjection);
118
+ if (projectionInUrl.getCode() !== this.state.projection) {
119
+ center = transform(center, projectionInUrl, targetProjection);
120
+ }
121
+ position.center = center;
122
+ }
123
+ addTooltip(position) {
124
+ if (this.hasToolTip()) {
125
+ const content = DOMPurify.sanitize(this.params['map_tooltip'], {
126
+ ALLOWED_TAGS: ['br', 'b', 'div', 'em', 'i', 'p', 'strong'],
127
+ ALLOWED_ATTR: []
128
+ });
129
+ position.tooltip = {
130
+ content: content,
131
+ position: position.center
132
+ };
133
+ }
134
+ }
135
+ addMarker(position) {
136
+ if (this.hasMarker()) {
137
+ const imageUrl = DOMPurify.sanitize(this.params['map_marker']);
138
+ let size;
139
+ let offset;
140
+ if (this.hasMarkerSize()) {
141
+ size = splitTrimAndConvertToNumber(DOMPurify.sanitize(this.params['map_marker_size']));
142
+ }
143
+ if (this.hasMarkerOffset()) {
144
+ offset = splitTrimAndConvertToNumber(DOMPurify.sanitize(this.params['map_marker_offset']));
145
+ }
146
+ position.markers.push({
147
+ imageUrl: imageUrl,
148
+ position: position.center,
149
+ size: size,
150
+ offset: offset
151
+ });
152
+ }
153
+ }
126
154
  hasSearch() {
127
155
  return this.params['search'] !== null;
128
156
  }
@@ -77,3 +77,8 @@ export declare const linkify: (str: string) => string;
77
77
  * @returns
78
78
  */
79
79
  export declare function applyDefaultPrefixToUrl(context: IGirafeContext, metadataUrl?: string): string | undefined;
80
+ /**
81
+ * Splits a String containing Numbers into an Array of Numbers. The Separator is a comma.
82
+ * @param numbersAsString The String containing Numbers.
83
+ */
84
+ export declare const splitTrimAndConvertToNumber: (numbersAsString: string) => number[];
@@ -199,3 +199,13 @@ export function applyDefaultPrefixToUrl(context, metadataUrl) {
199
199
  }
200
200
  return metadataUrl;
201
201
  }
202
+ /**
203
+ * Splits a String containing Numbers into an Array of Numbers. The Separator is a comma.
204
+ * @param numbersAsString The String containing Numbers.
205
+ */
206
+ export const splitTrimAndConvertToNumber = (numbersAsString) => {
207
+ return numbersAsString
208
+ .split(',')
209
+ .map((e) => e.trim())
210
+ .map(Number);
211
+ };
@@ -1,45 +0,0 @@
1
- import * as Cesium from 'cesium';
2
- import { Cartesian2, Cartesian3, Entity } from 'cesium';
3
- import DrawingFeature, { DrawingShape } from './drawingFeature.js';
4
- import MapComponent from '../map/component.js';
5
- import IGirafeContext from '../../tools/context/icontext.js';
6
- export default class CesiumDrawing {
7
- toolName: string;
8
- activeShapePoints: Cartesian3[];
9
- activeShapes: Entity[];
10
- floatingPoint: Entity | undefined;
11
- scene: Cesium.Scene | undefined;
12
- handler: Cesium.ScreenSpaceEventHandler | undefined;
13
- entities: Cesium.EntityCollection | undefined;
14
- fixedLineLength: number;
15
- private readonly context;
16
- private get state();
17
- private get drawingState();
18
- private get config();
19
- constructor(map: MapComponent, toolName: string, context: IGirafeContext);
20
- setFixedLineLength(length: number): void;
21
- activateTool(tool: DrawingShape): void;
22
- deactivateTool(): void;
23
- pickOnGlobe(position: Cartesian2): Cesium.Cartesian3 | undefined;
24
- removeLastPointAndTerminateShape(tool: DrawingShape): () => void;
25
- terminateShape(tool: DrawingShape): void;
26
- fixLastLength(tool: DrawingShape, length: number, coord: Cartesian3[]): void;
27
- updateShape(tool: DrawingShape): (event: Cesium.ScreenSpaceEventHandler.MotionEvent) => void;
28
- addPoint(tool: DrawingShape): (event: Cesium.ScreenSpaceEventHandler.PositionedEvent) => void;
29
- leveledCenterToMouse(pos: Cartesian3[]): Cesium.Cartesian3;
30
- makeRectangle(pos: Cartesian3[]): Cesium.Cartesian3[];
31
- makeRegularPolygon(center: Cartesian3, firstPosition: Cartesian3, nbEdges: number): Cesium.Cartesian3[];
32
- getShapes(tool: DrawingShape, pos: Cartesian3[], feature: DrawingFeature): Cesium.Entity[];
33
- registerInteractions(): void;
34
- unregisterInteractions(): void;
35
- private canExecute;
36
- private getPosition;
37
- private getLength;
38
- private createLabel;
39
- private createPoint;
40
- private getPolygonCenter;
41
- private getPolyLineLabels;
42
- private getPolygonArea;
43
- private getPolyline;
44
- private getPolygonEntity;
45
- }