@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.
- package/README.md +21 -4
- package/dist/components/BBoxMap/AutoComplete.svelte +176 -0
- package/dist/components/{AutoComplete.svelte.d.ts → BBoxMap/AutoComplete.svelte.d.ts} +12 -18
- package/dist/components/BBoxMap/BBoxMap.d.ts +1 -12
- package/dist/components/BBoxMap/BBoxMap.js +1 -200
- package/dist/components/BBoxMap/BBoxMap.svelte +43 -127
- package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +4 -20
- package/dist/components/BasicMap/BasicMap.svelte +34 -37
- package/dist/components/BasicMap/BasicMap.svelte.d.ts +9 -24
- package/dist/components/LocatorMap/LocatorMap.svelte +75 -0
- package/dist/components/LocatorMap/LocatorMap.svelte.d.ts +19 -0
- package/dist/components/MapEditor/Editor.svelte +25 -0
- package/dist/components/MapEditor/Editor.svelte.d.ts +7 -0
- package/dist/components/MapEditor/EditorLine.svelte +27 -0
- package/dist/components/MapEditor/EditorLine.svelte.d.ts +7 -0
- package/dist/components/MapEditor/EditorMarker.svelte +42 -0
- package/dist/components/MapEditor/EditorMarker.svelte.d.ts +7 -0
- package/dist/components/MapEditor/MapEditor.svelte +99 -0
- package/dist/components/MapEditor/MapEditor.svelte.d.ts +4 -0
- package/dist/components/MapEditor/editor.scss +16 -0
- package/dist/components/MapEditor/lib/element_abstract.d.ts +20 -0
- package/dist/components/MapEditor/lib/element_abstract.js +58 -0
- package/dist/components/MapEditor/lib/element_line.d.ts +14 -0
- package/dist/components/MapEditor/lib/element_line.js +76 -0
- package/dist/components/MapEditor/lib/element_marker.d.ts +20 -0
- package/dist/components/MapEditor/lib/element_marker.js +191 -0
- package/dist/components/MapEditor/lib/geocoder.d.ts +1 -0
- package/dist/components/MapEditor/lib/geocoder.js +8 -0
- package/dist/components/MapEditor/lib/geometry_manager.d.ts +18 -0
- package/dist/components/MapEditor/lib/geometry_manager.js +117 -0
- package/dist/components/MapEditor/lib/map_layer.d.ts +14 -0
- package/dist/components/MapEditor/lib/map_layer.js +61 -0
- package/dist/components/MapEditor/lib/types.d.ts +112 -0
- package/dist/components/MapEditor/lib/types.js +1 -0
- package/dist/components/MapEditor/lib/utils.d.ts +2 -0
- package/dist/components/MapEditor/lib/utils.js +11 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/utils/draw/bbox.d.ts +28 -0
- package/dist/utils/draw/bbox.js +193 -0
- package/dist/utils/location.d.ts +2 -1
- package/dist/utils/location.js +19 -10
- package/dist/utils/map_style.d.ts +6 -0
- package/dist/utils/map_style.js +28 -0
- package/dist/utils/sprite_library.d.ts +19 -0
- package/dist/utils/sprite_library.js +30 -0
- package/package.json +19 -14
- package/dist/components/AutoComplete.svelte +0 -197
- package/dist/components/BBoxMap/README.md +0 -70
- package/dist/components/BBoxMap/data/countries.jsonl +0 -258
- package/dist/components/BBoxMap/data/eu.jsonl +0 -1876
- package/dist/components/BBoxMap/data/us.jsonl +0 -52
- package/dist/components/BBoxMap/data/world.jsonl +0 -7
- package/dist/components/BBoxMap/helpers/geojson2bboxes.d.ts +0 -2
- package/dist/components/BBoxMap/helpers/geojson2bboxes.js +0 -183
- package/dist/components/BBoxMap/helpers/merge_bboxes.d.ts +0 -2
- package/dist/components/BBoxMap/helpers/merge_bboxes.js +0 -84
- package/dist/components/BBoxMap/helpers/population.raw.br +0 -0
- package/dist/utils/style.d.ts +0 -3
- 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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
4
|
-
|
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
|
-
|
20
|
-
map?: MaplibreMapType | undefined;
|
21
|
-
styleOptions?: StyleBuilderOptions;
|
6
|
+
styleOptions?: Parameters<typeof getMapStyle>[1];
|
22
7
|
mapOptions?: Partial<MapOptions>;
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
type 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,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
|
+
}
|