@versatiles/svelte 0.2.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 (60) hide show
  1. package/README.md +21 -4
  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.d.ts +1 -12
  5. package/dist/components/BBoxMap/BBoxMap.js +1 -200
  6. package/dist/components/BBoxMap/BBoxMap.svelte +43 -127
  7. package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +4 -20
  8. package/dist/components/BasicMap/BasicMap.svelte +34 -37
  9. package/dist/components/BasicMap/BasicMap.svelte.d.ts +9 -24
  10. package/dist/components/LocatorMap/LocatorMap.svelte +75 -0
  11. package/dist/components/LocatorMap/LocatorMap.svelte.d.ts +19 -0
  12. package/dist/components/MapEditor/Editor.svelte +25 -0
  13. package/dist/components/MapEditor/Editor.svelte.d.ts +7 -0
  14. package/dist/components/MapEditor/EditorLine.svelte +27 -0
  15. package/dist/components/MapEditor/EditorLine.svelte.d.ts +7 -0
  16. package/dist/components/MapEditor/EditorMarker.svelte +42 -0
  17. package/dist/components/MapEditor/EditorMarker.svelte.d.ts +7 -0
  18. package/dist/components/MapEditor/MapEditor.svelte +99 -0
  19. package/dist/components/MapEditor/MapEditor.svelte.d.ts +4 -0
  20. package/dist/components/MapEditor/editor.scss +16 -0
  21. package/dist/components/MapEditor/lib/element_abstract.d.ts +20 -0
  22. package/dist/components/MapEditor/lib/element_abstract.js +58 -0
  23. package/dist/components/MapEditor/lib/element_line.d.ts +14 -0
  24. package/dist/components/MapEditor/lib/element_line.js +76 -0
  25. package/dist/components/MapEditor/lib/element_marker.d.ts +20 -0
  26. package/dist/components/MapEditor/lib/element_marker.js +191 -0
  27. package/dist/components/MapEditor/lib/geocoder.d.ts +1 -0
  28. package/dist/components/MapEditor/lib/geocoder.js +8 -0
  29. package/dist/components/MapEditor/lib/geometry_manager.d.ts +18 -0
  30. package/dist/components/MapEditor/lib/geometry_manager.js +117 -0
  31. package/dist/components/MapEditor/lib/map_layer.d.ts +14 -0
  32. package/dist/components/MapEditor/lib/map_layer.js +61 -0
  33. package/dist/components/MapEditor/lib/types.d.ts +112 -0
  34. package/dist/components/MapEditor/lib/types.js +1 -0
  35. package/dist/components/MapEditor/lib/utils.d.ts +2 -0
  36. package/dist/components/MapEditor/lib/utils.js +11 -0
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.js +3 -1
  39. package/dist/utils/draw/bbox.d.ts +28 -0
  40. package/dist/utils/draw/bbox.js +193 -0
  41. package/dist/utils/location.d.ts +2 -1
  42. package/dist/utils/location.js +19 -10
  43. package/dist/utils/map_style.d.ts +6 -0
  44. package/dist/utils/map_style.js +28 -0
  45. package/dist/utils/sprite_library.d.ts +19 -0
  46. package/dist/utils/sprite_library.js +30 -0
  47. package/package.json +19 -14
  48. package/dist/components/AutoComplete.svelte +0 -197
  49. package/dist/components/BBoxMap/README.md +0 -70
  50. package/dist/components/BBoxMap/data/countries.jsonl +0 -258
  51. package/dist/components/BBoxMap/data/eu.jsonl +0 -1876
  52. package/dist/components/BBoxMap/data/us.jsonl +0 -52
  53. package/dist/components/BBoxMap/data/world.jsonl +0 -7
  54. package/dist/components/BBoxMap/helpers/geojson2bboxes.d.ts +0 -2
  55. package/dist/components/BBoxMap/helpers/geojson2bboxes.js +0 -183
  56. package/dist/components/BBoxMap/helpers/merge_bboxes.d.ts +0 -2
  57. package/dist/components/BBoxMap/helpers/merge_bboxes.js +0 -84
  58. package/dist/components/BBoxMap/helpers/population.raw.br +0 -0
  59. package/dist/utils/style.d.ts +0 -3
  60. package/dist/utils/style.js +0 -21
