@versatiles/svelte 2.0.1 → 2.1.0

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 (83) hide show
  1. package/dist/components/BBoxMap/BBoxMap.svelte +23 -12
  2. package/dist/components/BBoxMap/lib/bbox.d.ts +1 -1
  3. package/dist/components/BBoxMap/lib/bbox.js +19 -17
  4. package/dist/components/BasicMap/BasicMap.svelte +22 -9
  5. package/dist/components/BasicMap/BasicMap.svelte.d.ts +2 -1
  6. package/dist/components/MapEditor/MapEditor.svelte +51 -20
  7. package/dist/components/MapEditor/components/Dialog.svelte +92 -0
  8. package/dist/components/MapEditor/components/Dialog.svelte.d.ts +17 -0
  9. package/dist/components/MapEditor/components/DialogFile.svelte +112 -0
  10. package/dist/components/MapEditor/components/DialogFile.svelte.d.ts +6 -0
  11. package/dist/components/MapEditor/components/DialogShare.svelte +216 -0
  12. package/dist/components/MapEditor/components/DialogShare.svelte.d.ts +10 -0
  13. package/dist/components/MapEditor/components/Editor.svelte +6 -14
  14. package/dist/components/MapEditor/components/EditorFill.svelte +3 -3
  15. package/dist/components/MapEditor/components/EditorStroke.svelte +3 -3
  16. package/dist/components/MapEditor/components/EditorSymbol.svelte +9 -9
  17. package/dist/components/MapEditor/components/InputRow.svelte +2 -3
  18. package/dist/components/MapEditor/components/PanelFile.svelte +73 -0
  19. package/dist/components/MapEditor/components/PanelFile.svelte.d.ts +7 -0
  20. package/dist/components/MapEditor/components/PanelSymbolSelector.svelte +82 -0
  21. package/dist/components/MapEditor/components/PanelSymbolSelector.svelte.d.ts +8 -0
  22. package/dist/components/MapEditor/components/Sidebar.svelte +51 -98
  23. package/dist/components/MapEditor/components/Sidebar.svelte.d.ts +3 -3
  24. package/dist/components/MapEditor/components/SidebarPanel.svelte +13 -5
  25. package/dist/components/MapEditor/lib/element/abstract.d.ts +8 -4
  26. package/dist/components/MapEditor/lib/element/abstract.js +10 -1
  27. package/dist/components/MapEditor/lib/element/abstract_path.d.ts +3 -2
  28. package/dist/components/MapEditor/lib/element/abstract_path.js +6 -3
  29. package/dist/components/MapEditor/lib/element/circle.d.ts +25 -0
  30. package/dist/components/MapEditor/lib/element/circle.js +118 -0
  31. package/dist/components/MapEditor/lib/element/line.d.ts +2 -2
  32. package/dist/components/MapEditor/lib/element/line.js +1 -1
  33. package/dist/components/MapEditor/lib/element/marker.d.ts +4 -3
  34. package/dist/components/MapEditor/lib/element/marker.js +2 -2
  35. package/dist/components/MapEditor/lib/element/polygon.d.ts +2 -2
  36. package/dist/components/MapEditor/lib/element/polygon.js +2 -2
  37. package/dist/components/MapEditor/lib/element/types.d.ts +2 -3
  38. package/dist/components/MapEditor/lib/geometry_manager.d.ts +12 -29
  39. package/dist/components/MapEditor/lib/geometry_manager.js +44 -160
  40. package/dist/components/MapEditor/lib/geometry_manager_interactive.d.ts +33 -0
  41. package/dist/components/MapEditor/lib/geometry_manager_interactive.js +102 -0
  42. package/dist/components/MapEditor/lib/map_layer/abstract.d.ts +2 -1
  43. package/dist/components/MapEditor/lib/map_layer/abstract.js +25 -22
  44. package/dist/components/MapEditor/lib/map_layer/fill.js +2 -4
  45. package/dist/components/MapEditor/lib/map_layer/line.js +1 -1
  46. package/dist/components/MapEditor/lib/map_layer/symbol.js +1 -1
  47. package/dist/components/MapEditor/lib/selection.d.ts +11 -0
  48. package/dist/components/MapEditor/lib/selection.js +70 -0
  49. package/dist/components/MapEditor/lib/state/constants.js +5 -6
  50. package/dist/components/MapEditor/lib/state/history.d.ts +14 -0
  51. package/dist/components/MapEditor/lib/state/history.js +53 -0
  52. package/dist/components/MapEditor/lib/state/manager.d.ts +7 -10
  53. package/dist/components/MapEditor/lib/state/manager.js +19 -54
  54. package/dist/components/MapEditor/lib/state/reader.d.ts +6 -4
  55. package/dist/components/MapEditor/lib/state/reader.js +70 -18
  56. package/dist/components/MapEditor/lib/state/types.d.ts +19 -2
  57. package/dist/components/MapEditor/lib/state/utils.d.ts +2 -0
  58. package/dist/components/MapEditor/lib/state/utils.js +12 -0
  59. package/dist/components/MapEditor/lib/state/writer.d.ts +6 -4
  60. package/dist/components/MapEditor/lib/state/writer.js +59 -19
  61. package/dist/components/MapEditor/lib/symbols.d.ts +1 -1
  62. package/dist/components/MapEditor/lib/symbols.js +47 -28
  63. package/dist/components/MapEditor/lib/utils/event_handler.d.ts +10 -0
  64. package/dist/components/MapEditor/lib/utils/event_handler.js +39 -0
  65. package/dist/components/MapEditor/lib/utils/geometry.d.ts +12 -0
  66. package/dist/components/MapEditor/lib/utils/geometry.js +87 -0
  67. package/dist/components/MapEditor/lib/utils/types.d.ts +2 -0
  68. package/dist/components/MapEditor/lib/utils/types.js +1 -0
  69. package/dist/components/MapEditor/style/button.scss +115 -0
  70. package/dist/components/MapEditor/style/index.scss +3 -0
  71. package/dist/components/MapEditor/style/layout.scss +20 -0
  72. package/dist/components/MapEditor/style/other.scss +10 -0
  73. package/dist/utils/location.d.ts +1 -0
  74. package/dist/utils/location.js +181 -0
  75. package/dist/utils/map_style.d.ts +2 -2
  76. package/dist/utils/map_style.js +2 -2
  77. package/package.json +29 -29
  78. package/dist/components/MapEditor/components/SymbolSelector.svelte +0 -110
  79. package/dist/components/MapEditor/components/SymbolSelector.svelte.d.ts +0 -8
  80. package/dist/components/MapEditor/lib/utils.d.ts +0 -6
  81. package/dist/components/MapEditor/lib/utils.js +0 -23
  82. /package/dist/components/MapEditor/lib/{geocoder.d.ts → utils/geocoder.d.ts} +0 -0
  83. /package/dist/components/MapEditor/lib/{geocoder.js → utils/geocoder.js} +0 -0
