@versatiles/svelte 1.0.1 → 1.1.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/dist/components/BBoxMap/AutoComplete.svelte +117 -90
- package/dist/components/BBoxMap/BBoxMap.svelte +49 -40
- package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +0 -1
- package/dist/components/BasicMap/BasicMap.svelte +60 -34
- package/dist/components/LocatorMap/LocatorMap.svelte +66 -60
- package/dist/components/LocatorMap/LocatorMap.svelte.d.ts +0 -1
- package/dist/components/MapEditor/MapEditor.svelte +34 -80
- package/dist/components/MapEditor/MapEditor.svelte.d.ts +0 -1
- package/dist/components/MapEditor/components/Editor.svelte +53 -0
- package/dist/components/MapEditor/{Editor.svelte.d.ts → components/Editor.svelte.d.ts} +1 -1
- package/dist/components/MapEditor/components/EditorFill.svelte +28 -0
- package/dist/components/MapEditor/components/EditorFill.svelte.d.ts +7 -0
- package/dist/components/MapEditor/components/EditorStroke.svelte +28 -0
- package/dist/components/MapEditor/components/EditorStroke.svelte.d.ts +7 -0
- package/dist/components/MapEditor/components/EditorSymbol.svelte +43 -0
- package/dist/components/MapEditor/components/EditorSymbol.svelte.d.ts +7 -0
- package/dist/components/MapEditor/components/Sidebar.svelte +179 -0
- package/dist/components/MapEditor/components/Sidebar.svelte.d.ts +8 -0
- package/dist/components/MapEditor/components/SymbolSelector.svelte +118 -0
- package/dist/components/MapEditor/components/SymbolSelector.svelte.d.ts +8 -0
- package/dist/components/MapEditor/lib/__mocks__/cursor.d.ts +5 -0
- package/dist/components/MapEditor/lib/__mocks__/cursor.js +6 -0
- package/dist/components/MapEditor/lib/__mocks__/geometry_manager.d.ts +22 -0
- package/dist/components/MapEditor/lib/__mocks__/geometry_manager.js +21 -0
- package/dist/components/MapEditor/lib/__mocks__/map.d.ts +36 -0
- package/dist/components/MapEditor/lib/__mocks__/map.js +26 -0
- package/dist/components/MapEditor/lib/cursor.d.ts +10 -0
- package/dist/components/MapEditor/lib/cursor.js +43 -0
- package/dist/components/MapEditor/lib/element/abstract.d.ts +21 -0
- package/dist/components/MapEditor/lib/element/abstract.js +39 -0
- package/dist/components/MapEditor/lib/element/abstract_path.d.ts +11 -0
- package/dist/components/MapEditor/lib/element/abstract_path.js +79 -0
- package/dist/components/MapEditor/lib/element/line.d.ts +16 -0
- package/dist/components/MapEditor/lib/element/line.js +53 -0
- package/dist/components/MapEditor/lib/element/marker.d.ts +18 -0
- package/dist/components/MapEditor/lib/element/marker.js +62 -0
- package/dist/components/MapEditor/lib/element/polygon.d.ts +17 -0
- package/dist/components/MapEditor/lib/element/polygon.js +63 -0
- package/dist/components/MapEditor/lib/element/types.d.ts +11 -0
- package/dist/components/MapEditor/lib/geometry_manager.d.ts +20 -10
- package/dist/components/MapEditor/lib/geometry_manager.js +163 -57
- package/dist/components/MapEditor/lib/map_layer/abstract.d.ts +30 -0
- package/dist/components/MapEditor/lib/map_layer/abstract.js +94 -0
- package/dist/components/MapEditor/lib/map_layer/fill.d.ts +24 -0
- package/dist/components/MapEditor/lib/map_layer/fill.js +104 -0
- package/dist/components/MapEditor/lib/map_layer/line.d.ts +20 -0
- package/dist/components/MapEditor/lib/map_layer/line.js +90 -0
- package/dist/components/MapEditor/lib/map_layer/symbol.d.ts +19 -0
- package/dist/components/MapEditor/lib/map_layer/symbol.js +123 -0
- package/dist/components/MapEditor/lib/{types.d.ts → map_layer/types.d.ts} +7 -15
- package/dist/components/MapEditor/lib/map_layer/types.js +1 -0
- package/dist/components/MapEditor/lib/state/reader.d.ts +17 -0
- package/dist/components/MapEditor/lib/state/reader.js +161 -0
- package/dist/components/MapEditor/lib/state/types.d.ts +20 -0
- package/dist/components/MapEditor/lib/state/types.js +1 -0
- package/dist/components/MapEditor/lib/state/writer.d.ts +17 -0
- package/dist/components/MapEditor/lib/state/writer.js +178 -0
- package/dist/components/MapEditor/lib/symbols.d.ts +16 -0
- package/dist/components/MapEditor/lib/symbols.js +173 -0
- package/dist/components/MapEditor/lib/utils.d.ts +8 -1
- package/dist/components/MapEditor/lib/utils.js +33 -2
- package/dist/utils/draw/bbox.d.ts +1 -0
- package/dist/utils/draw/bbox.js +1 -1
- package/package.json +29 -30
- package/dist/components/MapEditor/Editor.svelte +0 -25
- package/dist/components/MapEditor/EditorLine.svelte +0 -27
- package/dist/components/MapEditor/EditorLine.svelte.d.ts +0 -7
- package/dist/components/MapEditor/EditorMarker.svelte +0 -42
- package/dist/components/MapEditor/EditorMarker.svelte.d.ts +0 -7
- package/dist/components/MapEditor/editor.scss +0 -16
- package/dist/components/MapEditor/lib/element_abstract.d.ts +0 -20
- package/dist/components/MapEditor/lib/element_abstract.js +0 -58
- package/dist/components/MapEditor/lib/element_line.d.ts +0 -14
- package/dist/components/MapEditor/lib/element_line.js +0 -76
- package/dist/components/MapEditor/lib/element_marker.d.ts +0 -20
- package/dist/components/MapEditor/lib/element_marker.js +0 -191
- package/dist/components/MapEditor/lib/map_layer.d.ts +0 -14
- package/dist/components/MapEditor/lib/map_layer.js +0 -61
- package/dist/utils/sprite_library.d.ts +0 -19
- package/dist/utils/sprite_library.js +0 -30
- /package/dist/components/MapEditor/lib/{types.js → element/types.js} +0 -0
@@ -1,27 +1,27 @@
|
|
1
|
-
<script lang="ts">
|
2
|
-
import
|
3
|
-
import
|
4
|
-
import {
|
5
|
-
import
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
let
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
}
|
24
|
-
|
1
|
+
<script lang="ts">
|
2
|
+
import type { Map as MaplibreMapType } from 'maplibre-gl';
|
3
|
+
import BasicMap from '../BasicMap/BasicMap.svelte';
|
4
|
+
import { onMount } from 'svelte';
|
5
|
+
import Sidebar from './components/Sidebar.svelte';
|
6
|
+
import type { GeometryManager } from './lib/geometry_manager.js';
|
7
|
+
|
8
|
+
let showSidebar = $state(false);
|
9
|
+
|
10
|
+
onMount(() => {
|
11
|
+
const inIframe = window.self !== window.top;
|
12
|
+
if (!inIframe) showSidebar = true;
|
13
|
+
});
|
14
|
+
|
15
|
+
let map: MaplibreMapType | undefined = $state();
|
16
|
+
let geometryManager: GeometryManager | undefined = $state();
|
17
|
+
|
18
|
+
function onMapInit(_map: MaplibreMapType) {
|
19
|
+
map = _map;
|
20
|
+
map.on('load', async () => {
|
21
|
+
const { GeometryManager } = await import('./lib/geometry_manager.js');
|
22
|
+
geometryManager = new GeometryManager(map!);
|
23
|
+
});
|
24
|
+
}
|
25
25
|
</script>
|
26
26
|
|
27
27
|
<div class="page">
|
@@ -29,62 +29,16 @@ $effect(() => geometryManager?.setActiveElement(activeElement));
|
|
29
29
|
<BasicMap {onMapInit} styleOptions={{ disableDarkMode: true }}></BasicMap>
|
30
30
|
</div>
|
31
31
|
{#if showSidebar && geometryManager}
|
32
|
-
<
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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>
|
32
|
+
<Sidebar {geometryManager} width={200} />
|
33
|
+
|
34
|
+
<style>
|
35
|
+
.page .container {
|
36
|
+
width: calc(100% - 200px);
|
37
|
+
position: absolute;
|
38
|
+
top: 0;
|
39
|
+
left: 0;
|
40
|
+
}
|
41
|
+
</style>
|
88
42
|
{/if}
|
89
43
|
</div>
|
90
44
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import type { AbstractElement } from '../lib/element/abstract.js';
|
3
|
+
import EditorFill from './EditorFill.svelte';
|
4
|
+
import EditorStroke from './EditorStroke.svelte';
|
5
|
+
import EditorSymbol from './EditorSymbol.svelte';
|
6
|
+
import { LineElement } from '../lib/element/line.js';
|
7
|
+
import { MarkerElement } from '../lib/element/marker.js';
|
8
|
+
import { PolygonElement } from '../lib/element/polygon.js';
|
9
|
+
|
10
|
+
const { element }: { element: AbstractElement } = $props();
|
11
|
+
let strokeVisible = $state(false);
|
12
|
+
|
13
|
+
if (element instanceof PolygonElement) {
|
14
|
+
element.strokeLayer.visible.subscribe((value) => (strokeVisible = value));
|
15
|
+
}
|
16
|
+
</script>
|
17
|
+
|
18
|
+
{#if element instanceof MarkerElement}
|
19
|
+
<h2>Marker</h2>
|
20
|
+
<EditorSymbol layer={element.layer} />
|
21
|
+
{/if}
|
22
|
+
{#if element instanceof LineElement}
|
23
|
+
<h2>Line Stroke</h2>
|
24
|
+
<EditorStroke layer={element.layer} />
|
25
|
+
{/if}
|
26
|
+
{#if element instanceof PolygonElement}
|
27
|
+
<h2>Polygon Fill</h2>
|
28
|
+
<EditorFill layer={element.fillLayer} />
|
29
|
+
<h2>Polygon Stroke</h2>
|
30
|
+
|
31
|
+
<div class="row-input">
|
32
|
+
<label for="showStroke">Outline:</label>
|
33
|
+
<input
|
34
|
+
id="showStroke"
|
35
|
+
type="checkbox"
|
36
|
+
bind:checked={
|
37
|
+
() => strokeVisible, (v) => (element as PolygonElement).strokeLayer.visible.set(v)
|
38
|
+
}
|
39
|
+
/>
|
40
|
+
</div>
|
41
|
+
|
42
|
+
{#if strokeVisible}
|
43
|
+
<EditorStroke layer={element.strokeLayer} />
|
44
|
+
{/if}
|
45
|
+
{/if}
|
46
|
+
{#if element instanceof PolygonElement || element instanceof LineElement}
|
47
|
+
<h2>Shape</h2>
|
48
|
+
<p>
|
49
|
+
Drag points to move.<br />Drag a midpoint to add.<br />Shift-click to delete a point.
|
50
|
+
</p>
|
51
|
+
{/if}
|
52
|
+
<h2>Actions</h2>
|
53
|
+
<input type="button" value="Delete" onclick={() => element!.delete()} />
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import { fillPatterns, type MapLayerFill } from '../lib/map_layer/fill.js';
|
3
|
+
|
4
|
+
const { layer }: { layer: MapLayerFill } = $props();
|
5
|
+
|
6
|
+
let color = $state(layer.color);
|
7
|
+
let pattern = $state(layer.pattern);
|
8
|
+
let opacity = $state(layer.opacity);
|
9
|
+
</script>
|
10
|
+
|
11
|
+
<div class="row-input">
|
12
|
+
<label for="color">Color:</label>
|
13
|
+
<input id="color" type="color" bind:value={$color} />
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<div class="row-input">
|
17
|
+
<label for="pattern">Pattern:</label>
|
18
|
+
<select id="pattern" bind:value={$pattern}>
|
19
|
+
{#each fillPatterns as [index, fill] (index)}
|
20
|
+
<option value={index}>{fill.name}</option>
|
21
|
+
{/each}
|
22
|
+
</select>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="row-input">
|
26
|
+
<label for="opacity">Opacity:</label>
|
27
|
+
<input id="opacity" type="range" min="0" max="1" step="0.02" bind:value={$opacity} />
|
28
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { type MapLayerFill } from '../lib/map_layer/fill.js';
|
2
|
+
type $$ComponentProps = {
|
3
|
+
layer: MapLayerFill;
|
4
|
+
};
|
5
|
+
declare const EditorFill: import("svelte").Component<$$ComponentProps, {}, "">;
|
6
|
+
type EditorFill = ReturnType<typeof EditorFill>;
|
7
|
+
export default EditorFill;
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import { dashArrays, MapLayerLine } from '../lib/map_layer/line.js';
|
3
|
+
|
4
|
+
const { layer }: { layer: MapLayerLine } = $props();
|
5
|
+
|
6
|
+
let color = $state(layer.color);
|
7
|
+
let width = $state(layer.width);
|
8
|
+
let dashed = $state(layer.dashed);
|
9
|
+
</script>
|
10
|
+
|
11
|
+
<div class="row-input">
|
12
|
+
<label for="dashed">Dashed:</label>
|
13
|
+
<select id="dashed" bind:value={$dashed}>
|
14
|
+
{#each dashArrays as [index, dash] (index)}
|
15
|
+
<option value={index}>{dash.name}</option>
|
16
|
+
{/each}
|
17
|
+
</select>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="row-input">
|
21
|
+
<label for="color">Color:</label>
|
22
|
+
<input id="color" type="color" bind:value={$color} />
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="row-input">
|
26
|
+
<label for="width">Width:</label>
|
27
|
+
<input id="width" type="range" min="0.5" max="5" step="0.5" bind:value={$width} />
|
28
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { MapLayerLine } from '../lib/map_layer/line.js';
|
2
|
+
type $$ComponentProps = {
|
3
|
+
layer: MapLayerLine;
|
4
|
+
};
|
5
|
+
declare const EditorStroke: import("svelte").Component<$$ComponentProps, {}, "">;
|
6
|
+
type EditorStroke = ReturnType<typeof EditorStroke>;
|
7
|
+
export default EditorStroke;
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import { MapLayerSymbol } from '../lib/map_layer/symbol.js';
|
3
|
+
import SymbolSelector from './SymbolSelector.svelte';
|
4
|
+
|
5
|
+
const { layer }: { layer: MapLayerSymbol } = $props();
|
6
|
+
|
7
|
+
let symbolIndex = $state(layer.symbolIndex);
|
8
|
+
let color = $state(layer.color);
|
9
|
+
let rotate = $state(layer.rotate);
|
10
|
+
let halo = $state(layer.halo);
|
11
|
+
let label = $state(layer.label);
|
12
|
+
let size = $state(layer.size);
|
13
|
+
</script>
|
14
|
+
|
15
|
+
<div class="row-input">
|
16
|
+
<div class="label">Symbol:</div>
|
17
|
+
<SymbolSelector bind:symbolIndex={$symbolIndex} symbolLibrary={layer.manager.symbolLibrary} />
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="row-input">
|
21
|
+
<label for="color">Color:</label>
|
22
|
+
<input id="color" type="color" bind:value={$color} />
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div class="row-input">
|
26
|
+
<label for="size">Size:</label>
|
27
|
+
<input id="size" type="range" min="0.5" max="3" step="0.1" bind:value={$size} />
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="row-input">
|
31
|
+
<label for="rotate">Rotation:</label>
|
32
|
+
<input id="rotate" type="range" min="-180" max="180" step="15" bind:value={$rotate} />
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<div class="row-input">
|
36
|
+
<label for="halo">Halo:</label>
|
37
|
+
<input id="halo" type="range" min="0" max="3" step="0.5" bind:value={$halo} />
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class="row-input">
|
41
|
+
<label for="label">Label:</label>
|
42
|
+
<input id="label" type="label" bind:value={$label} />
|
43
|
+
</div>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
import { MapLayerSymbol } from '../lib/map_layer/symbol.js';
|
2
|
+
type $$ComponentProps = {
|
3
|
+
layer: MapLayerSymbol;
|
4
|
+
};
|
5
|
+
declare const EditorSymbol: import("svelte").Component<$$ComponentProps, {}, "">;
|
6
|
+
type EditorSymbol = ReturnType<typeof EditorSymbol>;
|
7
|
+
export default EditorSymbol;
|
@@ -0,0 +1,179 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import type { AbstractElement } from '../lib/element/abstract.js';
|
3
|
+
import Editor from './Editor.svelte';
|
4
|
+
import type { GeometryManager } from '../lib/geometry_manager.js';
|
5
|
+
|
6
|
+
const { geometryManager, width }: { geometryManager: GeometryManager; width: number } = $props();
|
7
|
+
|
8
|
+
let activeElement: AbstractElement | undefined = $state(undefined);
|
9
|
+
$effect(() => geometryManager.selectElement(activeElement));
|
10
|
+
|
11
|
+
geometryManager.selectedElement.subscribe((value) => (activeElement = value));
|
12
|
+
|
13
|
+
function importGeoJSON() {
|
14
|
+
const input = document.createElement('input');
|
15
|
+
input.type = 'file';
|
16
|
+
input.onchange = (_) => {
|
17
|
+
if (!input.files) return alert('No file selected.');
|
18
|
+
const file = input.files[0];
|
19
|
+
const reader = new FileReader();
|
20
|
+
reader.onload = (evt) => {
|
21
|
+
try {
|
22
|
+
if (!evt.target) return alert('Failed to read file.');
|
23
|
+
const json = JSON.parse(evt.target.result as string);
|
24
|
+
geometryManager.addGeoJSON(json);
|
25
|
+
} catch (error) {
|
26
|
+
console.error(error);
|
27
|
+
return alert('Failed to import GeoJSON. Please check the file format.');
|
28
|
+
}
|
29
|
+
};
|
30
|
+
|
31
|
+
reader.onerror = () => alert('Failed to read file. Please try again.');
|
32
|
+
|
33
|
+
reader.readAsText(file);
|
34
|
+
};
|
35
|
+
input.click();
|
36
|
+
}
|
37
|
+
|
38
|
+
function exportGeoJSON() {
|
39
|
+
const geoJSON = geometryManager.getGeoJSON();
|
40
|
+
const blob = new Blob([JSON.stringify(geoJSON)], { type: 'application/geo+json' });
|
41
|
+
const url = URL.createObjectURL(blob);
|
42
|
+
const a = document.createElement('a');
|
43
|
+
a.setAttribute('href', url);
|
44
|
+
a.setAttribute('download', 'map.geojson');
|
45
|
+
a.click();
|
46
|
+
URL.revokeObjectURL(url);
|
47
|
+
}
|
48
|
+
</script>
|
49
|
+
|
50
|
+
<div class="sidebar" style="--gap: 10px;width: {width}px;">
|
51
|
+
<div style="min-height: calc(100vh - 2em);">
|
52
|
+
<div class="label">GeoJSON:</div>
|
53
|
+
<div class="row-flex">
|
54
|
+
<input type="button" value="Import" onclick={importGeoJSON} />
|
55
|
+
<input type="button" value="Export" onclick={exportGeoJSON} />
|
56
|
+
</div>
|
57
|
+
<hr />
|
58
|
+
<div class="label">Add new:</div>
|
59
|
+
<div class="row-flex">
|
60
|
+
<input
|
61
|
+
type="button"
|
62
|
+
value="Marker"
|
63
|
+
onclick={() => (activeElement = geometryManager.addNewMarker())}
|
64
|
+
/>
|
65
|
+
<input
|
66
|
+
type="button"
|
67
|
+
value="Line"
|
68
|
+
onclick={() => (activeElement = geometryManager.addNewLine())}
|
69
|
+
/>
|
70
|
+
<input
|
71
|
+
type="button"
|
72
|
+
value="Polygon"
|
73
|
+
onclick={() => (activeElement = geometryManager.addNewPolygon())}
|
74
|
+
/>
|
75
|
+
</div>
|
76
|
+
{#if activeElement != null}
|
77
|
+
<hr />
|
78
|
+
<Editor element={activeElement} />
|
79
|
+
{/if}
|
80
|
+
</div>
|
81
|
+
<div class="footer">
|
82
|
+
<a href="https://github.com/versatiles-org/node-versatiles-svelte/issues" target="_blank">
|
83
|
+
Add a GitHub issue.</a
|
84
|
+
>
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
|
88
|
+
<style>
|
89
|
+
.sidebar {
|
90
|
+
width: 200px;
|
91
|
+
height: 100%;
|
92
|
+
position: absolute;
|
93
|
+
top: 0;
|
94
|
+
right: 0;
|
95
|
+
background-color: #eee;
|
96
|
+
overflow-y: scroll;
|
97
|
+
box-sizing: border-box;
|
98
|
+
padding: 0.5em var(--gap) 0;
|
99
|
+
border-left: 0.5px solid rgba(0, 0, 0, 0.5);
|
100
|
+
|
101
|
+
hr {
|
102
|
+
border: none;
|
103
|
+
border-top: 0.5px solid rgba(0, 0, 0, 1);
|
104
|
+
margin: var(--gap) 0 var(--gap);
|
105
|
+
}
|
106
|
+
|
107
|
+
:global(h2) {
|
108
|
+
font-size: 0.9em;
|
109
|
+
font-weight: normal;
|
110
|
+
opacity: 0.5;
|
111
|
+
padding-top: var(--gap);
|
112
|
+
border-top: 0.5px solid rgba(0, 0, 0, 1);
|
113
|
+
margin: var(--gap) 0 var(--gap);
|
114
|
+
text-align: center;
|
115
|
+
}
|
116
|
+
|
117
|
+
:global(.row-flex) {
|
118
|
+
margin-bottom: var(--gap);
|
119
|
+
display: flex;
|
120
|
+
justify-content: space-between;
|
121
|
+
column-gap: var(--gap);
|
122
|
+
:global(input) {
|
123
|
+
flex-grow: 0;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
:global(.row-input) {
|
128
|
+
margin: var(--gap) 0 var(--gap);
|
129
|
+
display: flex;
|
130
|
+
justify-content: space-between;
|
131
|
+
align-items: center;
|
132
|
+
& > :global(label) {
|
133
|
+
flex-grow: 0;
|
134
|
+
}
|
135
|
+
& > :global(button),
|
136
|
+
& > :global(input),
|
137
|
+
& > :global(select) {
|
138
|
+
width: 60%;
|
139
|
+
flex-grow: 0;
|
140
|
+
}
|
141
|
+
& > :global(input[type='checkbox']) {
|
142
|
+
width: auto;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
:global(label),
|
147
|
+
:global(.label) {
|
148
|
+
opacity: 0.7;
|
149
|
+
font-size: 0.8em;
|
150
|
+
}
|
151
|
+
|
152
|
+
:global(button),
|
153
|
+
:global(input),
|
154
|
+
:global(select) {
|
155
|
+
width: 100%;
|
156
|
+
box-sizing: border-box;
|
157
|
+
margin: 0;
|
158
|
+
}
|
159
|
+
|
160
|
+
:global(p) {
|
161
|
+
font-size: 0.8em;
|
162
|
+
opacity: 0.5;
|
163
|
+
margin: 0.5em 0 1em;
|
164
|
+
}
|
165
|
+
|
166
|
+
.footer {
|
167
|
+
text-align: right;
|
168
|
+
font-size: 0.8em;
|
169
|
+
a {
|
170
|
+
color: #000;
|
171
|
+
text-decoration: none;
|
172
|
+
opacity: 0.3;
|
173
|
+
&:hover {
|
174
|
+
opacity: 1;
|
175
|
+
}
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
</style>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import type { GeometryManager } from '../lib/geometry_manager.js';
|
2
|
+
type $$ComponentProps = {
|
3
|
+
geometryManager: GeometryManager;
|
4
|
+
width: number;
|
5
|
+
};
|
6
|
+
declare const Sidebar: import("svelte").Component<$$ComponentProps, {}, "">;
|
7
|
+
type Sidebar = ReturnType<typeof Sidebar>;
|
8
|
+
export default Sidebar;
|
@@ -0,0 +1,118 @@
|
|
1
|
+
<script lang="ts">
|
2
|
+
import type { Action } from 'svelte/action';
|
3
|
+
import type { SymbolLibrary } from '../lib/symbols.js';
|
4
|
+
|
5
|
+
let {
|
6
|
+
symbolIndex = $bindable(),
|
7
|
+
symbolLibrary
|
8
|
+
}: { symbolIndex: number; symbolLibrary: SymbolLibrary } = $props();
|
9
|
+
|
10
|
+
let open = $state(false);
|
11
|
+
|
12
|
+
const drawIconHalo: Action<HTMLCanvasElement, number> = (canvas, index) =>
|
13
|
+
symbolLibrary.drawSymbol(canvas, index, true);
|
14
|
+
|
15
|
+
const drawIcon: Action<HTMLCanvasElement, number> = (canvas, index) =>
|
16
|
+
symbolLibrary.drawSymbol(canvas, index);
|
17
|
+
</script>
|
18
|
+
|
19
|
+
<button
|
20
|
+
onclick={() => (open = !open)}
|
21
|
+
style="text-align: left; white-space: nowrap; overflow: hidden; padding: 1px"
|
22
|
+
>
|
23
|
+
{#key symbolIndex}
|
24
|
+
<canvas
|
25
|
+
width="40"
|
26
|
+
height="40"
|
27
|
+
use:drawIcon={symbolIndex}
|
28
|
+
style="width:20px;height:20px;vertical-align:middle"
|
29
|
+
></canvas>
|
30
|
+
{/key}
|
31
|
+
{#if symbolIndex !== undefined}
|
32
|
+
{symbolLibrary.getSymbol(symbolIndex)?.name}
|
33
|
+
{:else}
|
34
|
+
Select Symbol
|
35
|
+
{/if}
|
36
|
+
</button>
|
37
|
+
|
38
|
+
<div class="modal" style="display: {open ? 'block' : 'none'};">
|
39
|
+
<button class="close" onclick={() => (open = false)}>✕</button>
|
40
|
+
<div class="inner">
|
41
|
+
{#each symbolLibrary.asList() as symbol (symbol.index)}
|
42
|
+
<button
|
43
|
+
class="icon"
|
44
|
+
onclick={() => {
|
45
|
+
symbolIndex = symbol.index;
|
46
|
+
open = false;
|
47
|
+
}}
|
48
|
+
><canvas width="64" height="64" use:drawIconHalo={symbol.index}></canvas><br
|
49
|
+
/>{symbol.name}</button
|
50
|
+
>
|
51
|
+
{/each}
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
|
55
|
+
<style>
|
56
|
+
.modal {
|
57
|
+
position: fixed;
|
58
|
+
top: max(calc(50vh - 250px), 0px);
|
59
|
+
left: max(calc(50vw - 250px), 0px);
|
60
|
+
width: min(500px, 100vw);
|
61
|
+
height: min(500px, 100vh);
|
62
|
+
background-color: rgba(255, 255, 255, 0.5);
|
63
|
+
backdrop-filter: blur(20px) brightness(0.85);
|
64
|
+
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
|
65
|
+
z-index: 10000;
|
66
|
+
border: 0.5px solid rgba(0, 0, 0, 0.5);
|
67
|
+
border-radius: 10px;
|
68
|
+
box-sizing: border-box;
|
69
|
+
padding: 20px;
|
70
|
+
|
71
|
+
.inner {
|
72
|
+
width: 100%;
|
73
|
+
height: 100%;
|
74
|
+
overflow-y: scroll;
|
75
|
+
display: grid;
|
76
|
+
grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
|
77
|
+
row-gap: 10px;
|
78
|
+
column-gap: 0px;
|
79
|
+
justify-items: center;
|
80
|
+
|
81
|
+
.icon {
|
82
|
+
width: 48px;
|
83
|
+
height: 48px;
|
84
|
+
cursor: pointer;
|
85
|
+
border: none;
|
86
|
+
font-size: 0.6em;
|
87
|
+
background: none;
|
88
|
+
line-height: 1em;
|
89
|
+
text-align: center;
|
90
|
+
padding: 0;
|
91
|
+
|
92
|
+
&:hover {
|
93
|
+
background-color: rgba(0, 0, 0, 0.1);
|
94
|
+
}
|
95
|
+
|
96
|
+
canvas {
|
97
|
+
display: inline-block;
|
98
|
+
width: 32px;
|
99
|
+
height: 32px;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
.close {
|
105
|
+
position: absolute;
|
106
|
+
top: 0px;
|
107
|
+
right: 0px;
|
108
|
+
font-size: 20px;
|
109
|
+
cursor: pointer;
|
110
|
+
background: none;
|
111
|
+
border: none;
|
112
|
+
width: 25px;
|
113
|
+
height: 25px;
|
114
|
+
text-align: center;
|
115
|
+
padding: 0;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
</style>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import type { SymbolLibrary } from '../lib/symbols.js';
|
2
|
+
type $$ComponentProps = {
|
3
|
+
symbolIndex: number;
|
4
|
+
symbolLibrary: SymbolLibrary;
|
5
|
+
};
|
6
|
+
declare const SymbolSelector: import("svelte").Component<$$ComponentProps, {}, "symbolIndex">;
|
7
|
+
type SymbolSelector = ReturnType<typeof SymbolSelector>;
|
8
|
+
export default SymbolSelector;
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { type Writable } from 'svelte/store';
|
2
|
+
import type { AbstractElement } from '../element/abstract.js';
|
3
|
+
import type { StateObject } from '../state/types.js';
|
4
|
+
import { MockMap } from './map.js';
|
5
|
+
import { MockCursor } from './cursor.js';
|
6
|
+
export declare class MockGeometryManager {
|
7
|
+
readonly elements: Writable<AbstractElement[]>;
|
8
|
+
readonly activeElement: Writable<AbstractElement | undefined>;
|
9
|
+
readonly map: MockMap;
|
10
|
+
readonly cursor: MockCursor;
|
11
|
+
constructor();
|
12
|
+
setActiveElement: import("vitest").Mock<(...args: any[]) => any>;
|
13
|
+
getState: import("vitest").Mock<() => StateObject>;
|
14
|
+
saveState: import("vitest").Mock<(...args: any[]) => any>;
|
15
|
+
loadState: import("vitest").Mock<(...args: any[]) => any>;
|
16
|
+
getElement: import("vitest").Mock<(index: number) => AbstractElement>;
|
17
|
+
addNewMarker: import("vitest").Mock<() => AbstractElement>;
|
18
|
+
addNewLine: import("vitest").Mock<() => AbstractElement>;
|
19
|
+
addNewPolygon: import("vitest").Mock<() => AbstractElement>;
|
20
|
+
deleteElement: import("vitest").Mock<(...args: any[]) => any>;
|
21
|
+
drawSelectionNodes: import("vitest").Mock<(...args: any[]) => any>;
|
22
|
+
}
|