poe-svelte-ui-lib 1.37.0 → 1.37.2
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,8 @@
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
let devices: MapDevice[] = $state([])
|
|
54
|
+
/* Экземпляр MapLibre — для кнопки «Все борта»; сам вид карта не меняет, бортов может быть много */
|
|
55
|
+
let mapInstance: any = $state()
|
|
54
56
|
let isCopied = $state(false)
|
|
55
57
|
let isDarkMode = $state(false)
|
|
56
58
|
let markerTimeout = $state(30_000)
|
|
@@ -84,11 +86,13 @@
|
|
|
84
86
|
$effect(() => {
|
|
85
87
|
if (data) {
|
|
86
88
|
/* (0, 0) — признак отсутствия реального GPS-фикса, в траекторию такие точки не добавляем */
|
|
87
|
-
const hasFix = data.NavLat !== 0 || data.NavLon !== 0
|
|
89
|
+
const hasFix = Number.isFinite(data.NavLat) && Number.isFinite(data.NavLon) && (data.NavLat !== 0 || data.NavLon !== 0)
|
|
88
90
|
const idx = devices.findIndex((d) => d.DevSN === data?.DevSN)
|
|
89
91
|
if (idx !== -1) {
|
|
90
|
-
/* Обновление
|
|
91
|
-
const
|
|
92
|
+
/* Обновление существующего; точку трека добавляем только при смене координат — курс и высота приходят чаще позиции */
|
|
93
|
+
const last = devices[idx].track.at(-1)
|
|
94
|
+
const moved = !last || last[0] !== data.NavLon || last[1] !== data.NavLat
|
|
95
|
+
const track = hasFix && moved ? [...devices[idx].track, [data.NavLon, data.NavLat] as [number, number]].slice(-trackLength) : devices[idx].track
|
|
92
96
|
devices[idx] = { ...devices[idx], ...data, track }
|
|
93
97
|
} else {
|
|
94
98
|
/* Новое устройство */
|
|
@@ -153,6 +157,23 @@
|
|
|
153
157
|
{ label: "1 h", value: 3_600_000 },
|
|
154
158
|
]
|
|
155
159
|
|
|
160
|
+
/* Вписывает в экран все борта с фиксом, один борт — приближение к нему */
|
|
161
|
+
const hasFixPoint = (d: MapDevice) => Number.isFinite(d.NavLat) && Number.isFinite(d.NavLon) && (d.NavLat !== 0 || d.NavLon !== 0)
|
|
162
|
+
const fitAllDevices = () => {
|
|
163
|
+
const fixed = devices.filter(hasFixPoint)
|
|
164
|
+
if (!mapInstance || fixed.length === 0) return
|
|
165
|
+
if (fixed.length === 1) return mapInstance.flyTo({ center: [fixed[0].NavLon, fixed[0].NavLat], zoom: 16 })
|
|
166
|
+
const lons = fixed.map((d) => d.NavLon)
|
|
167
|
+
const lats = fixed.map((d) => d.NavLat)
|
|
168
|
+
mapInstance.fitBounds(
|
|
169
|
+
[
|
|
170
|
+
[Math.min(...lons), Math.min(...lats)],
|
|
171
|
+
[Math.max(...lons), Math.max(...lats)],
|
|
172
|
+
],
|
|
173
|
+
{ padding: 60, maxZoom: 16 },
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
156
177
|
const changeTimeout = (val: number) => {
|
|
157
178
|
markerTimeout = val
|
|
158
179
|
devices.forEach((device) => restartFreshTimer(device.DevSN))
|
|
@@ -164,6 +185,7 @@
|
|
|
164
185
|
<h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
165
186
|
{/if}
|
|
166
187
|
<MapLibre
|
|
188
|
+
bind:map={mapInstance}
|
|
167
189
|
class={twMerge("h-[calc(100%-2rem)] min-h-50 overflow-hidden rounded-[14px] border border-(--hairline-color)", roleRingClass)}
|
|
168
190
|
style={isDarkMode ? "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json" : "https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"}
|
|
169
191
|
zoom={1.5}
|
|
@@ -205,6 +227,14 @@
|
|
|
205
227
|
{/each}
|
|
206
228
|
</select>
|
|
207
229
|
</div>
|
|
230
|
+
|
|
231
|
+
<button
|
|
232
|
+
class="cursor-pointer rounded px-2 py-1 text-sm font-medium whitespace-nowrap disabled:cursor-default disabled:opacity-50"
|
|
233
|
+
disabled={!devices.some(hasFixPoint)}
|
|
234
|
+
onclick={fitAllDevices}
|
|
235
|
+
>
|
|
236
|
+
{$T("constructor.props.map.fitAll")}
|
|
237
|
+
</button>
|
|
208
238
|
</div>
|
|
209
239
|
</CustomControl>
|
|
210
240
|
|
|
@@ -216,7 +246,7 @@
|
|
|
216
246
|
{/each}
|
|
217
247
|
{/if}
|
|
218
248
|
|
|
219
|
-
{#each devices as device}
|
|
249
|
+
{#each devices.filter((d) => Number.isFinite(d.NavLat) && Number.isFinite(d.NavLon)) as device (device.DevSN)}
|
|
220
250
|
<Marker lnglat={{ lng: device.NavLon, lat: device.NavLat }}>
|
|
221
251
|
{#snippet content()}
|
|
222
252
|
<div class="flex flex-col items-center justify-center leading-none">
|
|
@@ -261,19 +291,19 @@
|
|
|
261
291
|
<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
292
|
<div>
|
|
263
293
|
<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>
|
|
294
|
+
<p class="font-medium">{(device.NavLat ?? 0).toFixed(5)}, {(device.NavLon ?? 0).toFixed(5)}</p>
|
|
265
295
|
</div>
|
|
266
296
|
<div>
|
|
267
297
|
<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>
|
|
298
|
+
<p class="font-medium">{(device.NavAlt ?? 0).toFixed(1)} m</p>
|
|
269
299
|
</div>
|
|
270
300
|
<div>
|
|
271
301
|
<p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Heading</p>
|
|
272
|
-
<p class="font-medium">{device.NavHeading.toFixed(1)}°</p>
|
|
302
|
+
<p class="font-medium">{(device.NavHeading ?? 0).toFixed(1)}°</p>
|
|
273
303
|
</div>
|
|
274
304
|
<div>
|
|
275
305
|
<p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Satellites</p>
|
|
276
|
-
<p class="font-medium">{device.NavSatUse}</p>
|
|
306
|
+
<p class="font-medium">{device.NavSatUse ?? "—"}</p>
|
|
277
307
|
</div>
|
|
278
308
|
</div>
|
|
279
309
|
|
|
@@ -286,7 +316,7 @@
|
|
|
286
316
|
onclick={(e) => {
|
|
287
317
|
e.preventDefault()
|
|
288
318
|
navigator.clipboard.writeText(
|
|
289
|
-
`DevName: ${device.DevName}\nDevSN: ${device.DevSN}\nLat: ${device.NavLat.toFixed(
|
|
319
|
+
`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
320
|
)
|
|
291
321
|
isCopied = true
|
|
292
322
|
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;
|
|
@@ -351,6 +351,7 @@ const translations = {
|
|
|
351
351
|
"constructor.props.multiselect": ["Мультивыбор", "Multi-select", "多选"],
|
|
352
352
|
"constructor.props.access": ["Доступ (не для владельца)", "Access (non-owner)", "访问权限(非所有者)"],
|
|
353
353
|
"constructor.props.map.timeout": ["Таймаут маркеров:", "Marker timeout:", "标记超时:"],
|
|
354
|
+
"constructor.props.map.fitAll": ["Все борта", "All vehicles", "全部设备"],
|
|
354
355
|
"constructor.props.map.track": ["Траектория", "Track", "轨迹"],
|
|
355
356
|
"constructor.props.map.trackLength": ["Точек в траектории:", "Points in track:", "轨迹点数:"],
|
|
356
357
|
"constructor.props.joystick.pitch.axe": ["Ocь ⮃", "Pitch axis ⮃", "俯仰轴 ⮃"],
|