@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,38 +1,21 @@
|
|
1
|
-
import { type Writable } from 'svelte/store';
|
2
1
|
import type { AbstractElement } from './element/abstract.js';
|
3
|
-
import {
|
4
|
-
import {
|
5
|
-
import {
|
6
|
-
import { Cursor } from './cursor.js';
|
7
|
-
import { SymbolLibrary } from './symbols.js';
|
8
|
-
import { StateManager } from './state/manager.js';
|
2
|
+
import type { GeometryManagerInteractive } from './geometry_manager_interactive.js';
|
3
|
+
import type { SelectionHandler } from './selection.js';
|
4
|
+
import type { StateManager } from './state/manager.js';
|
9
5
|
import type { StateRoot } from './state/types.js';
|
10
|
-
|
11
|
-
map?: {
|
12
|
-
center: [number, number];
|
13
|
-
zoom: number;
|
14
|
-
};
|
15
|
-
};
|
6
|
+
import { type Writable } from 'svelte/store';
|
16
7
|
export declare class GeometryManager {
|
17
8
|
readonly elements: Writable<AbstractElement[]>;
|
18
9
|
readonly map: maplibregl.Map;
|
19
|
-
readonly selectedElement: Writable<AbstractElement | undefined>;
|
20
10
|
readonly canvas: HTMLElement;
|
21
|
-
readonly
|
22
|
-
readonly
|
23
|
-
readonly state: StateManager;
|
24
|
-
private readonly selectionNodes;
|
11
|
+
readonly state: StateManager | null;
|
12
|
+
readonly selection: SelectionHandler | null;
|
25
13
|
constructor(map: maplibregl.Map);
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
setState(state: StateRoot): void;
|
30
|
-
getElement(index: number): AbstractElement;
|
31
|
-
addNewMarker(): MarkerElement;
|
32
|
-
addNewLine(): LineElement;
|
33
|
-
addNewPolygon(): PolygonElement;
|
34
|
-
private appendElement;
|
14
|
+
isInteractive(): this is GeometryManagerInteractive;
|
15
|
+
clear(): void;
|
16
|
+
protected appendElement(element: AbstractElement): void;
|
35
17
|
removeElement(element: AbstractElement): void;
|
36
|
-
|
37
|
-
|
18
|
+
loadState(state: StateRoot): Promise<void>;
|
19
|
+
setState(state: StateRoot): Promise<void>;
|
20
|
+
getElement(index: number): AbstractElement;
|
38
21
|
}
|
@@ -1,31 +1,26 @@
|
|
1
1
|
import { get, writable } from 'svelte/store';
|
2
|
-
import {
|
2
|
+
import { getMapStyle } from '../../../utils/map_style.js';
|
3
|
+
import { CircleElement } from './element/circle.js';
|
3
4
|
import { LineElement } from './element/line.js';
|
5
|
+
import { MarkerElement } from './element/marker.js';
|
4
6
|
import { PolygonElement } from './element/polygon.js';
|
5
|
-
import { Cursor } from './cursor.js';
|
6
|
-
import { SymbolLibrary } from './symbols.js';
|
7
|
-
import { StateManager } from './state/manager.js';
|
8
7
|
export class GeometryManager {
|
9
8
|
elements;
|
10
9
|
map;
|
11
|
-
selectedElement = writable(undefined);
|
12
10
|
canvas;
|
13
|
-
|
14
|
-
|
15
|
-
state;
|
16
|
-
selectionNodes;
|
11
|
+
state = null;
|
12
|
+
selection = null;
|
17
13
|
constructor(map) {
|
18
14
|
this.elements = writable([]);
|
19
15
|
this.map = map;
|
20
16
|
this.canvas = this.map.getCanvasContainer();
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
const style = getMapStyle({ darkMode: false });
|
18
|
+
style.transition = { duration: 0, delay: 0 };
|
19
|
+
style.sources.selection_nodes = {
|
24
20
|
type: 'geojson',
|
25
21
|
data: { type: 'FeatureCollection', features: [] }
|
26
|
-
}
|
27
|
-
|
28
|
-
map.addLayer({
|
22
|
+
};
|
23
|
+
style.layers.push({
|
29
24
|
id: 'selection_nodes',
|
30
25
|
source: 'selection_nodes',
|
31
26
|
type: 'circle',
|
@@ -39,91 +34,46 @@ export class GeometryManager {
|
|
39
34
|
'circle-stroke-width': 1
|
40
35
|
}
|
41
36
|
});
|
42
|
-
map.
|
43
|
-
const element = get(this.selectedElement);
|
44
|
-
if (element == undefined)
|
45
|
-
return;
|
46
|
-
const feature = map.queryRenderedFeatures(e.point, { layers: ['selection_nodes'] })[0];
|
47
|
-
const selectedNode = element.getSelectionNodeUpdater(feature.properties);
|
48
|
-
if (selectedNode == undefined)
|
49
|
-
return;
|
50
|
-
// @ts-expect-error ensure that the event is ignored by other layers
|
51
|
-
e.ignore = true;
|
52
|
-
e.preventDefault();
|
53
|
-
if (e.originalEvent.shiftKey) {
|
54
|
-
selectedNode.delete();
|
55
|
-
this.drawSelectionNodes();
|
56
|
-
}
|
57
|
-
else {
|
58
|
-
const onMove = (e) => {
|
59
|
-
e.preventDefault();
|
60
|
-
selectedNode.update(e.lngLat.lng, e.lngLat.lat);
|
61
|
-
this.drawSelectionNodes();
|
62
|
-
};
|
63
|
-
map.on('mousemove', onMove);
|
64
|
-
map.once('mouseup', () => {
|
65
|
-
map.off('mousemove', onMove);
|
66
|
-
this.state.log();
|
67
|
-
});
|
68
|
-
}
|
69
|
-
});
|
70
|
-
map.on('mouseenter', 'selection_nodes', () => {
|
71
|
-
this.cursor.togglePrecise('selection_nodes');
|
72
|
-
});
|
73
|
-
map.on('mouseleave', 'selection_nodes', () => {
|
74
|
-
this.cursor.togglePrecise('selection_nodes', false);
|
75
|
-
});
|
76
|
-
map.on('click', (e) => {
|
77
|
-
if (!e.originalEvent.shiftKey)
|
78
|
-
this.selectElement(undefined);
|
79
|
-
e.preventDefault();
|
80
|
-
});
|
81
|
-
this.state = new StateManager(this);
|
37
|
+
map.setStyle(style);
|
82
38
|
}
|
83
|
-
|
84
|
-
|
85
|
-
return;
|
86
|
-
const elements = get(this.elements);
|
87
|
-
elements.forEach((e) => e.select(e == element));
|
88
|
-
this.selectedElement.set(element);
|
89
|
-
this.drawSelectionNodes();
|
39
|
+
isInteractive() {
|
40
|
+
return false;
|
90
41
|
}
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
features: nodes.map((n) => ({
|
96
|
-
type: 'Feature',
|
97
|
-
properties: { index: n.index, opacity: n.transparent ? 0.3 : 1 },
|
98
|
-
geometry: { type: 'Point', coordinates: n.coordinates }
|
99
|
-
}))
|
42
|
+
clear() {
|
43
|
+
this.elements.update((elements) => {
|
44
|
+
elements.forEach((e) => e.destroy());
|
45
|
+
return [];
|
100
46
|
});
|
101
47
|
}
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
zoom: this.map.getZoom()
|
108
|
-
},
|
109
|
-
elements: get(this.elements).map((element) => element.getState())
|
110
|
-
};
|
48
|
+
appendElement(element) {
|
49
|
+
this.elements.update((elements) => [...elements, element]);
|
50
|
+
}
|
51
|
+
removeElement(element) {
|
52
|
+
this.elements.update((elements) => elements.filter((e) => e !== element));
|
111
53
|
}
|
112
|
-
|
54
|
+
async loadState(state) {
|
113
55
|
if (!state)
|
114
56
|
return;
|
115
|
-
this.
|
116
|
-
this.
|
117
|
-
|
118
|
-
|
119
|
-
|
57
|
+
this.clear();
|
58
|
+
this.setState(state);
|
59
|
+
this.state?.history.reset(state);
|
60
|
+
}
|
61
|
+
async setState(state) {
|
62
|
+
if (!state)
|
63
|
+
return;
|
64
|
+
this.clear();
|
120
65
|
if (state.map) {
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
66
|
+
const { center, radius } = state.map;
|
67
|
+
const dy = (radius * 360) / 40074000;
|
68
|
+
const dx = dy / Math.cos((center[1] * Math.PI) / 180);
|
69
|
+
const bounds = [
|
70
|
+
[center[0] - dx, center[1] - dy],
|
71
|
+
[center[0] + dx, center[1] + dy]
|
72
|
+
];
|
73
|
+
this.map.fitBounds(bounds, { animate: false });
|
74
|
+
}
|
75
|
+
if (!this.map.isStyleLoaded()) {
|
76
|
+
await new Promise((r) => this.map.once('styledata', r));
|
127
77
|
}
|
128
78
|
if (state.elements) {
|
129
79
|
const elements = state.elements.map((element) => {
|
@@ -134,6 +84,8 @@ export class GeometryManager {
|
|
134
84
|
return LineElement.fromState(this, element);
|
135
85
|
case 'polygon':
|
136
86
|
return PolygonElement.fromState(this, element);
|
87
|
+
case 'circle':
|
88
|
+
return CircleElement.fromState(this, element);
|
137
89
|
default:
|
138
90
|
throw new Error('Unknown element type');
|
139
91
|
}
|
@@ -144,72 +96,4 @@ export class GeometryManager {
|
|
144
96
|
getElement(index) {
|
145
97
|
return get(this.elements)[index];
|
146
98
|
}
|
147
|
-
addNewMarker() {
|
148
|
-
const element = new MarkerElement(this);
|
149
|
-
this.appendElement(element);
|
150
|
-
this.selectElement(element);
|
151
|
-
return element;
|
152
|
-
}
|
153
|
-
addNewLine() {
|
154
|
-
const element = new LineElement(this);
|
155
|
-
this.appendElement(element);
|
156
|
-
this.selectElement(element);
|
157
|
-
return element;
|
158
|
-
}
|
159
|
-
addNewPolygon() {
|
160
|
-
const element = new PolygonElement(this);
|
161
|
-
this.appendElement(element);
|
162
|
-
this.selectElement(element);
|
163
|
-
return element;
|
164
|
-
}
|
165
|
-
appendElement(element) {
|
166
|
-
this.elements.update((elements) => [...elements, element]);
|
167
|
-
}
|
168
|
-
removeElement(element) {
|
169
|
-
if (get(this.selectedElement) === element)
|
170
|
-
this.selectElement(undefined);
|
171
|
-
this.elements.update((elements) => elements.filter((e) => e !== element));
|
172
|
-
}
|
173
|
-
getGeoJSON() {
|
174
|
-
const center = this.map.getCenter();
|
175
|
-
return {
|
176
|
-
type: 'FeatureCollection',
|
177
|
-
map: {
|
178
|
-
center: [center.lng, center.lat],
|
179
|
-
zoom: this.map.getZoom()
|
180
|
-
},
|
181
|
-
features: get(this.elements).map((element) => element.getFeature(true))
|
182
|
-
};
|
183
|
-
}
|
184
|
-
addGeoJSON(geojson) {
|
185
|
-
if ('map' in geojson && geojson.map) {
|
186
|
-
const { map } = geojson;
|
187
|
-
if (typeof map.zoom === 'number') {
|
188
|
-
this.map.setZoom(map.zoom);
|
189
|
-
}
|
190
|
-
if (Array.isArray(map.center)) {
|
191
|
-
const [lng, lat] = map.center;
|
192
|
-
if (typeof lng === 'number' && typeof lat === 'number') {
|
193
|
-
this.map.setCenter({ lng, lat });
|
194
|
-
}
|
195
|
-
}
|
196
|
-
}
|
197
|
-
for (const feature of geojson.features) {
|
198
|
-
let element;
|
199
|
-
switch (feature.geometry.type) {
|
200
|
-
case 'Point':
|
201
|
-
element = MarkerElement.fromGeoJSON(this, feature);
|
202
|
-
break;
|
203
|
-
case 'LineString':
|
204
|
-
element = LineElement.fromGeoJSON(this, feature);
|
205
|
-
break;
|
206
|
-
case 'Polygon':
|
207
|
-
element = PolygonElement.fromGeoJSON(this, feature);
|
208
|
-
break;
|
209
|
-
default:
|
210
|
-
throw new Error(`Unknown geometry type "${feature.geometry.type}"`);
|
211
|
-
}
|
212
|
-
this.appendElement(element);
|
213
|
-
}
|
214
|
-
}
|
215
99
|
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import type { AbstractElement } from './element/abstract.js';
|
2
|
+
import { CircleElement } from './element/circle.js';
|
3
|
+
import { LineElement } from './element/line.js';
|
4
|
+
import { MarkerElement } from './element/marker.js';
|
5
|
+
import { PolygonElement } from './element/polygon.js';
|
6
|
+
import { GeometryManager } from './geometry_manager.js';
|
7
|
+
import { SelectionHandler } from './selection.js';
|
8
|
+
import { Cursor } from './cursor.js';
|
9
|
+
import { StateManager } from './state/manager.js';
|
10
|
+
import type { StateRoot } from './state/types.js';
|
11
|
+
export type ExtendedGeoJSON = GeoJSON.FeatureCollection & {
|
12
|
+
map?: {
|
13
|
+
center: [number, number];
|
14
|
+
zoom: number;
|
15
|
+
};
|
16
|
+
};
|
17
|
+
export declare class GeometryManagerInteractive extends GeometryManager {
|
18
|
+
readonly selection: SelectionHandler;
|
19
|
+
readonly cursor: Cursor;
|
20
|
+
readonly state: StateManager;
|
21
|
+
constructor(map: maplibregl.Map);
|
22
|
+
clear(): void;
|
23
|
+
isInteractive(): this is GeometryManagerInteractive;
|
24
|
+
removeElement(element: AbstractElement): void;
|
25
|
+
addNewElement(type: 'marker'): MarkerElement;
|
26
|
+
addNewElement(type: 'line'): LineElement;
|
27
|
+
addNewElement(type: 'polygon'): PolygonElement;
|
28
|
+
addNewElement(type: 'circle'): CircleElement;
|
29
|
+
addNewElement(type: 'marker' | 'line' | 'polygon' | 'circle'): AbstractElement;
|
30
|
+
getGeoJSON(): GeoJSON.FeatureCollection;
|
31
|
+
getState(): StateRoot;
|
32
|
+
addGeoJSON(geojson: ExtendedGeoJSON): void;
|
33
|
+
}
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import { get } from 'svelte/store';
|
2
|
+
import { CircleElement } from './element/circle.js';
|
3
|
+
import { LineElement } from './element/line.js';
|
4
|
+
import { MarkerElement } from './element/marker.js';
|
5
|
+
import { PolygonElement } from './element/polygon.js';
|
6
|
+
import { GeometryManager } from './geometry_manager.js';
|
7
|
+
import { SelectionHandler } from './selection.js';
|
8
|
+
import { flatten } from './utils/geometry.js';
|
9
|
+
import { Cursor } from './cursor.js';
|
10
|
+
import { StateManager } from './state/manager.js';
|
11
|
+
export class GeometryManagerInteractive extends GeometryManager {
|
12
|
+
selection;
|
13
|
+
cursor;
|
14
|
+
state;
|
15
|
+
constructor(map) {
|
16
|
+
super(map);
|
17
|
+
this.cursor = new Cursor(map.getCanvasContainer());
|
18
|
+
this.selection = new SelectionHandler(this);
|
19
|
+
this.state = new StateManager(this);
|
20
|
+
}
|
21
|
+
clear() {
|
22
|
+
this.selection.selectElement();
|
23
|
+
super.clear();
|
24
|
+
}
|
25
|
+
isInteractive() {
|
26
|
+
return true;
|
27
|
+
}
|
28
|
+
removeElement(element) {
|
29
|
+
this.selection.selectElement();
|
30
|
+
super.removeElement(element);
|
31
|
+
}
|
32
|
+
addNewElement(type) {
|
33
|
+
const AbstractClass = {
|
34
|
+
marker: MarkerElement,
|
35
|
+
line: LineElement,
|
36
|
+
polygon: PolygonElement,
|
37
|
+
circle: CircleElement
|
38
|
+
}[type];
|
39
|
+
const element = new AbstractClass(this);
|
40
|
+
this.appendElement(element);
|
41
|
+
this.selection.selectElement(element);
|
42
|
+
return element;
|
43
|
+
}
|
44
|
+
getGeoJSON() {
|
45
|
+
const center = this.map.getCenter();
|
46
|
+
return {
|
47
|
+
type: 'FeatureCollection',
|
48
|
+
map: {
|
49
|
+
center: [center.lng, center.lat],
|
50
|
+
zoom: this.map.getZoom()
|
51
|
+
},
|
52
|
+
features: get(this.elements).map((element) => element.getGeoJSON())
|
53
|
+
};
|
54
|
+
}
|
55
|
+
getState() {
|
56
|
+
const center = this.map.getCenter();
|
57
|
+
const bounds = this.map.getBounds();
|
58
|
+
const radiusDegrees = Math.min(bounds.getNorth() - bounds.getSouth(), (bounds.getEast() - bounds.getWest()) * Math.cos((center.lat * Math.PI) / 180)) / 2;
|
59
|
+
const radius = 40074000 * (radiusDegrees / 360);
|
60
|
+
return {
|
61
|
+
map: {
|
62
|
+
center: [center.lng, center.lat],
|
63
|
+
radius
|
64
|
+
},
|
65
|
+
elements: get(this.elements).map((element) => element.getState())
|
66
|
+
};
|
67
|
+
}
|
68
|
+
addGeoJSON(geojson) {
|
69
|
+
if ('map' in geojson && geojson.map) {
|
70
|
+
const { map } = geojson;
|
71
|
+
if (typeof map.zoom === 'number') {
|
72
|
+
this.map.setZoom(map.zoom);
|
73
|
+
}
|
74
|
+
if (Array.isArray(map.center)) {
|
75
|
+
const [lng, lat] = map.center;
|
76
|
+
if (typeof lng === 'number' && typeof lat === 'number') {
|
77
|
+
this.map.setCenter({ lng, lat });
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
for (const feature of flatten(geojson.features)) {
|
82
|
+
let element;
|
83
|
+
const p = feature.properties;
|
84
|
+
switch (feature.geometry.type) {
|
85
|
+
case 'Point':
|
86
|
+
if (p && p.subType == 'Circle' && p.radius != null) {
|
87
|
+
element = CircleElement.fromGeoJSON(this, feature);
|
88
|
+
break;
|
89
|
+
}
|
90
|
+
element = MarkerElement.fromGeoJSON(this, feature);
|
91
|
+
break;
|
92
|
+
case 'LineString':
|
93
|
+
element = LineElement.fromGeoJSON(this, feature);
|
94
|
+
break;
|
95
|
+
case 'Polygon':
|
96
|
+
element = PolygonElement.fromGeoJSON(this, feature);
|
97
|
+
break;
|
98
|
+
}
|
99
|
+
this.appendElement(element);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import type { LayerFill, LayerLine, LayerSymbol } from './types.js';
|
2
2
|
import type { GeometryManager } from '../geometry_manager.js';
|
3
3
|
import type { StateStyle } from '../state/types.js';
|
4
|
+
import type { GeometryManagerInteractive } from '../geometry_manager_interactive.js';
|
4
5
|
type LayerSpec = LayerFill | LayerLine | LayerSymbol;
|
5
6
|
type Events = 'click' | 'mousedown' | 'mousemove' | 'mouseup';
|
6
7
|
type MouseEventHandler = (event: maplibregl.MapMouseEvent) => void;
|
@@ -8,7 +9,7 @@ export declare abstract class MapLayer<T extends LayerSpec> {
|
|
8
9
|
private layout;
|
9
10
|
private paint;
|
10
11
|
protected readonly id: string;
|
11
|
-
readonly manager: GeometryManager;
|
12
|
+
readonly manager: GeometryManager | GeometryManagerInteractive;
|
12
13
|
protected readonly map: maplibregl.Map;
|
13
14
|
eventHandlers: Map<Events, MouseEventHandler[]>;
|
14
15
|
isSelected: boolean;
|
@@ -45,28 +45,31 @@ export class MapLayer {
|
|
45
45
|
handlers.forEach((handler) => handler(e));
|
46
46
|
}
|
47
47
|
addEvents() {
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
this.
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
48
|
+
const manager = this.manager;
|
49
|
+
if (manager.isInteractive()) {
|
50
|
+
this.map.on('mouseenter', this.id, () => {
|
51
|
+
if (this.isSelected)
|
52
|
+
manager.cursor.toggleGrab(this.id);
|
53
|
+
manager.cursor.toggleHover(this.id);
|
54
|
+
});
|
55
|
+
this.map.on('mouseleave', this.id, () => {
|
56
|
+
if (this.isSelected)
|
57
|
+
manager.cursor.toggleGrab(this.id, false);
|
58
|
+
manager.cursor.toggleHover(this.id, false);
|
59
|
+
});
|
60
|
+
this.map.on('click', this.id, (e) => {
|
61
|
+
this.dispatchEvent('click', e);
|
62
|
+
if (this.isSelected)
|
63
|
+
manager.cursor.toggleGrab(this.id);
|
64
|
+
manager.cursor.toggleHover(this.id);
|
65
|
+
e.preventDefault();
|
66
|
+
});
|
67
|
+
this.map.on('mousedown', this.id, (e) => {
|
68
|
+
if (manager.cursor.isPrecise())
|
69
|
+
return;
|
70
|
+
this.dispatchEvent('mousedown', e);
|
71
|
+
});
|
72
|
+
}
|
70
73
|
this.map.on('mouseup', this.id, (e) => this.dispatchEvent('mouseup', e));
|
71
74
|
this.map.on('mousemove', this.id, (e) => this.dispatchEvent('mousemove', e));
|
72
75
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { get, writable } from 'svelte/store';
|
2
2
|
import { MapLayer } from './abstract.js';
|
3
3
|
import { Color } from '@versatiles/style';
|
4
|
-
import { removeDefaultFields } from '../utils.js';
|
4
|
+
import { removeDefaultFields } from '../state/utils.js';
|
5
5
|
const size = 32;
|
6
6
|
export const fillPatterns = new Map([
|
7
7
|
[0, { name: 'solid', fill: undefined }],
|
@@ -86,9 +86,7 @@ export class MapLayerFill extends MapLayer {
|
|
86
86
|
if (properties['fill-opacity'])
|
87
87
|
this.opacity.set(properties['fill-opacity']);
|
88
88
|
if (properties['fill-pattern']) {
|
89
|
-
const pattern = fillPatterns
|
90
|
-
.entries()
|
91
|
-
.find(([, { name }]) => name === properties['fill-pattern']);
|
89
|
+
const pattern = fillPatterns.entries().find(([, { name }]) => name === properties['fill-pattern']);
|
92
90
|
if (pattern)
|
93
91
|
this.pattern.set(pattern[0]);
|
94
92
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import { derived, get, writable } from 'svelte/store';
|
2
2
|
import { MapLayer } from './abstract.js';
|
3
3
|
import { Color } from '@versatiles/style';
|
4
|
-
import { removeDefaultFields } from '../utils.js';
|
4
|
+
import { removeDefaultFields } from '../state/utils.js';
|
5
5
|
export const dashArrays = new Map([
|
6
6
|
[0, { name: 'solid', array: [100] }],
|
7
7
|
[1, { name: 'dashed', array: [2, 4] }],
|
@@ -19,8 +19,8 @@ export declare class MapLayerSymbol extends MapLayer<LayerSymbol> {
|
|
19
19
|
label: Writable<string>;
|
20
20
|
labelAlign: Writable<number>;
|
21
21
|
symbolInfo: import("svelte/store").Readable<import("../symbols.js").SymbolInfo>;
|
22
|
-
textAnchor: import("svelte/store").Readable<"center" | "
|
23
|
-
textVariableAnchor: import("svelte/store").Readable<("center" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "
|
22
|
+
textAnchor: import("svelte/store").Readable<"center" | "left" | "right" | "top" | "bottom" | undefined>;
|
23
|
+
textVariableAnchor: import("svelte/store").Readable<("center" | "top-left" | "top-right" | "bottom-left" | "bottom-right" | "left" | "right" | "top" | "bottom")[] | undefined>;
|
24
24
|
constructor(manager: GeometryManager, id: string, source: string);
|
25
25
|
getState(): StateStyle | undefined;
|
26
26
|
setState(state: StateStyle): void;
|
@@ -2,7 +2,7 @@ import { derived, get, writable } from 'svelte/store';
|
|
2
2
|
import { MapLayer } from './abstract.js';
|
3
3
|
import { Color } from '@versatiles/style';
|
4
4
|
import { getSymbol, getSymbolIndexByName } from '../symbols.js';
|
5
|
-
import { removeDefaultFields } from '../utils.js';
|
5
|
+
import { removeDefaultFields } from '../state/utils.js';
|
6
6
|
export const labelPositions = [
|
7
7
|
{ index: 0, name: 'auto' },
|
8
8
|
{ index: 1, name: 'right', anchor: 'left' },
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { type Writable } from 'svelte/store';
|
2
|
+
import type { AbstractElement } from './element/abstract.js';
|
3
|
+
import type { GeometryManagerInteractive } from './geometry_manager_interactive.js';
|
4
|
+
export declare class SelectionHandler {
|
5
|
+
readonly selectedElement: Writable<AbstractElement | undefined>;
|
6
|
+
private selectionNodes;
|
7
|
+
private manager;
|
8
|
+
constructor(manager: GeometryManagerInteractive);
|
9
|
+
selectElement(element?: AbstractElement): void;
|
10
|
+
updateSelectionNodes(): void;
|
11
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
import { get, writable } from 'svelte/store';
|
2
|
+
export class SelectionHandler {
|
3
|
+
selectedElement = writable(undefined);
|
4
|
+
selectionNodes;
|
5
|
+
manager;
|
6
|
+
constructor(manager) {
|
7
|
+
this.manager = manager;
|
8
|
+
const map = this.manager.map;
|
9
|
+
map.on('mousedown', 'selection_nodes', (e) => {
|
10
|
+
const element = get(this.selectedElement);
|
11
|
+
if (element == null)
|
12
|
+
return;
|
13
|
+
const feature = map.queryRenderedFeatures(e.point, { layers: ['selection_nodes'] })[0];
|
14
|
+
const selectedNode = element.getSelectionNodeUpdater(feature.properties);
|
15
|
+
if (selectedNode == null)
|
16
|
+
return;
|
17
|
+
// @ts-expect-error ensure that the event is ignored by other layers
|
18
|
+
e.ignore = true;
|
19
|
+
e.preventDefault();
|
20
|
+
if (e.originalEvent.shiftKey) {
|
21
|
+
selectedNode.delete();
|
22
|
+
this.updateSelectionNodes();
|
23
|
+
}
|
24
|
+
else {
|
25
|
+
const onMove = (e) => {
|
26
|
+
e.preventDefault();
|
27
|
+
selectedNode.update(e.lngLat.lng, e.lngLat.lat);
|
28
|
+
this.updateSelectionNodes();
|
29
|
+
};
|
30
|
+
map.on('mousemove', onMove);
|
31
|
+
map.once('mouseup', () => {
|
32
|
+
map.off('mousemove', onMove);
|
33
|
+
this.manager.state.log();
|
34
|
+
});
|
35
|
+
}
|
36
|
+
});
|
37
|
+
map.on('mouseenter', 'selection_nodes', () => {
|
38
|
+
this.manager.cursor.togglePrecise('selection_nodes');
|
39
|
+
});
|
40
|
+
map.on('mouseleave', 'selection_nodes', () => {
|
41
|
+
this.manager.cursor.togglePrecise('selection_nodes', false);
|
42
|
+
});
|
43
|
+
map.on('click', (e) => {
|
44
|
+
if (!e.originalEvent.shiftKey)
|
45
|
+
this.selectElement();
|
46
|
+
e.preventDefault();
|
47
|
+
});
|
48
|
+
}
|
49
|
+
selectElement(element) {
|
50
|
+
if (element == get(this.selectedElement))
|
51
|
+
return;
|
52
|
+
const elements = get(this.manager.elements);
|
53
|
+
elements.forEach((e) => e.select(e == element));
|
54
|
+
this.selectedElement.set(element);
|
55
|
+
this.updateSelectionNodes();
|
56
|
+
}
|
57
|
+
updateSelectionNodes() {
|
58
|
+
const nodes = get(this.selectedElement)?.getSelectionNodes() ?? [];
|
59
|
+
if (!this.selectionNodes)
|
60
|
+
this.selectionNodes = this.manager.map.getSource('selection_nodes');
|
61
|
+
this.selectionNodes?.setData({
|
62
|
+
type: 'FeatureCollection',
|
63
|
+
features: nodes.map((n) => ({
|
64
|
+
type: 'Feature',
|
65
|
+
properties: { index: n.index, opacity: n.transparent ? 0.3 : 1 },
|
66
|
+
geometry: { type: 'Point', coordinates: n.coordinates }
|
67
|
+
}))
|
68
|
+
});
|
69
|
+
}
|
70
|
+
}
|