@@ -1,14 +1,18 @@
1
1
  <script lang="ts">
2
+ import '../style/index.scss';
2
3
  import Editor from './Editor.svelte';
3
- import type { GeometryManager } from '../lib/geometry_manager.js';
4
4
  import SidebarPanel from './SidebarPanel.svelte';
5
+ import DialogShareMap from './DialogShare.svelte';
6
+ import PanelFile from './PanelFile.svelte';
7
+ import type { GeometryManagerInteractive } from '../lib/geometry_manager_interactive.js';
5
8
 
6
- const { geometryManager, width }: { geometryManager: GeometryManager; width: number } = $props();
9
+ const { geometryManager }: { geometryManager: GeometryManagerInteractive } = $props();
7
10
 
11
+ let panelShareMap: DialogShareMap | null = null;
8
12
  let history = geometryManager.state;
9
- let undoEnabled = $state(geometryManager.state.undoEnabled);
10
- let redoEnabled = $state(geometryManager.state.redoEnabled);
11
- let activeElement = geometryManager.selectedElement;
13
+ let undoEnabled = $state(geometryManager.state.history.undoEnabled);
14
+ let redoEnabled = $state(geometryManager.state.history.redoEnabled);
15
+ let activeElement = geometryManager.selection.selectedElement;
12
16
 
13
17
  function importGeoJSON() {
14
18
  const input = document.createElement('input');
@@ -47,58 +51,51 @@
47
51
  URL.revokeObjectURL(url);
48
52
  }
49
53
 