@@ -1,22 +1,6 @@
1
- import type { BBox } from './BBoxMap.js';
2
1
  import 'maplibre-gl/dist/maplibre-gl.css';
3
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
4
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
5
- $$bindings?: Bindings;
6
- } & Exports;
7
- (internal: unknown, props: Props & {
8
- $$events?: Events;
9
- $$slots?: Slots;
10
- }): Exports & {
11
- $set?: any;
12
- $on?: any;
13
- };
14
- z_$$bindings?: Bindings;
15
- }
16
- declare const BBoxMap: $$__sveltets_2_IsomorphicComponent<{
17
- selectedBBox?: BBox;
18
- }, {
19
- [evt: string]: CustomEvent<any>;
20
- }, {}, {}, string>;
21
- type BBoxMap = InstanceType<typeof BBoxMap>;
2
+ declare const BBoxMap: import("svelte").Component<{
3
+ selectedBBox?: any;
4
+ }, {}, "selectedBBox">;
5
+ type BBoxMap = ReturnType<typeof BBoxMap>;
22
6
  export default BBoxMap;
@@ -1,41 +1,38 @@
1
1
  <!-- BasicMap.svelte -->
2
- <script lang="ts">
3
- import type { Map as MaplibreMapType, MapOptions } from 'maplibre-gl';
4
- import { onMount, createEventDispatcher } from 'svelte';
5
- import 'maplibre-gl/dist/maplibre-gl.css';
6
- import { getMapStyle, isDarkMode } from '../../utils/style.js';
7
- import type { StyleBuilderOptions } from '@versatiles/style';
8
-
9
- // Props
10
- export let style: string = 'position:absolute; left:0px; top:0px; width:100%; height:100%;';
11
- export let container: HTMLDivElement | undefined = undefined;
12
- export let map: MaplibreMapType | undefined = undefined;
13
- export let styleOptions: StyleBuilderOptions = {};
14
- export let mapOptions: Partial<MapOptions> = {};
15
-
16
- // Create the event dispatcher
17
- const dispatch = createEventDispatcher();
18
-
19
- onMount(async (): Promise<void> => {
20
- let MaplibreMap: typeof MaplibreMapType = (await import('maplibre-gl')).Map;
21
-
22
- if (!container) throw Error();
23
-
24
- const darkMode = isDarkMode(container);
25
- container.style.setProperty('--bg-color', darkMode ? '#000' : '#fff');
26
- container.style.setProperty('--fg-color', darkMode ? '#fff' : '#000');
27
-
28
- map = new MaplibreMap({
29
- container,
30
- style: getMapStyle(darkMode, styleOptions),
31
- renderWorldCopies: false,
32
- dragRotate: false,
33
- attributionControl: { compact: false },
34
- ...mapOptions
35
- });
36
-
37
- dispatch('mapReady', { map });
38
- });
2
+ <script lang="ts">import 'maplibre-gl/dist/maplibre-gl.css';
3
+ import { getMapStyle, isDarkMode } from '../../utils/map_style.js';
4
+ // Props
5
+ let { style = 'position:absolute; left:0px; top:0px; width:100%; height:100%;', styleOptions = { transitionDuration: 0 }, mapOptions = {}, map = $bindable(), onMapInit, onMapLoad } = $props();
6
+ let container;
7
+ $effect(() => {
8
+ if (container)
9
+ init();
10
+ });
11
+ async function init() {
12
+ if (map)
13
+ return;
14
+ let MaplibreMap = (await import('maplibre-gl')).Map;
15
+ if (!container)
16
+ throw Error();
17
+ const darkMode = isDarkMode(container);
18
+ container.style.setProperty('--bg-color', darkMode ? '#000' : '#fff');
19
+ container.style.setProperty('--fg-color', darkMode ? '#fff' : '#000');
20
+ map = new MaplibreMap({
21
+ container,
22
+ style: getMapStyle(darkMode, styleOptions),
23
+ renderWorldCopies: false,
24
+ dragRotate: false,
25
+ attributionControl: { compact: false },
26
+ fadeDuration: 0,
27
+ ...mapOptions
28
+ });
29
+ if (onMapInit)
30
+ onMapInit(map);
31
+ map.on('load', () => {
32
+ if (onMapLoad)
33
+ onMapLoad(map);
34
+ });
35
+ }
39
36
  </script>
