@versatiles/svelte 2.0.1 → 2.1.1
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.
- package/dist/components/BBoxMap/BBoxMap.svelte +39 -19
- package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +1 -1
- package/dist/components/BBoxMap/lib/bbox.d.ts +5 -2
- package/dist/components/BBoxMap/lib/bbox.js +33 -24
- package/dist/components/BasicMap/BasicMap.svelte +22 -9
- package/dist/components/BasicMap/BasicMap.svelte.d.ts +2 -1
- package/dist/components/MapEditor/MapEditor.svelte +51 -20
- package/dist/components/MapEditor/components/Dialog.svelte +92 -0
- package/dist/components/MapEditor/components/Dialog.svelte.d.ts +17 -0
- package/dist/components/MapEditor/components/DialogFile.svelte +112 -0
- package/dist/components/MapEditor/components/DialogFile.svelte.d.ts +6 -0
- package/dist/components/MapEditor/components/DialogShare.svelte +216 -0
- package/dist/components/MapEditor/components/DialogShare.svelte.d.ts +10 -0
- package/dist/components/MapEditor/components/Editor.svelte +6 -14
- package/dist/components/MapEditor/components/EditorFill.svelte +3 -3
- package/dist/components/MapEditor/components/EditorStroke.svelte +3 -3
- package/dist/components/MapEditor/components/EditorSymbol.svelte +9 -9
- package/dist/components/MapEditor/components/InputRow.svelte +2 -3
- package/dist/components/MapEditor/components/PanelFile.svelte +73 -0
- package/dist/components/MapEditor/components/PanelFile.svelte.d.ts +7 -0
- package/dist/components/MapEditor/components/PanelSymbolSelector.svelte +82 -0
- package/dist/components/MapEditor/components/PanelSymbolSelector.svelte.d.ts +8 -0
- package/dist/components/MapEditor/components/Sidebar.svelte +51 -98
- package/dist/components/MapEditor/components/Sidebar.svelte.d.ts +3 -3
- package/dist/components/MapEditor/components/SidebarPanel.svelte +13 -5
- package/dist/components/MapEditor/lib/element/abstract.d.ts +8 -4
- package/dist/components/MapEditor/lib/element/abstract.js +10 -1
- package/dist/components/MapEditor/lib/element/abstract_path.d.ts +3 -2
- package/dist/components/MapEditor/lib/element/abstract_path.js +6 -3
- package/dist/components/MapEditor/lib/element/circle.d.ts +25 -0
- package/dist/components/MapEditor/lib/element/circle.js +118 -0
- package/dist/components/MapEditor/lib/element/line.d.ts +2 -2
- package/dist/components/MapEditor/lib/element/line.js +1 -1
- package/dist/components/MapEditor/lib/element/marker.d.ts +4 -3
- package/dist/components/MapEditor/lib/element/marker.js +2 -2
- package/dist/components/MapEditor/lib/element/polygon.d.ts +2 -2
- package/dist/components/MapEditor/lib/element/polygon.js +2 -2
- package/dist/components/MapEditor/lib/element/types.d.ts +2 -3
- package/dist/components/MapEditor/lib/geometry_manager.d.ts +12 -29
- package/dist/components/MapEditor/lib/geometry_manager.js +44 -160
- package/dist/components/MapEditor/lib/geometry_manager_interactive.d.ts +33 -0
- package/dist/components/MapEditor/lib/geometry_manager_interactive.js +102 -0
- package/dist/components/MapEditor/lib/map_layer/abstract.d.ts +2 -1
- package/dist/components/MapEditor/lib/map_layer/abstract.js +25 -22
- package/dist/components/MapEditor/lib/map_layer/fill.js +2 -4
- package/dist/components/MapEditor/lib/map_layer/line.js +1 -1
- package/dist/components/MapEditor/lib/map_layer/symbol.d.ts +2 -2
- package/dist/components/MapEditor/lib/map_layer/symbol.js +1 -1
- package/dist/components/MapEditor/lib/selection.d.ts +11 -0
- package/dist/components/MapEditor/lib/selection.js +70 -0
- package/dist/components/MapEditor/lib/state/constants.js +5 -6
- package/dist/components/MapEditor/lib/state/history.d.ts +14 -0
- package/dist/components/MapEditor/lib/state/history.js +53 -0
- package/dist/components/MapEditor/lib/state/manager.d.ts +7 -10
- package/dist/components/MapEditor/lib/state/manager.js +19 -54
- package/dist/components/MapEditor/lib/state/reader.d.ts +6 -4
- package/dist/components/MapEditor/lib/state/reader.js +70 -18
- package/dist/components/MapEditor/lib/state/types.d.ts +19 -2
- package/dist/components/MapEditor/lib/state/utils.d.ts +2 -0
- package/dist/components/MapEditor/lib/state/utils.js +12 -0
- package/dist/components/MapEditor/lib/state/writer.d.ts +6 -4
- package/dist/components/MapEditor/lib/state/writer.js +59 -19
- package/dist/components/MapEditor/lib/symbols.d.ts +1 -1
- package/dist/components/MapEditor/lib/symbols.js +47 -28
- package/dist/components/MapEditor/lib/utils/event_handler.d.ts +10 -0
- package/dist/components/MapEditor/lib/utils/event_handler.js +39 -0
- package/dist/components/MapEditor/lib/utils/geometry.d.ts +12 -0
- package/dist/components/MapEditor/lib/utils/geometry.js +87 -0
- package/dist/components/MapEditor/lib/utils/types.d.ts +2 -0
- package/dist/components/MapEditor/lib/utils/types.js +1 -0
- package/dist/components/MapEditor/style/button.scss +115 -0
- package/dist/components/MapEditor/style/index.scss +3 -0
- package/dist/components/MapEditor/style/layout.scss +20 -0
- package/dist/components/MapEditor/style/other.scss +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/location.d.ts +1 -0
- package/dist/utils/location.js +181 -0
- package/dist/utils/map_style.d.ts +2 -2
- package/dist/utils/map_style.js +2 -2
- package/package.json +29 -29
- package/dist/components/MapEditor/components/SymbolSelector.svelte +0 -110
- package/dist/components/MapEditor/components/SymbolSelector.svelte.d.ts +0 -8
- package/dist/components/MapEditor/lib/utils.d.ts +0 -6
- package/dist/components/MapEditor/lib/utils.js +0 -23
- /package/dist/components/MapEditor/lib/{geocoder.d.ts → utils/geocoder.d.ts} +0 -0
- /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
|
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
|
51
|
-
|
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"
|
59
|
+
<div class="sidebar">
|
73
60
|
<div style="margin-bottom: 36px;">
|
74
|
-
<div class="
|
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
|
-
<
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
<
|
86
|
-
|
87
|
-
<
|
88
|
-
|
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="
|
92
|
-
<button onclick={() =>
|
93
|
-
<button onclick={() =>
|
94
|
-
<button onclick={() =>
|
95
|
-
<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="
|
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
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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-
|
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:
|
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
|
1
|
+
import '../style/index.scss';
|
2
|
+
import type { GeometryManagerInteractive } from '../lib/geometry_manager_interactive.js';
|
2
3
|
type $$ComponentProps = {
|
3
|
-
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:
|
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:
|
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 {
|
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):
|
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 {
|
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:
|
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.
|
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', () =>
|
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 {
|
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?:
|
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 {
|
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:
|
9
|
-
constructor(manager: GeometryManager, point?:
|
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
|
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 {
|
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?:
|
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
|
-
|
2
|
-
export type ElementPath = ElementPoint[];
|
1
|
+
import type { GeoPoint } from '../utils/types.js';
|
3
2
|
export interface SelectionNode {
|
4
|
-
coordinates:
|
3
|
+
coordinates: GeoPoint;
|
5
4
|
index: number;
|
6
5
|
transparent?: boolean;
|
7
6
|
}
|