@versatiles/svelte 0.3.0 → 1.0.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 (47) hide show
  1. package/README.md +11 -6
  2. package/dist/components/BBoxMap/AutoComplete.svelte +176 -0
  3. package/dist/components/{AutoComplete.svelte.d.ts → BBoxMap/AutoComplete.svelte.d.ts} +12 -18
  4. package/dist/components/BBoxMap/BBoxMap.svelte +43 -54
  5. package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +4 -17
  6. package/dist/components/BasicMap/BasicMap.svelte +34 -37
  7. package/dist/components/BasicMap/BasicMap.svelte.d.ts +9 -24
  8. package/dist/components/LocatorMap/LocatorMap.svelte +61 -20
  9. package/dist/components/MapEditor/Editor.svelte +25 -0
  10. package/dist/components/MapEditor/Editor.svelte.d.ts +7 -0
  11. package/dist/components/MapEditor/EditorLine.svelte +27 -0
  12. package/dist/components/MapEditor/EditorLine.svelte.d.ts +7 -0
  13. package/dist/components/MapEditor/EditorMarker.svelte +42 -0
  14. package/dist/components/MapEditor/EditorMarker.svelte.d.ts +7 -0
  15. package/dist/components/MapEditor/MapEditor.svelte +99 -0
  16. package/dist/components/MapEditor/MapEditor.svelte.d.ts +4 -0
  17. package/dist/components/MapEditor/editor.scss +16 -0
  18. package/dist/components/MapEditor/lib/element_abstract.d.ts +20 -0
  19. package/dist/components/MapEditor/lib/element_abstract.js +58 -0
  20. package/dist/components/MapEditor/lib/element_line.d.ts +14 -0
  21. package/dist/components/MapEditor/lib/element_line.js +76 -0
  22. package/dist/components/MapEditor/lib/element_marker.d.ts +20 -0
  23. package/dist/components/MapEditor/lib/element_marker.js +191 -0
  24. package/dist/components/MapEditor/lib/geocoder.d.ts +1 -0
  25. package/dist/components/MapEditor/lib/geocoder.js +8 -0
  26. package/dist/components/MapEditor/lib/geometry_manager.d.ts +18 -0
  27. package/dist/components/MapEditor/lib/geometry_manager.js +117 -0
  28. package/dist/components/MapEditor/lib/map_layer.d.ts +14 -0
  29. package/dist/components/MapEditor/lib/map_layer.js +61 -0
  30. package/dist/components/MapEditor/lib/types.d.ts +112 -0
  31. package/dist/components/MapEditor/lib/types.js +1 -0
  32. package/dist/components/MapEditor/lib/utils.d.ts +2 -0
  33. package/dist/components/MapEditor/lib/utils.js +11 -0
  34. package/dist/index.d.ts +2 -1
  35. package/dist/index.js +2 -1
  36. package/dist/utils/draw/bbox.d.ts +2 -9
  37. package/dist/utils/draw/bbox.js +8 -13
  38. package/dist/utils/map_style.d.ts +5 -2
  39. package/dist/utils/map_style.js +13 -6
  40. package/package.json +9 -6
  41. package/dist/components/AutoComplete.svelte +0 -196
  42. package/dist/utils/draw/abstract.d.ts +0 -5
  43. package/dist/utils/draw/abstract.js +0 -2
  44. package/dist/utils/draw/marker.d.ts +0 -24
  45. package/dist/utils/draw/marker.js +0 -97
  46. package/dist/utils/draw/style.d.ts +0 -19
  47. package/dist/utils/draw/style.js +0 -40