40
37
 
41
38
  <div class="map" {style} bind:this={container}></div>
@@ -1,29 +1,14 @@
1
1
  import type { Map as MaplibreMapType, MapOptions } from 'maplibre-gl';
2
2
  import 'maplibre-gl/dist/maplibre-gl.css';
3
- import type { StyleBuilderOptions } from '@versatiles/style';
4
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
5
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
- $$bindings?: Bindings;
7
- } & Exports;
8
- (internal: unknown, props: Props & {
9
- $$events?: Events;
10
- $$slots?: Slots;
11
- }): Exports & {
12
- $set?: any;
13
- $on?: any;
14
- };
15
- z_$$bindings?: Bindings;
16
- }
17
- declare const BasicMap: $$__sveltets_2_IsomorphicComponent<{
3
+ import { getMapStyle } from '../../utils/map_style.js';
4
+ type $$ComponentProps = {
18
5
  style?: string;
19
- container?: HTMLDivElement | undefined;
20
- map?: MaplibreMapType | undefined;
21
- styleOptions?: StyleBuilderOptions;
6
+ styleOptions?: Parameters<typeof getMapStyle>[1];
22
7
  mapOptions?: Partial<MapOptions>;
23
- }, {
24
- mapReady: CustomEvent<any>;
25
- } & {
26
- [evt: string]: CustomEvent<any>;
27
- }, {}, {}, string>;
28
- type BasicMap = InstanceType<typeof BasicMap>;
8
+ map?: MaplibreMapType;
9
+ onMapInit?: (map: MaplibreMapType) => void;
10
+ onMapLoad?: (map: MaplibreMapType) => void;
11
+ };
12
+ declare const BasicMap: import("svelte").Component<$$ComponentProps, {}, "map">;
13
+ type BasicMap = ReturnType<typeof BasicMap>;
29
14
  export default BasicMap;
