poe-svelte-ui-lib 1.37.0 → 1.37.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/dist/Map/Map.svelte
CHANGED
|
@@ -51,6 +51,9 @@
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
let devices: MapDevice[] = $state([])
|
|
54
|
+
/* Экземпляр MapLibre — для перелёта к первому устройству с фиксом (стартовый вид — весь мир) */
|
|
55
|
+
let mapInstance: any = $state()
|
|
56
|
+
let isCentered = false
|
|
54
57
|
let isCopied = $state(false)
|
|
55
58
|
let isDarkMode = $state(false)
|
|
56
59
|
let markerTimeout = $state(30_000)
|
|
@@ -84,11 +87,17 @@
|
|
|
84
87
|
$effect(() => {
|
|
85
88
|
if (data) {
|
|
86
89
|
/* (0, 0) — признак отсутствия реального GPS-фикса, в траекторию такие точки не добавляем */
|
|
87
|
-
const hasFix = data.NavLat !== 0 || data.NavLon !== 0
|
|
90
|
+
const hasFix = Number.isFinite(data.NavLat) && Number.isFinite(data.NavLon) && (data.NavLat !== 0 || data.NavLon !== 0)
|
|
91
|
+
if (hasFix && !isCentered && mapInstance) {
|
|
92
|
+
mapInstance.flyTo({ center: [data.NavLon, data.NavLat], zoom: 16 })
|
|
93
|
+
isCentered = true
|
|
94
|
+
}
|
|
88
95
|
const idx = devices.findIndex((d) => d.DevSN === data?.DevSN)
|
|
89
96
|
if (idx !== -1) {
|
|
90
|
-
/* Обновление
|
|
91
|
-
const
|
|
97
|
+
/* Обновление существующего; точку трека добавляем только при смене координат — курс и высота приходят чаще позиции */
|
|
98
|
+
const last = devices[idx].track.at(-1)
|
|
99
|
+
const moved = !last || last[0] !== data.NavLon || last[1] !== data.NavLat
|
|
100
|
+
const track = hasFix && moved ? [...devices[idx].track, [data.NavLon, data.NavLat] as [number, number]].slice(-trackLength) : devices[idx].track
|
|
92
101
|
devices[idx] = { ...devices[idx], ...data, track }
|
|
93
102
|
} else {
|
|
94
103
|
/* Новое устройство */
|
|
@@ -164,6 +173,7 @@
|
|
|
164
173
|
<h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
165
174
|
{/if}
|
|
166
175
|
<MapLibre
|
|
176
|
+
bind:map={mapInstance}
|
|
167
177
|
class={twMerge("h-[calc(100%-2rem)] min-h-50 overflow-hidden rounded-[14px] border border-(--hairline-color)", roleRingClass)}
|
|
168
178
|
style={isDarkMode ? "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json" : "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"}
|
|
169
179
|
zoom={1.5}
|
|
@@ -216,7 +226,7 @@
|
|
|
216
226
|
{/each}
|
|
217
227
|
{/if}
|
|
218
228
|
|
|
219
|
-
{#each devices as device}
|
|
229
|
+
{#each devices.filter((d) => Number.isFinite(d.NavLat) && Number.isFinite(d.NavLon)) as device (device.DevSN)}
|
|
220
230
|
<Marker lnglat={{ lng: device.NavLon, lat: device.NavLat }}>
|
|
221
231
|
{#snippet content()}
|
|
222
232
|
<div class="flex flex-col items-center justify-center leading-none">
|
|
@@ -261,19 +271,19 @@
|
|
|
261
271
|
<div class={`${twMerge("grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg bg-(--container-color) p-2 text-xs", roleBgClass)} ${roleBgPaint}`}>
|
|
262
272
|
<div>
|
|
263
273
|
<p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Lat / Lon</p>
|
|
264
|
-
<p class="font-medium">{device.NavLat.toFixed(5)}, {device.NavLon.toFixed(5)}</p>
|
|
274
|
+
<p class="font-medium">{(device.NavLat ?? 0).toFixed(5)}, {(device.NavLon ?? 0).toFixed(5)}</p>
|
|
265
275
|
</div>
|
|
266
276
|
<div>
|
|
267
277
|
<p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Alt</p>
|
|
268
|
-
<p class="font-medium">{device.NavAlt.toFixed(1)} m</p>
|
|
278
|
+
<p class="font-medium">{(device.NavAlt ?? 0).toFixed(1)} m</p>
|
|
269
279
|
</div>
|
|
270
280
|
<div>
|
|
271
281
|
<p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Heading</p>
|
|
272
|
-
<p class="font-medium">{device.NavHeading.toFixed(1)}°</p>
|
|
282
|
+
<p class="font-medium">{(device.NavHeading ?? 0).toFixed(1)}°</p>
|
|
273
283
|
</div>
|
|
274
284
|
<div>
|
|
275
285
|
<p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Satellites</p>
|
|
276
|
-
<p class="font-medium">{device.NavSatUse}</p>
|
|
286
|
+
<p class="font-medium">{device.NavSatUse ?? "—"}</p>
|
|
277
287
|
</div>
|
|
278
288
|
</div>
|
|
279
289
|
|
|
@@ -286,7 +296,7 @@
|
|
|
286
296
|
onclick={(e) => {
|
|
287
297
|
e.preventDefault()
|
|
288
298
|
navigator.clipboard.writeText(
|
|
289
|
-
`DevName: ${device.DevName}\nDevSN: ${device.DevSN}\nLat: ${device.NavLat.toFixed(
|
|
299
|
+
`DevName: ${device.DevName}\nDevSN: ${device.DevSN}\nLat: ${(device.NavLat ?? 0).toFixed(6)} | Lon: ${(device.NavLon ?? 0).toFixed(6)} | Alt: ${device.NavAlt}\nHeading: ${device.NavHeading} | Satellites: ${device.NavSatUse}`,
|
|
290
300
|
)
|
|
291
301
|
isCopied = true
|
|
292
302
|
setTimeout(() => (isCopied = false), 1000)
|
package/dist/Map/README.md
CHANGED
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
Карта - это UI-компонент, который позволяет отображать географическую информацию с маркерами устройств GPS. Компонент поддерживает различные настройки отображения, темы оформления, настройки таймаута маркеров и другие параметры через систему пропсов.
|
|
6
6
|
|
|
7
|
+
## Источник данных в DevCloud и WebApp
|
|
8
|
+
|
|
9
|
+
В конструкторе `id` карты — префикс группы полей, как у смарт-виджетов: `"MAV"` (или любое поле группы, например `"MAV.Lat"`) — GUIPreview собирает `data` из `MAV.Lat`, `MAV.Lon`, `MAV.Alt`, `MAV.Heading`, `MAV.Sat` выбранного модуля. Если под `id` лежит готовый объект `IDeviceGNSS` — старый формат, передаётся как есть.
|
|
10
|
+
|
|
11
|
+
Карта перелетает к первому устройству с валидным фиксом (зум 16); точка траектории добавляется только при смене координат — курс и высота могут обновляться чаще позиции. Маркер без конечных координат не рисуется.
|
|
12
|
+
|
|
7
13
|
## Пропсы
|
|
8
14
|
|
|
9
15
|
| Название | Тип | По умолчанию | Описание |
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
style?: any | string
|
|
10
10
|
zoom?: number
|
|
11
11
|
center?: any
|
|
12
|
+
map?: any
|
|
12
13
|
children?: Snippet<[any]>
|
|
13
14
|
}
|
|
14
15
|
|
|
@@ -17,11 +18,11 @@
|
|
|
17
18
|
style = { version: 8, sources: {}, layers: [] },
|
|
18
19
|
zoom = $bindable(undefined),
|
|
19
20
|
center = $bindable(undefined),
|
|
21
|
+
map = $bindable(undefined),
|
|
20
22
|
children,
|
|
21
23
|
}: Props = $props()
|
|
22
24
|
|
|
23
25
|
let container: HTMLElement | undefined = $state()
|
|
24
|
-
let map: any | undefined = $state()
|
|
25
26
|
let isLoading = $state(false)
|
|
26
27
|
let hasConnection = $state(true)
|
|
27
28
|
|
|
@@ -4,8 +4,9 @@ interface Props {
|
|
|
4
4
|
style?: any | string;
|
|
5
5
|
zoom?: number;
|
|
6
6
|
center?: any;
|
|
7
|
+
map?: any;
|
|
7
8
|
children?: Snippet<[any]>;
|
|
8
9
|
}
|
|
9
|
-
declare const MapLibre: import("svelte").Component<Props, {}, "center" | "zoom">;
|
|
10
|
+
declare const MapLibre: import("svelte").Component<Props, {}, "center" | "map" | "zoom">;
|
|
10
11
|
type MapLibre = ReturnType<typeof MapLibre>;
|
|
11
12
|
export default MapLibre;
|