@@ -0,0 +1,7 @@
1
+ import type { LineElement } from './lib/element_line.js';
2
+ type $$ComponentProps = {
3
+ element: LineElement;
4
+ };
5
+ declare const EditorLine: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EditorLine = ReturnType<typeof EditorLine>;
7
+ export default EditorLine;
@@ -0,0 +1,42 @@
1
+ <script lang="ts">import {} from './editor.scss';
2
+ import { get } from 'svelte/store';
3
+ import { symbols } from './lib/element_marker.js';
4
+ const symbolList = Array.from(symbols.keys()).sort();
5
+ let { element } = $props();
6
+ let color = $state(get(element.color));
7
+ let halo = $state(get(element.halo));
8
+ let rotate = $state(get(element.rotate));
9
+ let size = $state(get(element.size));
10
+ let symbol = $state(get(element.symbol));
11
+ let label = $state(get(element.label));
12
+ $effect(() => element.color.set(color));
13
+ $effect(() => element.halo.set(halo));
14
+ $effect(() => element.rotate.set(rotate));
15
+ $effect(() => element.size.set(size));
16
+ $effect(() => element.label.set(label));
17
+ $effect(() => element.symbol.set(symbol));
18
+ </script>
19
+
20
+ <div class="row">
21
+ <label for="symbol-input">Symbol</label>
22
+ <select id="symbol-input" bind:value={symbol}>
23
+ {#each symbolList as s}
24
+ <option value={s}>{s}</option>
25
+ {/each}
26
+ </select>
27
+
28
+ <label for="color-input">Color</label>
29
+ <input id="color-input" type="color" bind:value={color} />
30
+
31
+ <label for="size-input">Size</label>
32
+ <input id="size-input" type="range" min="0.5" max="3" step="0.1" bind:value={size} />
33
+
34
+ <label for="rotate-input">Rotation</label>
35
+ <input id="rotate-input" type="range" min="-180" max="180" step="15" bind:value={rotate} />
36
+
37
+ <label for="halo-input">Halo</label>
38
+ <input id="halo-input" type="range" min="0" max="3" step="0.5" bind:value={halo} />
39
+
40
+ <label for="label-input">Label</label>
41
+ <input id="label-input" type="text" bind:value={label} />
42
+ </div>
@@ -0,0 +1,7 @@
1
+ import type { MarkerElement } from './lib/element_marker.js';
2
+ type $$ComponentProps = {
3
+ element: MarkerElement;
4
+ };
5
+ declare const EditorMarker: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EditorMarker = ReturnType<typeof EditorMarker>;
7
+ export default EditorMarker;
@@ -0,0 +1,99 @@
1
+ <script lang="ts">import 'maplibre-gl/dist/maplibre-gl.css';
2
+ import BasicMap from '../BasicMap/BasicMap.svelte';
3
+ import Editor from './Editor.svelte';
4
+ import { GeometryManager } from './lib/geometry_manager.js';
5
+ import { onMount } from 'svelte';
6
+ let showSidebar = $state(false);
7
+ onMount(() => {
8
+ const inIframe = window.self !== window.top;
9
+ if (!inIframe)
10
+ showSidebar = true;
11
+ });
12
+ let map = $state();
13
+ let geometryManager = $state();
14
+ let elements = $state([]);
15
+ let activeElement = $state(undefined);
16
+ function onMapInit(_map) {
17
+ map = _map;
18
+ map.on('load', async () => {
19
+ geometryManager = new GeometryManager(map);
20
+ geometryManager.elements.subscribe((value) => (elements = value));
21
+ geometryManager.activeElement.subscribe((value) => (activeElement = value));
22
+ });
23
+ }
24
+ $effect(() => geometryManager?.setActiveElement(activeElement));
25
+ </script>
26
+
27
+ <div class="page">
28
+ <div class="container">
29
+ <BasicMap {onMapInit} styleOptions={{ disableDarkMode: true }}></BasicMap>
30
+ </div>
31
+ {#if showSidebar && geometryManager}
32
+ <div class="sidebar" style="--gap: 10px;">
33
+ <div class="label">Add new:</div>
34
+ <div class="row" style="display: flex; column-gap: var(--gap);">
35
+ <input
36
+ type="button"
37
+ value="Marker"
38
+ onclick={() => (activeElement = geometryManager?.getNewMarker())}
39
+ />
40
+ <input
41
+ type="button"
42
+ value="Line"
43
+ onclick={() => (activeElement = geometryManager?.getNewLine())}
44
+ />
45
+ </div>
46
+ <hr />
47
+ <div class="row">
48
+ <select
49
+ size="5"
50
+ bind:value={
51
+ () => elements.indexOf(activeElement!), (index) => (activeElement = elements[index])
52
+ }
53
+ >
54
+ {#each elements as element, index}
55
+ <option value={index}>{element.name}</option>
56
+ {/each}
57
+ </select>
58
+ </div>
59
+ {#if activeElement != null}
60
+ <hr />
61
+ <div class="editor">
62
+ <Editor element={activeElement} />
63
+ </div>
64
+ {/if}
65
+ </div>
66
+ <style>.page .sidebar {
67
+ width: 300px;
68
+ height: 100%;
69
+ position: absolute;
70
+ top: 0;
71
+ right: 0;
72
+ min-height: 6em;
73
+ background-color: #eee;
74
+ overflow-y: scroll;
75
+ box-sizing: border-box;
76
+ padding: var(--gap);
77
+ }
78
+ .page .row {
79
+ margin-bottom: var(--gap);
80
+ }
81
+ .page .container {
82
+ width: calc(100% - 300px);
83
+ height: 100%;
84
+ position: absolute;
85
+ top: 0;
86
+ left: 0;
87
+ }</style>
88
+ {/if}
89
+ </div>
90
+
91
+ <style>
92
+ .page,
93
+ .container {
94
+ width: 100%;
95
+ height: 100%;
96
+ position: relative;
97
+ min-height: 6em;
98
+ }
99
+ </style>
@@ -0,0 +1,4 @@
1
+ import 'maplibre-gl/dist/maplibre-gl.css';
2
+ declare const MapEditor: import("svelte").Component<Record<string, never>, {}, "">;
3
+ type MapEditor = ReturnType<typeof MapEditor>;
4
+ export default MapEditor;
@@ -0,0 +1,16 @@
1
+ input {
2
+ width: 100%;
3
+ }
4
+
5
+ label,
6
+ div.label {
7
+ opacity: 0.7;
8
+ font-size: 0.8em;
9
+ display: block;
10
+ margin-top: 1.5em;
11
+ margin-bottom: 0.2em;
12
+ }
13
+
14
+ select {
15
+ width: 100%;
16
+ }
@@ -0,0 +1,20 @@
1
+ import type { Feature } from 'geojson';
2
+ import type maplibregl from 'maplibre-gl';
3
+ import { MapLayer } from './map_layer.js';
4
+ import type { ElementPoint, LayerFill, LayerLine, LayerSymbol, SelectionNode } from './types.js';
5
+ import type { GeometryManager } from './geometry_manager.js';
6
+ export declare abstract class AbstractElement<T extends LayerSymbol | LayerFill | LayerLine = LayerSymbol | LayerFill | LayerLine> {
7
+ name: string;
8
+ protected canvas: HTMLElement;
9
+ protected manager: GeometryManager;
10
+ protected map: maplibregl.Map;
11
+ protected layer: MapLayer<T>;
12
+ protected source: maplibregl.GeoJSONSource;
13
+ private isActive;
14
+ private slug;
15
+ constructor(manager: GeometryManager, name: string, type: 'symbol' | 'fill' | 'line');
16
+ protected randomPositions(name: string, length: number): ElementPoint[];
17
+ abstract getFeature(): Feature;
18
+ abstract getSelectionNodes(): SelectionNode[];
19
+ abstract getSelectionNodeUpdater(properties?: Record<string, unknown>): ((lng: number, lat: number) => void) | undefined;
20
+ }
@@ -0,0 +1,58 @@
1
+ import { MapLayer } from './map_layer.js';
2
+ export class AbstractElement {
3
+ name;
4
+ canvas;
5
+ manager;
6
+ map;
7
+ layer;
8
+ source;
9
+ isActive = true;
10
+ slug = '_' + Math.random().toString(36).slice(2);
11
+ constructor(manager, name, type) {
12
+ this.manager = manager;
13
+ this.map = manager.map;
14
+ this.canvas = this.map.getCanvasContainer();
15
+ this.name = name;
16
+ this.map.addSource('source' + this.slug, {
17
+ type: 'geojson',
18
+ data: { type: 'FeatureCollection', features: [] }
19
+ });
20
+ this.source = this.map.getSource('source' + this.slug);
21
+ this.layer = new MapLayer(this.map, type + this.slug, 'source' + this.slug, type);
22
+ this.map.on('mouseenter', this.layer.id, () => {
23
+ if (this.isActive)
24
+ this.canvas.style.cursor = 'pointer';
25
+ });
26
+ this.map.on('mouseleave', this.layer.id, () => {
27
+ if (this.isActive)
28
+ this.canvas.style.cursor = 'default';
29
+ });
30
+ this.map.on('click', this.layer.id, (e) => {
31
+ if (this.isActive) {
32
+ this.manager.setActiveElement(this);
33
+ e.preventDefault();
34
+ }
35
+ });
36
+ }
37
+ randomPositions(name, length) {
38
+ let seed = name
39
+ .split('')
40
+ .reduce((acc, char) => (acc * 0x101 + char.charCodeAt(0)) % 0x100000000, 0);
41
+ const points = [];
42
+ for (let i = 0; i < length; i++) {
43
+ const xr = random() * 0.5 + 0.25;
44
+ const yr = random() * 0.5 + 0.25;
45
+ const bounds = this.map.getBounds();
46
+ points.push([
47
+ (1 - xr) * bounds.getWest() + xr * bounds.getEast(),
48
+ (1 - yr) * bounds.getSouth() + yr * bounds.getNorth()
49
+ ]);
50
+ }
51
+ return points;
52
+ function random() {
53
+ for (let i = 0; i < 10; i++)
54
+ seed = ((Math.cos(seed * 3.14 + 0.0159) + 1.1) * 9631) % 1;
55
+ return seed;
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,14 @@
1
+ import { AbstractElement } from './element_abstract.js';
2
+ import type { GeometryManager } from './geometry_manager.js';
3
+ import type { ElementLine, LayerLine, SelectionNode } from './types.js';
4
+ export declare const dashArrays: Map<string, number[] | undefined>;
5
+ export declare class LineElement extends AbstractElement<LayerLine> {
6
+ readonly color: import("svelte/store").Writable<string>;
7
+ readonly dashed: import("svelte/store").Writable<string>;
8
+ readonly width: import("svelte/store").Writable<number>;
9
+ private line;
10
+ constructor(manager: GeometryManager, name: string, line?: ElementLine);
11
+ getFeature(): GeoJSON.Feature<GeoJSON.LineString>;
12
+ getSelectionNodes(): SelectionNode[];
13
+ getSelectionNodeUpdater(properties?: Record<string, unknown>): ((lng: number, lat: number) => void) | undefined;
14
+ }
@@ -0,0 +1,76 @@
1
+ import { Color } from '@versatiles/style';
2
+ import { AbstractElement } from './element_abstract.js';
3
+ import { get, writable } from 'svelte/store';
4
+ import { getMiddlePoint } from './utils.js';
5
+ export const dashArrays = new Map([
6
+ ['solid', undefined],
7
+ ['dashed', [2, 4]],
8
+ ['dotted', [0, 2]]
9
+ ]);
10
+ export class LineElement extends AbstractElement {
11
+ color = writable('#ff0000');
12
+ dashed = writable('solid');
13
+ width = writable(2);
14
+ line = [
15
+ [0, 0],
16
+ [0, 0]
17
+ ];
18
+ constructor(manager, name, line) {
19
+ super(manager, name, 'line');
20
+ this.line = line ?? this.randomPositions(name, 2);
21
+ const getDashArray = () => dashArrays.get(get(this.dashed));
22
+ this.layer.setLayout({
23
+ 'line-cap': 'round',
24
+ 'line-join': 'round'
25
+ });
26
+ this.layer.setPaint({
27
+ 'line-color': Color.parse(get(this.color)).asString(),
28
+ 'line-dasharray': getDashArray(),
29
+ 'line-width': get(this.width)
30
+ });
31
+ this.color.subscribe((value) => this.layer.updatePaint('line-color', Color.parse(value)));
32
+ this.width.subscribe((value) => this.layer.updatePaint('line-width', value));
33
+ this.dashed.subscribe(() => this.layer.updatePaint('line-dasharray', getDashArray()));
34
+ this.source.setData(this.getFeature());
35
+ }
36
+ getFeature() {
37
+ return {
38
+ type: 'Feature',
39
+ properties: {},
40
+ geometry: { type: 'LineString', coordinates: this.line }
41
+ };
42
+ }
43
+ getSelectionNodes() {
44
+ const points = [];
45
+ for (let i = 0; i < this.line.length; i++) {
46
+ points.push({ index: i, coordinates: this.line[i] });
47
+ if (i === this.line.length - 1)
48
+ continue;
49
+ points.push({
50
+ index: i + 0.5,
51
+ transparent: true,
52
+ coordinates: getMiddlePoint(this.line[i], this.line[i + 1])
53
+ });
54
+ }
55
+ return points;
56
+ }
57
+ getSelectionNodeUpdater(properties) {
58
+ if (properties == undefined)
59
+ return;
60
+ const index = properties.index;
61
+ let point;
62
+ if (index % 1 === 0) {
63
+ point = this.line[index];
64
+ }
65
+ else {
66
+ const i = Math.ceil(index);
67
+ this.line.splice(i, 0, [0, 0]);
68
+ point = this.line[i];
69
+ }
70
+ return (lng, lat) => {
71
+ point[0] = lng;
72
+ point[1] = lat;
73
+ this.source.setData(this.getFeature());
74
+ };
75
+ }
76
+ }
@@ -0,0 +1,20 @@
1
+ import { AbstractElement } from './element_abstract.js';
2
+ import type { GeometryManager } from './geometry_manager.js';
3
+ import type { ElementPoint, LayerSymbol, SelectionNode } from './types.js';
4
+ export declare const symbols: Map<string, {
5
+ image: string;
6
+ offset?: [number, number];
7
+ }>;
8
+ export declare class MarkerElement extends AbstractElement<LayerSymbol> {
9
+ readonly color: import("svelte/store").Writable<string>;
10
+ readonly halo: import("svelte/store").Writable<number>;
11
+ readonly rotate: import("svelte/store").Writable<number>;
12
+ readonly size: import("svelte/store").Writable<number>;
13
+ readonly symbol: import("svelte/store").Writable<string>;
14
+ readonly label: import("svelte/store").Writable<string>;
15
+ private point;
16
+ constructor(manager: GeometryManager, name: string, point?: ElementPoint);
17
+ getFeature(): GeoJSON.Feature<GeoJSON.Point>;
18
+ getSelectionNodes(): SelectionNode[];
19
+ getSelectionNodeUpdater(): ((lng: number, lat: number) => void) | undefined;
20
+ }
@@ -0,0 +1,191 @@
1
+ import { Color } from '@versatiles/style';
2
+ import { AbstractElement } from './element_abstract.js';
3
+ import { get, writable } from 'svelte/store';
4
+ export const symbols = new Map([
5
+ ['airplane', { image: 'basics:icon-airfield' }],
6
+ ['airport', { image: 'basics:icon-airport' }],
7
+ ['alcohol shop', { image: 'basics:icon-alcohol_shop' }],
8
+ ['art gallery', { image: 'basics:icon-art_gallery' }],
9
+ ['artwork', { image: 'basics:icon-artwork' }],
10
+ ['atm', { image: 'basics:icon-atm' }],
11
+ ['bakery', { image: 'basics:icon-bakery' }],
12
+ ['bank', { image: 'basics:icon-bank' }],
13
+ ['beauty', { image: 'basics:icon-beauty' }],
14
+ ['beer', { image: 'basics:icon-beer' }],
15
+ ['beergarden', { image: 'basics:icon-beergarden' }],
16
+ ['bench', { image: 'basics:icon-bench' }],
17
+ ['beverages', { image: 'basics:icon-beverages' }],
18
+ ['bicycle share', { image: 'basics:icon-bicycle_share' }],
19
+ ['books', { image: 'basics:icon-books' }],
20
+ ['bus', { image: 'basics:icon-bus' }],
21
+ ['butcher', { image: 'basics:icon-butcher' }],
22
+ ['cafe', { image: 'basics:icon-cafe', offset: [2, 0] }],
23
+ ['car rental', { image: 'basics:icon-car_rental' }],
24
+ ['car wash', { image: 'basics:icon-car_wash' }],
25
+ ['castle', { image: 'basics:icon-castle' }],
26
+ ['cemetery', { image: 'basics:icon-cemetery' }],
27
+ ['chalet', { image: 'basics:icon-chalet' }],
28
+ ['chemist', { image: 'basics:icon-chemist' }],
29
+ ['cinema', { image: 'basics:icon-cinema' }],
30
+ ['clothes', { image: 'basics:icon-clothes' }],
31
+ ['college', { image: 'basics:icon-college' }],
32
+ ['community', { image: 'basics:icon-community' }],
33
+ ['defibrillator', { image: 'basics:icon-defibrillator' }],
34
+ ['doctor', { image: 'basics:icon-doctor' }],
35
+ ['dog park', { image: 'basics:icon-dog_park' }],
36
+ ['doityourself', { image: 'basics:icon-doityourself' }],
37
+ ['drinking water', { image: 'basics:icon-drinking_water' }],
38
+ ['drycleaning', { image: 'basics:icon-drycleaning' }],
39
+ ['emergency phone', { image: 'basics:icon-emergency_phone' }],
40
+ ['fast food', { image: 'basics:icon-fast_food' }],
41
+ ['fire station', { image: 'basics:icon-fire_station' }],
42
+ ['flag', { image: 'basics:icon-embassy', offset: [7.5, -10] }],
43
+ ['florist', { image: 'basics:icon-florist' }],
44
+ ['fountain', { image: 'basics:icon-fountain' }],
45
+ ['furniture', { image: 'basics:icon-furniture' }],
46
+ ['garden centre', { image: 'basics:icon-garden_centre' }],
47
+ ['gift', { image: 'basics:icon-gift' }],
48
+ ['glasses', { image: 'basics:icon-optician' }],
49
+ ['golf', { image: 'basics:icon-golf' }],
50
+ ['greengrocer', { image: 'basics:icon-greengrocer' }],
51
+ ['hardware', { image: 'basics:icon-hardware' }],
52
+ ['hospital', { image: 'basics:icon-hospital' }],
53
+ ['huntingstand', { image: 'basics:icon-huntingstand' }],
54
+ ['hydrant', { image: 'basics:icon-hydrant' }],
55
+ ['icerink', { image: 'basics:icon-icerink' }],
56
+ ['information', { image: 'basics:transport-information' }],
57
+ ['jewelry store', { image: 'basics:icon-jewelry_store' }],
58
+ ['kiosk', { image: 'basics:icon-kiosk' }],
59
+ ['laundry', { image: 'basics:icon-laundry' }],
60
+ ['letter', { image: 'basics:icon-post' }],
61
+ ['library', { image: 'basics:icon-library' }],
62
+ ['lighthouse', { image: 'basics:icon-lighthouse' }],
63
+ ['marketplace', { image: 'basics:icon-marketplace' }],
64
+ ['money', { image: 'basics:icon-bar' }],
65
+ ['monument', { image: 'basics:icon-monument' }],
66
+ ['newsagent', { image: 'basics:icon-newsagent' }],
67
+ ['nightclub', { image: 'basics:icon-nightclub' }],
68
+ ['nursinghome', { image: 'basics:icon-nursinghome' }],
69
+ ['observation tower', { image: 'basics:icon-observation_tower' }],
70
+ ['outdoor', { image: 'basics:icon-outdoor' }],
71
+ ['pharmacy', { image: 'basics:icon-pharmacy' }],
72
+ ['picnic site', { image: 'basics:icon-picnic_site' }],
73
+ ['place of worship', { image: 'basics:icon-place_of_worship' }],
74
+ ['playground', { image: 'basics:icon-playground' }],
75
+ ['police', { image: 'basics:icon-police', offset: [-1, -3] }],
76
+ ['postbox', { image: 'basics:icon-postbox' }],
77
+ ['prison', { image: 'basics:icon-prison' }],
78
+ ['rail light', { image: 'basics:icon-rail_light' }],
79
+ ['rail metro', { image: 'basics:icon-rail_metro' }],
80
+ ['rail', { image: 'basics:icon-rail' }],
81
+ ['recycling', { image: 'basics:icon-recycling' }],
82
+ ['restaurant', { image: 'basics:icon-restaurant' }],
83
+ ['run', { image: 'basics:icon-pitch' }],
84
+ ['school', { image: 'basics:icon-school' }],
85
+ ['scissor', { image: 'basics:icon-hairdresser' }],
86
+ ['shield', { image: 'basics:icon-historic', offset: [0, -10] }],
87
+ ['shoes', { image: 'basics:icon-shoes', offset: [-5, 0] }],
88
+ ['shop', { image: 'basics:icon-shop' }],
89
+ ['shop', { image: 'basics:icon-shop' }],
90
+ ['shrine', { image: 'basics:icon-shrine' }],
91
+ ['sports', { image: 'basics:icon-sports' }],
92
+ ['stadium', { image: 'basics:icon-stadium' }],
93
+ ['stationery', { image: 'basics:icon-stationery' }],
94
+ ['surveillance', { image: 'basics:icon-surveillance' }],
95
+ ['swimming', { image: 'basics:icon-swimming' }],
96
+ ['telephone', { image: 'basics:icon-telephone' }],
97
+ ['theatre', { image: 'basics:icon-theatre' }],
98
+ ['toilet', { image: 'basics:icon-toilet' }],
99
+ ['tooth', { image: 'basics:icon-dentist' }],
100
+ ['town hall', { image: 'basics:icon-town_hall' }],
101
+ ['toys', { image: 'basics:icon-toys' }],
102
+ ['tram', { image: 'basics:transport-tram' }],
103
+ ['travel agent', { image: 'basics:icon-travel_agent' }],
104
+ ['vendingmachine', { image: 'basics:icon-vendingmachine' }],
105
+ ['veterinary', { image: 'basics:icon-veterinary' }],
106
+ ['video', { image: 'basics:icon-video' }],
107
+ ['viewpoint', { image: 'basics:icon-viewpoint', offset: [0, -6] }],
108
+ ['waste basket', { image: 'basics:icon-waste_basket' }],
109
+ ['watermill', { image: 'basics:icon-watermill' }],
110
+ ['waterpark', { image: 'basics:icon-waterpark' }],
111
+ ['windmill', { image: 'basics:icon-windmill' }],
112
+ ['zoo', { image: 'basics:icon-zoo' }]
113
+ ]);
114
+ export class MarkerElement extends AbstractElement {
115
+ color = writable('#ff0000');
116
+ halo = writable(1);
117
+ rotate = writable(0);
118
+ size = writable(1);
119
+ symbol = writable('flag');
120
+ label = writable('');
121
+ point = [0, 0];
122
+ constructor(manager, name, point) {
123
+ super(manager, name, 'symbol');
124
+ this.point = point ?? this.randomPositions(name, 1)[0];
125
+ const getSymbol = () => {
126
+ const entry = symbols.get(get(this.symbol)) ?? symbols.get('flag');
127
+ return { image: entry.image, offset: entry.offset ?? [0, 0] };
128
+ };
129
+ this.layer.setLayout({
130
+ 'icon-image': getSymbol().image,
131
+ 'icon-offset': getSymbol().offset,
132
+ 'icon-overlap': 'always',
133
+ 'icon-rotate': get(this.rotate),
134
+ 'icon-size': get(this.size),
135
+ 'text-field': get(this.label),
136
+ 'text-font': ['noto_sans_regular'],
137
+ 'text-justify': 'left',
138
+ 'text-anchor': 'right',
139
+ 'text-offset': [-0.4, -0.6]
140
+ });
141
+ this.layer.setPaint({
142
+ 'icon-color': Color.parse(get(this.color)).asString(),
143
+ 'icon-halo-blur': 0,
144
+ 'icon-halo-color': '#FFFFFF',
145
+ 'icon-halo-width': get(this.halo) * get(this.size),
146
+ 'icon-opacity': 1,
147
+ 'text-halo-blur': 0,
148
+ 'text-halo-color': '#FFFFFF',
149
+ 'text-halo-width': get(this.halo) * get(this.size)
150
+ });
151
+ this.color.subscribe((value) => this.layer.updatePaint('icon-color', Color.parse(value)));
152
+ this.halo.subscribe((value) => {
153
+ this.layer.updatePaint('icon-halo-width', value * get(this.size));
154
+ this.layer.updatePaint('text-halo-width', value * get(this.size));
155
+ });
156
+ this.label.subscribe((value) => this.layer.updateLayout('text-field', value));
157
+ this.rotate.subscribe((value) => this.layer.updateLayout('icon-rotate', value));
158
+ this.size.subscribe((value) => {
159
+ this.layer.updateLayout('icon-size', value);
160
+ this.layer.updatePaint('icon-halo-width', value * get(this.halo));
161
+ this.layer.updateLayout('text-size', value * 16);
162
+ this.layer.updatePaint('text-halo-width', value * get(this.halo));
163
+ });
164
+ this.symbol.subscribe(() => {
165
+ const symbol = getSymbol();
166
+ this.layer.updateLayout('icon-image', symbol.image);
167
+ this.layer.updateLayout('icon-offset', symbol.offset);
168
+ });
169
+ this.source.setData(this.getFeature());
170
+ }
171
+ getFeature() {
172
+ return {
173
+ type: 'Feature',
174
+ properties: {},
175
+ geometry: {
176
+ type: 'Point',
177
+ coordinates: this.point
178
+ }
179
+ };
180
+ }
181
+ getSelectionNodes() {
182
+ return [{ index: 0, coordinates: this.point }];
183
+ }
184
+ getSelectionNodeUpdater() {
185
+ return (lng, lat) => {
186
+ this.point[0] = lng;
187
+ this.point[1] = lat;
188
+ this.source.setData(this.getFeature());
189
+ };
190
+ }
191
+ }
@@ -0,0 +1 @@
1
+ export declare function getLatLng(query: string): Promise<[number, number] | undefined>;
@@ -0,0 +1,8 @@
1
+ export async function getLatLng(query) {
2
+ const url = `https://photon.komoot.io/api/?${new URLSearchParams(query)}`;
3
+ const result = await fetch(url).then((r) => r.json());
4
+ const geometry = result?.features?.[0]?.geometry;
5
+ if (geometry?.type !== 'Point')
6
+ return;
7
+ return geometry.coordinates;
8
+ }
@@ -0,0 +1,18 @@
1
+ import { type Writable } from 'svelte/store';
2
+ import type { AbstractElement } from './element_abstract.js';
3
+ import type maplibregl from 'maplibre-gl';
4
+ export declare class GeometryManager {
5
+ readonly elements: Writable<AbstractElement[]>;
6
+ readonly map: maplibregl.Map;
7
+ readonly activeElement: Writable<AbstractElement | undefined>;
8
+ private readonly selection_nodes;
9
+ private readonly canvas;
10
+ constructor(map: maplibregl.Map);
11
+ setActiveElement(element: AbstractElement | undefined): void;
12
+ private drawSelectionNodes;
13
+ getElement(index: number): AbstractElement;
14
+ getNewMarker(): AbstractElement;
15
+ getNewLine(): AbstractElement;
16
+ private addElement;
17
+ private newName;
18
+ }