@@ -0,0 +1,75 @@
1
+ <!-- LocatorMap.svelte -->
2
+ <script lang="ts">import 'maplibre-gl/dist/maplibre-gl.css';
3
+ import BasicMap from '../BasicMap/BasicMap.svelte';
4
+ let map;
5
+ function onMapInit(_map) {
6
+ map = _map;
7
+ map.on('load', async () => {
8
+ let coordinates = [0, 0];
9
+ const initialHash = parseHash();
10
+ if (initialHash) {
11
+ console.log('initialHash', initialHash);
12
+ coordinates = [initialHash[1], initialHash[2]];
13
+ map.setZoom(initialHash[0]);
14
+ map.setCenter(coordinates);
15
+ }
16
+ else {
17
+ map.on('move', () => {
18
+ const { lng, lat } = map.getCenter();
19
+ source.setData({
20
+ type: 'Feature',
21
+ geometry: { type: 'Point', coordinates: [lng, lat] },
22
+ properties: {}
23
+ });
24
+ });
25
+ map.on('moveend', () => updateHash());
26
+ }
27
+ map.addSource('marker', {
28
+ type: 'geojson',
29
+ data: { type: 'Feature', geometry: { type: 'Point', coordinates }, properties: {} }
30
+ });
31
+ const source = map.getSource('marker');
32
+ map.addLayer({
33
+ id: 'marker',
34
+ source: 'marker',
35
+ type: 'symbol',
36
+ layout: {
37
+ 'icon-image': 'basics:icon-embassy',
38
+ 'icon-size': 1,
39
+ 'icon-overlap': 'always'
40
+ },
41
+ paint: {
42
+ 'icon-color': '#FF0000',
43
+ 'icon-halo-color': '#FFFFFF',
44
+ 'icon-halo-width': 1,
45
+ 'icon-halo-blur': 0
46
+ }
47
+ });
48
+ function parseHash() {
49
+ const hash = window.location.hash
50
+ .replace(/[^0-9/.]+/g, '')
51
+ .split('/')
52
+ .map(parseFloat);
53
+ return hash.length === 3 ? hash : undefined;
54
+ }
55
+ function updateHash() {
56
+ const center = map.getCenter();
57
+ const zoom = map.getZoom();
58
+ window.location.hash = `#${zoom.toFixed(2)}/${center.lng.toFixed(6)}/${center.lat.toFixed(6)}`;
59
+ }
60
+ });
61
+ }
62
+ </script>
63
+
64
+ <div class="container">
65
+ <BasicMap {onMapInit}></BasicMap>
66
+ </div>
67
+
68
+ <style>
69
+ .container {
70
+ width: 100%;
71
+ height: 100%;
72
+ position: relative;
73
+ min-height: 6em;
74
+ }
75
+ </style>
@@ -0,0 +1,19 @@
1
+ import 'maplibre-gl/dist/maplibre-gl.css';
2
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
3
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
4
+ $$bindings?: Bindings;
5
+ } & Exports;
6
+ (internal: unknown, props: {
7
+ $$events?: Events;
8
+ $$slots?: Slots;
9
+ }): Exports & {
10
+ $set?: any;
11
+ $on?: any;
12
+ };
13
+ z_$$bindings?: Bindings;
14
+ }
15
+ declare const LocatorMap: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
16
+ [evt: string]: CustomEvent<any>;
17
+ }, {}, {}, string>;
18
+ type LocatorMap = InstanceType<typeof LocatorMap>;
19
+ export default LocatorMap;
@@ -0,0 +1,25 @@
1
+ <script lang="ts">import {} from './editor.scss';
2
+ import EditorMarker from './EditorMarker.svelte';
3
+ import EditorLine from './EditorLine.svelte';
4
+ import { LineElement } from './lib/element_line.js';
5
+ import { MarkerElement } from './lib/element_marker.js';
6
+ const { element } = $props();
7
+ let name = $state(element.name);
8
+ $effect(() => {
9
+ name = element.name;
10
+ });
11
+ $effect(() => {
12
+ //element.name = name;
13
+ });
14
+ </script>
15
+
16
+ {#if element}
17
+ <label for="input-name">Name</label>
18
+ <input id="input-name" type="text" bind:value={name} />
19
+ {#if element instanceof MarkerElement}
20
+ <EditorMarker {element} />
21
+ {/if}
22
+ {#if element instanceof LineElement}
23
+ <EditorLine {element} />
24
+ {/if}
25
+ {/if}
@@ -0,0 +1,7 @@
1
+ import type { AbstractElement } from './lib/element_abstract.js';
2
+ type $$ComponentProps = {
3
+ element: AbstractElement;
4
+ };
5
+ declare const Editor: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type Editor = ReturnType<typeof Editor>;
7
+ export default Editor;
@@ -0,0 +1,27 @@
1
+ <script lang="ts">import {} from './editor.scss';
2
+ import { get } from 'svelte/store';
3
+ import { dashArrays } from './lib/element_line.js';
4
+ const dashedList = Array.from(dashArrays.keys()).sort();
5
+ let { element } = $props();
6
+ let color = $state(get(element.color));
7
+ let width = $state(get(element.width));
8
+ let dashed = $state(get(element.dashed));
9
+ $effect(() => element.color.set(color));
10
+ $effect(() => element.width.set(width));
11
+ $effect(() => element.dashed.set(dashed));
12
+ </script>
13
+
14
+ <div class="row">
15
+ <label for="dashed-input">Dashed</label>
16
+ <select id="dashed-input" bind:value={dashed}>
17
+ {#each dashedList as d}
18
+ <option value={d}>{d}</option>
19
+ {/each}
20
+ </select>
21
+
22
+ <label for="color-input">Color</label>
23
+ <input id="color-input" type="color" bind:value={color} />
24
+
25
+ <label for="width-input">Width</label>
26
+ <input id="width-input" type="range" min="0.5" max="5" step="0.5" bind:value={width} />
27
+ </div>
@@ -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
+ }