@versatiles/svelte 0.3.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -6
- 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.svelte +43 -54
- package/dist/components/BBoxMap/BBoxMap.svelte.d.ts +6 -17
- package/dist/components/BasicMap/BasicMap.svelte +34 -37
- package/dist/components/BasicMap/BasicMap.svelte.d.ts +9 -24
- package/dist/components/LocatorMap/LocatorMap.svelte +61 -20
- 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 +2 -1
- package/dist/index.js +2 -1
- package/dist/utils/draw/bbox.d.ts +4 -10
- package/dist/utils/draw/bbox.js +62 -62
- package/dist/utils/map_style.d.ts +5 -2
- package/dist/utils/map_style.js +13 -6
- package/package.json +10 -7
- package/dist/components/AutoComplete.svelte +0 -196
- package/dist/utils/draw/abstract.d.ts +0 -5
- package/dist/utils/draw/abstract.js +0 -2
- package/dist/utils/draw/marker.d.ts +0 -24
- package/dist/utils/draw/marker.js +0 -97
- package/dist/utils/draw/style.d.ts +0 -19
- package/dist/utils/draw/style.js +0 -40
@@ -1,196 +0,0 @@
|
|
1
|
-
<!-- AutoComplete.svelte -->
|
2
|
-
<script lang="ts" generics="T">
|
3
|
-
import { isDarkMode } from '../utils/map_style.js';
|
4
|
-
/* eslint svelte/no-at-html-tags: off */
|
5
|
-
|
6
|
-
import { createEventDispatcher, onMount } from 'svelte';
|
7
|
-
const dispatch = createEventDispatcher();
|
8
|
-
|
9
|
-
type Item = { key: string; value: T };
|
10
|
-
type ResultItem = Item & { _label: string };
|
11
|
-
|
12
|
-
// Component properties
|
13
|
-
export let placeholder: string = '';
|
14
|
-
export let minChar: number = 3;
|
15
|
-
export let maxItems: number = 10;
|
16
|
-
|
17
|
-
// Reactive variables
|
18
|
-
export let items: Item[];
|
19
|
-
|
20
|
-
let inputElement: HTMLInputElement; // Reference to DOM element
|
21
|
-
let autocompleteElement: HTMLDivElement; // Reference to DOM element
|
22
|
-
let isOpen = false;
|
23
|
-
let results: ResultItem[] = [];
|
24
|
-
let selectedIndex = 0;
|
25
|
-
let inputText: string = '';
|
26
|
-
|
27
|
-
// Escape special characters in search string for use in regex
|
28
|
-
const regExpEscape = (s: string) => s.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
|
29
|
-
|
30
|
-
if (inputText.length >= minChar) {
|
31
|
-
const r = filterResults();
|
32
|
-
if (r.length > 0) {
|
33
|
-
const { key, value } = r[0];
|
34
|
-
inputText = key;
|
35
|
-
dispatch('change', JSON.parse(JSON.stringify(value)));
|
36
|
-
} else {
|
37
|
-
inputText = '';
|
38
|
-
}
|
39
|
-
}
|
40
|
-
|
41
|
-
export function setInputText(text: string) {
|
42
|
-
inputText = text;
|
43
|
-
results = filterResults();
|
44
|
-
close(0);
|
45
|
-
}
|
46
|
-
|
47
|
-
// Handle input change
|
48
|
-
function onChange() {
|
49
|
-
if (inputText.length >= minChar) {
|
50
|
-
results = filterResults();
|
51
|
-
selectedIndex = 0;
|
52
|
-
isOpen = true;
|
53
|
-
} else {
|
54
|
-
isOpen = false;
|
55
|
-
}
|
56
|
-
}
|
57
|
-
|
58
|
-
function onFocus() {
|
59
|
-
inputElement.setSelectionRange(0, 1000);
|
60
|
-
}
|
61
|
-
|
62
|
-
// Filter results based on search query
|
63
|
-
function filterResults(): ResultItem[] {
|
64
|
-
const searchText = inputText.trim();
|
65
|
-
const searchTextUpper = searchText.toUpperCase();
|
66
|
-
const searchReg = RegExp(regExpEscape(searchText), 'i');
|
67
|
-
return items
|
68
|
-
.filter((item) => item.key.toUpperCase().includes(searchTextUpper))
|
69
|
-
.slice(0, maxItems)
|
70
|
-
.map((item) => ({
|
71
|
-
...item,
|
72
|
-
_label: item.key.replace(searchReg, '<span>$&</span>')
|
73
|
-
}));
|
74
|
-
}
|
75
|
-
|
76
|
-
// Handle keyboard navigation
|
77
|
-
function onKeyDown(event: KeyboardEvent) {
|
78
|
-
switch (event.key) {
|
79
|
-
case 'ArrowDown':
|
80
|
-
if (selectedIndex < results.length - 1) selectedIndex += 1;
|
81
|
-
break;
|
82
|
-
case 'ArrowUp':
|
83
|
-
if (selectedIndex > 0) selectedIndex -= 1;
|
84
|
-
break;
|
85
|
-
case 'Enter':
|
86
|
-
event.preventDefault();
|
87
|
-
close(selectedIndex);
|
88
|
-
break;
|
89
|
-
case 'Escape':
|
90
|
-
event.preventDefault();
|
91
|
-
close();
|
92
|
-
break;
|
93
|
-
}
|
94
|
-
}
|
95
|
-
|
96
|
-
// Close the autocomplete and select an item
|
97
|
-
function close(index = -1) {
|
98
|
-
isOpen = false;
|
99
|
-
if (index >= 0 && results[index]) {
|
100
|
-
const { key, value } = results[index];
|
101
|
-
inputText = key;
|
102
|
-
dispatch('change', JSON.parse(JSON.stringify(value)));
|
103
|
-
}
|
104
|
-
}
|
105
|
-
|
106
|
-
onMount(() => {
|
107
|
-
const darkMode = isDarkMode(autocompleteElement);
|
108
|
-
autocompleteElement.style.setProperty('--bg-color', darkMode ? '#000' : '#fff');
|
109
|
-
autocompleteElement.style.setProperty('--fg-color', darkMode ? '#fff' : '#000');
|
110
|
-
});
|
111
|
-
</script>
|
112
|
-
|
113
|
-
<svelte:window on:click={() => close()} />
|
114
|
-
|
115
|
-
<div class="autocomplete" bind:this={autocompleteElement}>
|
116
|
-
<input
|
117
|
-
type="text"
|
118
|
-
bind:value={inputText}
|
119
|
-
{placeholder}
|
120
|
-
autocomplete="off"
|
121
|
-
on:input={onChange}
|
122
|
-
on:keydown={onKeyDown}
|
123
|
-
on:focusin={onFocus}
|
124
|
-
on:click={(e) => e.stopPropagation()}
|
125
|
-
bind:this={inputElement}
|
126
|
-
aria-activedescendant={isOpen ? `result-${selectedIndex}` : undefined}
|
127
|
-
aria-autocomplete="list"
|
128
|
-
aria-controls="autocomplete-results"
|
129
|
-
/>
|
130
|
-
<div class="autocomplete-results" class:hide-results={!isOpen}>
|
131
|
-
{#each results as result, i}
|
132
|
-
<button
|
133
|
-
on:click={() => close(i)}
|
134
|
-
class={i === selectedIndex ? ' is-active' : ''}
|
135
|
-
role="option"
|
136
|
-
aria-selected={i === selectedIndex}
|
137
|
-
>
|
138
|
-
{@html result._label}
|
139
|
-
</button>
|
140
|
-
{/each}
|
141
|
-
</div>
|
142
|
-
</div>
|
143
|
-
|
144
|
-
<style>
|
145
|
-
.autocomplete {
|
146
|
-
position: relative;
|
147
|
-
border-radius: 0.5em;
|
148
|
-
background: color-mix(in srgb, var(--bg-color) 80%, transparent);
|
149
|
-
box-sizing: border-box;
|
150
|
-
line-height: normal;
|
151
|
-
}
|
152
|
-
|
153
|
-
input {
|
154
|
-
width: 100%;
|
155
|
-
display: block;
|
156
|
-
box-sizing: border-box;
|
157
|
-
padding: 0.3em 0.6em;
|
158
|
-
border: none;
|
159
|
-
background: none;
|
160
|
-
color: var(--fg-color);
|
161
|
-
}
|
162
|
-
|
163
|
-
.autocomplete-results {
|
164
|
-
padding: 0;
|
165
|
-
margin: 0;
|
166
|
-
background: none;
|
167
|
-
width: 100%;
|
168
|
-
display: block;
|
169
|
-
border-radius: 0 0 0.5em 0.5em;
|
170
|
-
}
|
171
|
-
|
172
|
-
.autocomplete-results.hide-results {
|
173
|
-
display: none;
|
174
|
-
}
|
175
|
-
|
176
|
-
button {
|
177
|
-
padding: 0.2rem 0.5rem;
|
178
|
-
cursor: pointer;
|
179
|
-
border: none;
|
180
|
-
display: block;
|
181
|
-
background: transparent;
|
182
|
-
font-weight: normal;
|
183
|
-
color: color-mix(in srgb, var(--fg-color) 50%, transparent);
|
184
|
-
width: 100%;
|
185
|
-
text-align: left;
|
186
|
-
}
|
187
|
-
|
188
|
-
button > :global(span) {
|
189
|
-
color: var(--fg-color);
|
190
|
-
}
|
191
|
-
|
192
|
-
button.is-active,
|
193
|
-
button:hover {
|
194
|
-
background-color: color-mix(in srgb, var(--fg-color) 15%, transparent);
|
195
|
-
}
|
196
|
-
</style>
|
@@ -1,24 +0,0 @@
|
|
1
|
-
import type geojson from 'geojson';
|
2
|
-
import type { SymbolStyle } from './style.js';
|
3
|
-
import { AbstractDrawer } from './abstract.js';
|
4
|
-
export type Point = [number, number];
|
5
|
-
export declare class MarkerDrawer extends AbstractDrawer<geojson.BBox> {
|
6
|
-
private source?;
|
7
|
-
private isDragging;
|
8
|
-
private dragPoint;
|
9
|
-
private map;
|
10
|
-
private canvas;
|
11
|
-
private symbolStyle;
|
12
|
-
private point;
|
13
|
-
constructor(map: maplibregl.Map, options?: {
|
14
|
-
point?: Point;
|
15
|
-
} & SymbolStyle);
|
16
|
-
private updateDragPoint;
|
17
|
-
private getAsFeatureCollection;
|
18
|
-
setGeometry(point: geojson.Position): void;
|
19
|
-
getBounds(): maplibregl.LngLatBounds;
|
20
|
-
private redraw;
|
21
|
-
private getAsPixel;
|
22
|
-
private checkDragPointAt;
|
23
|
-
private doDrag;
|
24
|
-
}
|
@@ -1,97 +0,0 @@
|
|
1
|
-
import { AbstractDrawer } from './abstract.js';
|
2
|
-
import { getSymbolStyle } from './style.js';
|
3
|
-
const maplibregl = await import('maplibre-gl');
|
4
|
-
const { LngLatBounds } = maplibregl;
|
5
|
-
export class MarkerDrawer extends AbstractDrawer {
|
6
|
-
source;
|
7
|
-
isDragging = false;
|
8
|
-
dragPoint = false;
|
9
|
-
map;
|
10
|
-
canvas;
|
11
|
-
symbolStyle;
|
12
|
-
point;
|
13
|
-
constructor(map, options) {
|
14
|
-
super();
|
15
|
-
this.point = options?.point ?? [0, 0];
|
16
|
-
this.symbolStyle = getSymbolStyle(options);
|
17
|
-
this.map = map;
|
18
|
-
const sourceId = 'marker_' + Math.random().toString(36).slice(2);
|
19
|
-
if (this.source)
|
20
|
-
throw new Error('BBoxDrawer already added to map');
|
21
|
-
map.addSource(sourceId, { type: 'geojson', data: this.getAsFeatureCollection() });
|
22
|
-
map.addLayer({
|
23
|
-
id: 'marker_' + Math.random().toString(36).slice(2),
|
24
|
-
type: 'symbol',
|
25
|
-
source: sourceId,
|
26
|
-
filter: ['==', '$type', 'Point'],
|
27
|
-
...this.symbolStyle
|
28
|
-
});
|
29
|
-
this.source = map.getSource(sourceId);
|
30
|
-
this.canvas = map.getCanvasContainer();
|
31
|
-
map.on('mousemove', (e) => {
|
32
|
-
if (e.originalEvent.buttons % 2 === 0)
|
33
|
-
return this.checkDragPointAt(e.point);
|
34
|
-
if (!this.isDragging)
|
35
|
-
return;
|
36
|
-
if (!this.dragPoint)
|
37
|
-
return this.checkDragPointAt(e.point);
|
38
|
-
this.doDrag(e.lngLat);
|
39
|
-
this.redraw();
|
40
|
-
e.preventDefault();
|
41
|
-
});
|
42
|
-
map.on('mousedown', (e) => {
|
43
|
-
if (this.isDragging)
|
44
|
-
return;
|
45
|
-
if (e.originalEvent.buttons % 2) {
|
46
|
-
this.checkDragPointAt(e.point);
|
47
|
-
if (this.dragPoint)
|
48
|
-
this.isDragging = true;
|
49
|
-
if (this.isDragging)
|
50
|
-
e.preventDefault();
|
51
|
-
}
|
52
|
-
});
|
53
|
-
map.on('mouseup', () => {
|
54
|
-
this.isDragging = false;
|
55
|
-
this.updateDragPoint(false);
|
56
|
-
});
|
57
|
-
}
|
58
|
-
updateDragPoint(dragPoint) {
|
59
|
-
if (this.dragPoint === dragPoint)
|
60
|
-
return;
|
61
|
-
this.dragPoint = dragPoint;
|
62
|
-
this.canvas.style.cursor = dragPoint ? 'move' : 'default';
|
63
|
-
}
|
64
|
-
getAsFeatureCollection() {
|
65
|
-
return {
|
66
|
-
type: 'FeatureCollection',
|
67
|
-
features: [getPoint(this.point)]
|
68
|
-
};
|
69
|
-
function getPoint(coordinates) {
|
70
|
-
return { type: 'Feature', geometry: { type: 'Point', coordinates }, properties: {} };
|
71
|
-
}
|
72
|
-
}
|
73
|
-
setGeometry(point) {
|
74
|
-
this.point = [point[0], point[1]];
|
75
|
-
this.redraw();
|
76
|
-
}
|
77
|
-
getBounds() {
|
78
|
-
return new LngLatBounds(this.point, this.point);
|
79
|
-
}
|
80
|
-
redraw() {
|
81
|
-
this.source?.setData(this.getAsFeatureCollection());
|
82
|
-
}
|
83
|
-
getAsPixel() {
|
84
|
-
const p = this.map.project([this.point[0], this.point[1]]);
|
85
|
-
return [p.x, p.y];
|
86
|
-
}
|
87
|
-
checkDragPointAt(point) {
|
88
|
-
const maxDistance = 5;
|
89
|
-
const { x, y } = point;
|
90
|
-
const [x0, y0] = this.getAsPixel();
|
91
|
-
const distance = Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2));
|
92
|
-
this.updateDragPoint(distance < maxDistance);
|
93
|
-
}
|
94
|
-
doDrag(lngLat) {
|
95
|
-
this.point = [Math.round(lngLat.lng * 1e5) / 1e5, Math.round(lngLat.lat * 1e5) / 1e5];
|
96
|
-
}
|
97
|
-
}
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import type { FillLayerSpecification, LineLayerSpecification, SymbolLayerSpecification } from 'maplibre-gl';
|
2
|
-
export type AbstractLayerStyle<T extends FillLayerSpecification | LineLayerSpecification | SymbolLayerSpecification> = {
|
3
|
-
paint: {} & T['paint'];
|
4
|
-
layout: {} & T['layout'];
|
5
|
-
};
|
6
|
-
export interface FillStyle {
|
7
|
-
color?: string;
|
8
|
-
fillColor?: string;
|
9
|
-
}
|
10
|
-
export declare function getFillStyle(style?: FillStyle): AbstractLayerStyle<FillLayerSpecification>;
|
11
|
-
export interface LineStyle {
|
12
|
-
color?: string;
|
13
|
-
lineColor?: string;
|
14
|
-
}
|
15
|
-
export declare function getLineStyle(style?: LineStyle): AbstractLayerStyle<LineLayerSpecification>;
|
16
|
-
export interface SymbolStyle {
|
17
|
-
color?: string;
|
18
|
-
}
|
19
|
-
export declare function getSymbolStyle(style?: SymbolStyle): AbstractLayerStyle<SymbolLayerSpecification>;
|
package/dist/utils/draw/style.js
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
import { Color } from '@versatiles/style';
|
2
|
-
export function getFillStyle(style) {
|
3
|
-
const result = {
|
4
|
-
layout: {},
|
5
|
-
paint: {}
|
6
|
-
};
|
7
|
-
if (style) {
|
8
|
-
if (style.fillColor) {
|
9
|
-
result.paint['fill-color'] = Color.parse(style.fillColor).asString();
|
10
|
-
}
|
11
|
-
else if (style.color) {
|
12
|
-
result.paint['fill-color'] = Color.parse(style.color).fade(0.8).asString();
|
13
|
-
}
|
14
|
-
}
|
15
|
-
return result;
|
16
|
-
}
|
17
|
-
export function getLineStyle(style) {
|
18
|
-
const result = {
|
19
|
-
layout: { 'line-cap': 'round', 'line-join': 'round' },
|
20
|
-
paint: {}
|
21
|
-
};
|
22
|
-
if (style) {
|
23
|
-
const color = style.lineColor ?? style.color;
|
24
|
-
if (color)
|
25
|
-
result.paint['line-color'] = Color.parse(color).asString();
|
26
|
-
}
|
27
|
-
return result;
|
28
|
-
}
|
29
|
-
export function getSymbolStyle(style) {
|
30
|
-
const result = {
|
31
|
-
layout: {},
|
32
|
-
paint: {}
|
33
|
-
};
|
34
|
-
result.paint['icon-color'] = Color.parse(style?.color ?? '#a00').asString();
|
35
|
-
result.paint['icon-halo-color'] = Color.parse('#fff').asString();
|
36
|
-
result.paint['icon-halo-width'] = 0.5;
|
37
|
-
result.paint['icon-halo-blur'] = 0;
|
38
|
-
result.layout['icon-image'] = 'basics:icon-embassy';
|
39
|
-
return result;
|
40
|
-
}
|