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.
@@ -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 track = hasFix ? [...devices[idx].track, [data.NavLon, data.NavLat] as [number, number]].slice(-trackLength) : devices[idx].track
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(3)} | Lon: ${device.NavLon.toFixed(3)} | Alt: ${device.NavAlt}\nHeading: ${device.NavHeading} | Satellites: ${device.NavSatUse}`,
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)
@@ -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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-svelte-ui-lib",
3
- "version": "1.37.0",
3
+ "version": "1.37.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Oleg-Perevyshin/ElementsUI.git"