50
- function getLink() {
51
- const url = new URL(window.location.href);
52
- url.hash = geometryManager.state.getHash();
53
- return url.href;
54
- }
55
-
56
- function copyLink() {
57
- navigator.clipboard.writeText(getLink()).then(
58
- () => alert('Link copied to clipboard!'),
59
- () => alert('Failed to copy link. Please try again.')
60
- );
61
- }
62
-
63
- function copyEmbedCode() {
64
- const html = `<iframe style="width:100%; height:60vh" src="${getLink()}"></iframe>`;
65
- navigator.clipboard.writeText(html).then(
66
- () => alert('Embed code copied to clipboard!'),
67
- () => alert('Failed to copy embed code. Please try again.')
68
- );
54
+ function addNewElement(type: 'marker' | 'line' | 'polygon' | 'circle') {
55
+ activeElement.set(geometryManager.addNewElement(type));
69
56
  }
70
57
  </script>
71
58
 
72
- <div class="sidebar" style="width: {width}px;">
59
+ <div class="sidebar">
73
60
  <div style="margin-bottom: 36px;">
74
- <div class="flex flex-two">
75
- <button onclick={() => history.undo()} disabled={!$undoEnabled}>Undo</button>
76
- <button onclick={() => history.redo()} disabled={!$redoEnabled}>Redo</button>
61
+ <div class="grid2">
62
+ <button class="btn" onclick={() => history.undo()} disabled={!$undoEnabled}>Undo</button>
63
+ <button class="btn" onclick={() => history.redo()} disabled={!$redoEnabled}>Redo</button>
77
64
  </div>
78
- <SidebarPanel title="Share map" open={false}>
79
- <div class="flex flex-one">
80
- <button value="Link" onclick={copyLink}>Link</button>
81
- <button onclick={copyEmbedCode}>Embed Code</button>
65
+ <hr class="thick" />
66
+ <SidebarPanel title="Map">
67
+ <PanelFile manager={geometryManager} />
68
+ <div class="grid1">
69
+ <button class="btn" onclick={() => panelShareMap?.open()}>Share/Embed</button>
70
+ <DialogShareMap bind:this={panelShareMap} bind:state={() => geometryManager.state, () => {}} />
82
71
  </div>
83
72
  </SidebarPanel>
73
+ <hr class="thick" />
84
74
  <SidebarPanel title="Import/Export" open={false}>
85
- <div class="flex flex-one">
86
- <button onclick={importGeoJSON}>Import GeoJSON</button>
87
- <button onclick={exportGeoJSON}>Export GeoJSON</button>
88
- </div>
75
+ <label
76
+ >GeoJSON:
77
+ <div class="grid2">
78
+ <button class="btn" onclick={importGeoJSON}>Import</button>
79
+ <button class="btn" onclick={exportGeoJSON} data-testid="btnExportGeoJSON">Export</button>
80
+ </div>
81
+ </label>
89
82
  </SidebarPanel>
83
+ <hr class="thick" />
90
84
  <SidebarPanel title="Add new">
91
- <div class="flex flex-two">
92
- <button onclick={() => activeElement.set(geometryManager.addNewMarker())}>Marker</button>
93
- <button onclick={() => activeElement.set(geometryManager.addNewLine())}>Line</button>
94
- <button onclick={() => activeElement.set(geometryManager.addNewPolygon())}>Polygon</button>
95
- <button disabled>Circle</button>
85
+ <div class="grid2">
86
+ <button class="btn" onclick={() => addNewElement('marker')}>Marker</button>
87
+ <button class="btn" onclick={() => addNewElement('line')}>Line</button>
88
+ <button class="btn" onclick={() => addNewElement('polygon')}>Polygon</button>
89
+ <button class="btn" onclick={() => addNewElement('circle')}>Circle</button>
96
90
  </div>
97
91
  </SidebarPanel>
92
+ <hr class="thick" />
98
93
  <Editor element={$activeElement} />
94
+ <hr class="thick" />
99
95
  <SidebarPanel title="Actions" disabled={!$activeElement}>
100
- <div class="flex flex-two">
96
+ <div class="grid2">
101
97
  <button
98
+ class="btn"
102
99
  onclick={() => {
103
100
  $activeElement!.delete();
104
101
  geometryManager.state.log();
@@ -106,26 +103,24 @@
106
103
  >
107
104
  </div>
108
105
  </SidebarPanel>
106
+ <hr class="thick" />
109
107
  <SidebarPanel title="Help" open={false}>
110
- Submit bugs and feature requests as
111
- <a
112
- id="github_link"
113
- href="https://github.com/versatiles-org/node-versatiles-svelte/issues"
114
- target="_blank"
115
- aria-label="Repository on GitHub">GitHub issues</a
116
- >
108
+ <p>
109
+ Submit bugs and feature requests as
110
+ <a
111
+ id="github_link"
112
+ href="https://github.com/versatiles-org/node-versatiles-svelte/issues"
113
+ target="_blank"
114
+ aria-label="Repository on GitHub">GitHub Issues</a
115
+ >
116
+ </p>
117
117
  </SidebarPanel>
118
118
  </div>
119
119
  </div>
120
120
 
121
121
  <style>
122
122
  .sidebar {
123
- --color-btn: #336680;
124
- --color-bg: #ffffff;
125
- --color-text: #000000;
126
- --gap: 10px;
127
-
128
- background-color: rgb(from var(--color-bg) r g b/ 0.7);
123
+ background: color-mix(in srgb, var(--color-bg) 80%, transparent);
129
124
  backdrop-filter: blur(10px);
130
125
  box-sizing: border-box;
131
126
  color: var(--color-text);
@@ -136,49 +131,7 @@
136
131
  position: absolute;
137
132
  right: 0;
138
133
  top: 0;
139
- width: 200px;
140
-
141
- .flex {
142
- --gap: 5px;
143
- align-items: center;
144
- display: flex;
145
- flex-wrap: wrap;
146
- gap: var(--gap);
147
- justify-content: space-between;
148
- margin: var(--gap) 0 var(--gap);
149
- width: 100%;
150
- }
151
- .flex-two button {
152
- flex-grow: 1;
153
- flex-basis: 0;
154
- width: 40%;
155
- }
156
-
157
- .flex-one button {
158
- width: 100%;
159
- }
160
-
161
- button {
162
- background-color: var(--color-btn);
163
- border: 2px solid var(--color-btn);
164
- border-radius: 0.2em;
165
- color: var(--color-bg);
166
- cursor: pointer;
167
- font-weight: 600;
168
- padding: 0.4em 1em;
169
- transition:
170
- background-color 0.1s ease-in-out,
171
- color 0.1s ease-in-out;
172
-
173
- &:not([disabled]):hover {
174
- background-color: var(--color-bg);
175
- color: var(--color-btn);
176
- }
177
- &:disabled {
178
- cursor: not-allowed;
179
- opacity: 0.5;
180
- }
181
- }
134
+ width: 250px;
182
135
  }
183
136
 
184
137
  a {
@@ -1,7 +1,7 @@
1
- import type { GeometryManager } from '../lib/geometry_manager.js';
1
+ import '../style/index.scss';
2
+ import type { GeometryManagerInteractive } from '../lib/geometry_manager_interactive.js';
2
3
  type $$ComponentProps = {
3
- geometryManager: GeometryManager;
4
- width: number;
4
+ geometryManager: GeometryManagerInteractive;
5
5
  };
6
6
  declare const Sidebar: import("svelte").Component<$$ComponentProps, {}, "">;
7
7
  type Sidebar = ReturnType<typeof Sidebar>;
@@ -25,7 +25,7 @@
25
25
 
26
26
  <style>
27
27
  .panel {
28
- margin: 1em 0;
28
+ margin: 0;
29
29
 
30
30
  .header {
31
31
  background: none;
@@ -45,6 +45,7 @@
45
45
  }
46
46
 
47
47
  .chevron {
48
+ border-radius: 1em;
48
49
  box-sizing: border-box;
49
50
  display: block;
50
51
  height: 1em;
@@ -52,7 +53,7 @@
52
53
  padding: 0;
53
54
  position: absolute;
54
55
  right: 0.4em;
55
- top: 0;
56
+ top: 0.05em;
56
57
  width: 1em;
57
58
 
58
59
  svg {
@@ -64,20 +65,26 @@
64
65
  width: 100%;
65
66
  }
66
67
  }
68
+
69
+ &:focus {
70
+ outline: none;
71
+ .chevron {
72
+ outline: 1px solid var(--color-blue);
73
+ outline-offset: 2px;
74
+ }
75
+ }
67
76
  }
68
77
 
69
78
  .content {
70
79
  box-sizing: border-box;
71
80
  height: 0;
72
- margin: var(--gap) 0;
81
+ margin: 0;
73
82
  overflow: hidden;
74
83
  padding: 0;
75
84
  }
76
85
  }
77
86
 
78
87
  .open {
79
- margin-bottom: 2em;
80
-
81
88
  .header {
82
89
  .chevron {
83
90
  svg {
@@ -88,6 +95,7 @@
88
95
 
89
96
  .content {
90
97
  height: auto;
98
+ overflow: visible;
91
99
  }
92
100
  }
93
101
 
@@ -1,18 +1,22 @@
1
- import type { ElementPoint, SelectionNode, SelectionNodeUpdater } from './types.js';
1
+ import type { SelectionNode, SelectionNodeUpdater } from './types.js';
2
+ import type { GeoPoint } from '../utils/types.js';
2
3
  import type { GeometryManager } from '../geometry_manager.js';
3
4
  import type { StateElement } from '../state/types.js';
5
+ import type { GeometryManagerInteractive } from '../geometry_manager_interactive.js';
4
6
  export declare abstract class AbstractElement {
5
7
  protected readonly canvas: HTMLElement;
6
8
  protected readonly map: maplibregl.Map;
7
9
  protected readonly source: maplibregl.GeoJSONSource;
8
10
  protected readonly slug: string;
9
11
  protected isSelected: boolean;
10
- readonly manager: GeometryManager;
12
+ readonly manager: GeometryManager | GeometryManagerInteractive;
11
13
  readonly sourceId: string;
12
- constructor(manager: GeometryManager);
14
+ constructor(manager: GeometryManager | GeometryManagerInteractive);
13
15
  select(value: boolean): void;
14
- protected randomPositions(length: number): ElementPoint[];
16
+ protected randomPositions(length: number): GeoPoint[];
17
+ protected randomRadius(): number;
15
18
  delete(): void;
19
+ getGeoJSON(): GeoJSON.Feature;
16
20
  abstract destroy(): void;
17
21
  abstract getFeature(includeProperties?: boolean): GeoJSON.Feature;
18
22
  abstract getSelectionNodes(): SelectionNode[];
@@ -21,10 +21,10 @@ export class AbstractElement {
21
21
  }
22
22
  randomPositions(length) {
23
23
  const points = [];
24
+ const bounds = this.map.getBounds();
24
25
  for (let i = 0; i < length; i++) {
25
26
  const xr = Math.random() * 0.5 + 0.25;
26
27
  const yr = Math.random() * 0.5 + 0.25;
27
- const bounds = this.map.getBounds();
28
28
  points.push([
29
29
  (1 - xr) * bounds.getWest() + xr * bounds.getEast(),
30
30
  (1 - yr) * bounds.getSouth() + yr * bounds.getNorth()
@@ -32,8 +32,17 @@ export class AbstractElement {
32
32
  }
33
33
  return points;
34
34
  }
35
+ randomRadius() {
36
+ const bounds = this.map.getBounds();
37
+ const width = bounds.getEast() - bounds.getWest();
38
+ const height = bounds.getNorth() - bounds.getSouth();
39
+ return Math.sqrt(width * height) * 10000;
40
+ }
35
41
  delete() {
36
42
  this.manager.removeElement(this);
37
43
  this.destroy();
38
44
  }
45
+ getGeoJSON() {
46
+ return this.getFeature(true);
47
+ }
39
48
  }
@@ -1,8 +1,9 @@
1
1
  import { AbstractElement } from './abstract.js';
2
2
  import type { GeometryManager } from '../geometry_manager.js';
3
- import type { ElementPath, SelectionNode, SelectionNodeUpdater } from './types.js';
3
+ import type { SelectionNode, SelectionNodeUpdater } from './types.js';
4
+ import type { GeoPath } from '../utils/types.js';
4
5
  export declare abstract class AbstractPathElement extends AbstractElement {
5
- path: ElementPath;
6
+ path: GeoPath;
6
7
  protected readonly isLine: boolean;
7
8
  constructor(manager: GeometryManager, isLine: boolean);
8
9
  protected handleDrag(e: maplibregl.MapMouseEvent): void;
@@ -1,5 +1,5 @@
1
1
  import { AbstractElement } from './abstract.js';
2
- import { getMiddlePoint, lat2mercator, mercator2lat } from '../utils.js';
2
+ import { getMiddlePoint, lat2mercator, mercator2lat } from '../utils/geometry.js';
3
3
  export class AbstractPathElement extends AbstractElement {
4
4
  path = [];
5
5
  isLine;
@@ -20,11 +20,14 @@ export class AbstractPathElement extends AbstractElement {
20
20
  x0 = lng;
21
21
  this.path = this.path.map(([x, y]) => [x + dx, mercator2lat(lat2mercator(y) + dy)]);
22
22
  this.source.setData(this.getFeature(false));
23
- this.manager.drawSelectionNodes();
23
+ this.manager.selection?.updateSelectionNodes();
24
24
  e.preventDefault();
25
25
  };
26
26
  this.manager.map.on('mousemove', moveHandler);
27
- this.manager.map.once('mouseup', () => this.manager.map.off('mousemove', moveHandler));
27
+ this.manager.map.once('mouseup', () => {
28
+ this.manager.map.off('mousemove', moveHandler);
29
+ this.manager.state?.log();
30
+ });
28
31
  e.preventDefault();
29
32
  }
30
33
  getSelectionNodes() {
@@ -0,0 +1,25 @@
1
+ import type { GeometryManager } from '../geometry_manager.js';
2
+ import type { SelectionNode, SelectionNodeUpdater } from './types.js';
3
+ import type { GeoPoint } from '../utils/types.js';
4
+ import { MapLayerFill } from '../map_layer/fill.js';
5
+ import { MapLayerLine } from '../map_layer/line.js';
6
+ import type { StateElementCircle } from '../state/types.js';
7
+ import { AbstractElement } from './abstract.js';
8
+ export declare class CircleElement extends AbstractElement {
9
+ readonly fillLayer: MapLayerFill;
10
+ readonly strokeLayer: MapLayerLine;
11
+ point: GeoPoint;
12
+ radius: number;
13
+ constructor(manager: GeometryManager, point?: GeoPoint, radius?: number);
14
+ getSelectionNodes(): SelectionNode[];
15
+ getSelectionNodeUpdater(properties?: Record<string, unknown>): SelectionNodeUpdater | undefined;
16
+ select(value: boolean): void;
17
+ getFeature(includeProperties?: boolean): GeoJSON.Feature<GeoJSON.Polygon>;
18
+ getGeoJSON(): GeoJSON.Feature<GeoJSON.Point>;
19
+ destroy(): void;
20
+ getState(): StateElementCircle;
21
+ static fromState(manager: GeometryManager, state: StateElementCircle): CircleElement;
22
+ static fromGeoJSON(manager: GeometryManager, feature: GeoJSON.Feature<GeoJSON.Point, {
23
+ radius: number;
24
+ }>): CircleElement;
25
+ }
@@ -0,0 +1,118 @@
1
+ import { MapLayerFill } from '../map_layer/fill.js';
2
+ import { MapLayerLine } from '../map_layer/line.js';
3
+ import { AbstractElement } from './abstract.js';
4
+ import { circle, distance } from '../utils/geometry.js';
5
+ export class CircleElement extends AbstractElement {
6
+ fillLayer;
7
+ strokeLayer;
8
+ point;
9
+ radius;
10
+ constructor(manager, point, radius) {
11
+ super(manager);
12
+ this.point = point ?? this.randomPositions(1)[0];
13
+ this.radius = radius ?? this.randomRadius();
14
+ this.fillLayer = new MapLayerFill(manager, 'fill' + this.slug, this.sourceId);
15
+ this.fillLayer.on('click', () => this.manager.selection?.selectElement(this));
16
+ this.strokeLayer = new MapLayerLine(manager, 'line' + this.slug, this.sourceId);
17
+ this.strokeLayer.on('click', () => this.manager.selection?.selectElement(this));
18
+ this.source.setData(this.getFeature());
19
+ }
20
+ getSelectionNodes() {
21
+ return [
22
+ { index: 0, coordinates: this.point },
23
+ ...circle(this.point, this.radius, 4).map((coordinates) => ({
24
+ index: 1,
25
+ transparent: true,
26
+ coordinates
27
+ }))
28
+ ];
29
+ }
30
+ getSelectionNodeUpdater(properties) {
31
+ if (properties == undefined)
32
+ return;
33
+ if (properties.index == 0) {
34
+ return {
35
+ update: (lng, lat) => {
36
+ this.point[0] = lng;
37
+ this.point[1] = lat;
38
+ this.source.setData(this.getFeature(false));
39
+ },
40
+ delete: () => this.delete()
41
+ };
42
+ }
43
+ else {
44
+ return {
45
+ update: (lng, lat) => {
46
+ this.radius = distance([lng, lat], this.point);
47
+ this.source.setData(this.getFeature(false));
48
+ },
49
+ delete: () => this.delete()
50
+ };
51
+ }
52
+ }
53
+ select(value) {
54
+ super.select(value);
55
+ this.fillLayer.isSelected = value;
56
+ this.strokeLayer.isSelected = value;
57
+ }
58
+ getFeature(includeProperties = false) {
59
+ const coordinates = circle(this.point, this.radius, 72);
60
+ coordinates.push(coordinates[0]); // Close the circle
61
+ return {
62
+ type: 'Feature',
63
+ properties: includeProperties
64
+ ? {
65
+ ...this.fillLayer.getGeoJSONProperties(),
66
+ ...this.strokeLayer.getGeoJSONProperties(),
67
+ 'circle-center-x': this.point[0],
68
+ 'circle-center-y': this.point[1],
69
+ 'circle-radius': this.radius
70
+ }
71
+ : {},
72
+ geometry: { type: 'Polygon', coordinates: [coordinates] }
73
+ };
74
+ }
75
+ getGeoJSON() {
76
+ return {
77
+ type: 'Feature',
78
+ properties: {
79
+ ...this.fillLayer.getGeoJSONProperties(),
80
+ ...this.strokeLayer.getGeoJSONProperties(),
81
+ subType: 'Circle',
82
+ radius: this.radius
83
+ },
84
+ geometry: { type: 'Point', coordinates: this.point }
85
+ };
86
+ }
87
+ destroy() {
88
+ this.fillLayer.destroy();
89
+ this.strokeLayer.destroy();
90
+ this.map.removeSource(this.sourceId);
91
+ }
92
+ getState() {
93
+ return {
94
+ type: 'circle',
95
+ point: this.point,
96
+ radius: this.radius,
97
+ style: this.fillLayer.getState(),
98
+ strokeStyle: this.strokeLayer.getState()
99
+ };
100
+ }
101
+ static fromState(manager, state) {
102
+ const element = new CircleElement(manager, state.point, state.radius);
103
+ if (state.style)
104
+ element.fillLayer.setState(state.style);
105
+ if (state.strokeStyle)
106
+ element.strokeLayer.setState(state.strokeStyle);
107
+ return element;
108
+ }
109
+ static fromGeoJSON(manager, feature) {
110
+ const properties = feature.properties;
111
+ const center = feature.geometry.coordinates;
112
+ const radius = feature.properties.radius;
113
+ const element = new CircleElement(manager, center, radius);
114
+ element.fillLayer.setGeoJSONProperties(properties);
115
+ element.strokeLayer.setGeoJSONProperties(properties);
116
+ return element;
117
+ }
118
+ }
@@ -1,11 +1,11 @@
1
1
  import type { GeometryManager } from '../geometry_manager.js';
2
- import type { ElementPath } from './types.js';
2
+ import type { GeoPath } from '../utils/types.js';
3
3
  import { MapLayerLine } from '../map_layer/line.js';
4
4
  import { AbstractPathElement } from './abstract_path.js';
5
5
  import type { StateElementLine } from '../state/types.js';
6
6
  export declare class LineElement extends AbstractPathElement {
7
7
  readonly layer: MapLayerLine;
8
- constructor(manager: GeometryManager, line?: ElementPath);
8
+ constructor(manager: GeometryManager, line?: GeoPath);
9
9
  select(value: boolean): void;
10
10
  getFeature(includeProperties?: boolean): GeoJSON.Feature<GeoJSON.LineString>;
11
11
  destroy(): void;
@@ -6,7 +6,7 @@ export class LineElement extends AbstractPathElement {
6
6
  super(manager, true);
7
7
  this.path = line ?? this.randomPositions(2);
8
8
  this.layer = new MapLayerLine(manager, 'line' + this.slug, this.sourceId);
9
- this.layer.on('click', () => this.manager.selectElement(this));
9
+ this.layer.on('click', () => this.manager.selection?.selectElement(this));
10
10
  this.layer.on('mousedown', (e) => {
11
11
  if (!this.isSelected)
12
12
  return;
@@ -1,12 +1,13 @@
1
1
  import { AbstractElement } from './abstract.js';
2
2
  import type { GeometryManager } from '../geometry_manager.js';
3
- import type { ElementPoint, SelectionNode, SelectionNodeUpdater } from './types.js';
3
+ import type { SelectionNode, SelectionNodeUpdater } from './types.js';
4
4
  import { MapLayerSymbol } from '../map_layer/symbol.js';
5
5
  import type { StateElementMarker } from '../state/types.js';
6
+ import type { GeoPoint } from '../utils/types.js';
6
7
  export declare class MarkerElement extends AbstractElement {
7
8
  readonly layer: MapLayerSymbol;
8
- point: ElementPoint;
9
- constructor(manager: GeometryManager, point?: ElementPoint);
9
+ point: GeoPoint;
10
+ constructor(manager: GeometryManager, point?: GeoPoint);
10
11
  select(value: boolean): void;
11
12
  getFeature(includeProperties?: boolean): GeoJSON.Feature<GeoJSON.Point>;
12
13
  getSelectionNodes(): SelectionNode[];
@@ -2,12 +2,12 @@ import { AbstractElement } from './abstract.js';
2
2
  import { MapLayerSymbol } from '../map_layer/symbol.js';
3
3
  export class MarkerElement extends AbstractElement {
4
4
  layer;
5
- point = [0, 0];
5
+ point;
6
6
  constructor(manager, point) {
7
7
  super(manager);
8
8
  this.point = point ?? this.randomPositions(1)[0];
9
9
  this.layer = new MapLayerSymbol(manager, 'symbol' + this.slug, this.sourceId);
10
- this.layer.on('click', () => this.manager.selectElement(this));
10
+ this.layer.on('click', () => this.manager.selection?.selectElement(this));
11
11
  this.source.setData(this.getFeature());
12
12
  }
13
13
  select(value) {
@@ -1,5 +1,5 @@
1
1
  import type { GeometryManager } from '../geometry_manager.js';
2
- import type { ElementPath } from './types.js';
2
+ import type { GeoPath } from '../utils/types.js';
3
3
  import { MapLayerFill } from '../map_layer/fill.js';
4
4
  import { MapLayerLine } from '../map_layer/line.js';
5
5
  import { AbstractPathElement } from './abstract_path.js';
@@ -7,7 +7,7 @@ import type { StateElementPolygon } from '../state/types.js';
7
7
  export declare class PolygonElement extends AbstractPathElement {
8
8
  readonly fillLayer: MapLayerFill;
9
9
  readonly strokeLayer: MapLayerLine;
10
- constructor(manager: GeometryManager, polygon?: ElementPath);
10
+ constructor(manager: GeometryManager, polygon?: GeoPath);
11
11
  select(value: boolean): void;
12
12
  getFeature(includeProperties?: boolean): GeoJSON.Feature<GeoJSON.Polygon>;
13
13
  destroy(): void;
@@ -8,14 +8,14 @@ export class PolygonElement extends AbstractPathElement {
8
8
  super(manager, false);
9
9
  this.path = polygon ?? this.randomPositions(3);
10
10
  this.fillLayer = new MapLayerFill(manager, 'fill' + this.slug, this.sourceId);
11
- this.fillLayer.on('click', () => this.manager.selectElement(this));
11
+ this.fillLayer.on('click', () => this.manager.selection?.selectElement(this));
12
12
  this.fillLayer.on('mousedown', (e) => {
13
13
  if (!this.isSelected)
14
14
  return;
15
15
  this.handleDrag(e);
16
16
  });
17
17
  this.strokeLayer = new MapLayerLine(manager, 'line' + this.slug, this.sourceId);
18
- this.strokeLayer.on('click', () => this.manager.selectElement(this));
18
+ this.strokeLayer.on('click', () => this.manager.selection?.selectElement(this));
19
19
  this.source.setData(this.getFeature());
20
20
  }
21
21
  select(value) {
@@ -1,7 +1,6 @@
1
- export type ElementPoint = [number, number];
2
- export type ElementPath = ElementPoint[];
1
+ import type { GeoPoint } from '../utils/types.js';
3
2
  export interface SelectionNode {
4
- coordinates: ElementPoint;
3
+ coordinates: GeoPoint;
5
4
  index: number;
6
5
  transparent?: boolean;
7
6
  }