poe-svelte-ui-lib 1.84.0 → 1.86.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/Graph/GraphProps.svelte +34 -33
- package/dist/Graph/README.md +2 -2
- package/dist/WidgetMap/README.md +94 -3
- package/dist/WidgetMap/WidgetMap.svelte +321 -189
- package/dist/WidgetMap/WidgetMap.svelte.d.ts +1 -1
- package/dist/WidgetMap/WidgetMapProps.svelte +63 -42
- package/dist/WidgetMap/mission/MapAgro.svelte +713 -0
- package/dist/WidgetMap/mission/MapAgro.svelte.d.ts +19 -0
- package/dist/WidgetMap/mission/MapRoute.svelte +444 -0
- package/dist/WidgetMap/mission/MapRoute.svelte.d.ts +19 -0
- package/dist/WidgetMap/mission/MissionIcon.svelte +5 -0
- package/dist/WidgetMap/mission/MissionIcon.svelte.d.ts +18 -0
- package/dist/WidgetMap/mission/MissionLayers.svelte +220 -0
- package/dist/WidgetMap/mission/MissionLayers.svelte.d.ts +20 -0
- package/dist/WidgetMap/mission/coverage.d.ts +58 -0
- package/dist/WidgetMap/mission/coverage.js +754 -0
- package/dist/WidgetMap/mission/plan.d.ts +22 -0
- package/dist/WidgetMap/mission/plan.js +78 -0
- package/dist/WidgetMap/mission/route.d.ts +33 -0
- package/dist/WidgetMap/mission/route.js +77 -0
- package/dist/WidgetPFD/README.md +1 -1
- package/dist/WidgetPFD/WidgetPFDProps.svelte +29 -24
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/locales/translations.js +246 -4
- package/dist/protocols/PROTOCOL.md +13 -0
- package/dist/types.d.ts +8 -0
- package/package.json +1 -1
|
@@ -27,8 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
{#snippet GraphIsTest()}
|
|
29
29
|
<UI.Switch
|
|
30
|
-
|
|
31
|
-
label={{ name: $T("constructor.props.istest") }}
|
|
30
|
+
label={{ name: $T("constructor.props.simulation") }}
|
|
32
31
|
value={component.properties.isTest ? 1 : 0}
|
|
33
32
|
options={[{ id: crypto.randomUUID(), value: 0, class: "" }]}
|
|
34
33
|
onChange={(value) => updateProperty("isTest", value === 1, component, onPropertyChange)}
|
|
@@ -44,35 +43,37 @@
|
|
|
44
43
|
/>
|
|
45
44
|
{/snippet}
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
<div class="flex flex-col gap-2">
|
|
47
|
+
<PropsGroup>
|
|
48
|
+
{@render GraphIsTest()}
|
|
49
|
+
</PropsGroup>
|
|
50
|
+
<!-- В режиме имитации остальные свойства не учитываются, поэтому вся панель бледная и недоступна -->
|
|
51
|
+
<div class={twMerge("flex flex-col gap-2 transition-opacity", component.properties.isTest && "opacity-40 grayscale")} inert={component.properties.isTest}>
|
|
52
|
+
{#if forConstructor}
|
|
53
|
+
<PropsGroup label={$T("constructor.props.group.general")}>
|
|
54
|
+
<CommonSnippets snippet="Access" {component} {onPropertyChange} />
|
|
55
|
+
<CommonSnippets snippet="Variable" {VARIABLE_OPTIONS} {component} {onPropertyChange} />
|
|
56
|
+
</PropsGroup>
|
|
57
|
+
<PropsGroup label={$T("constructor.props.group.appearance")}>
|
|
58
|
+
<CommonSnippets snippet="Label" {component} {onPropertyChange} />
|
|
59
|
+
<CommonSnippets snippet="LabelAlign" initialValue={initialAlign} {component} {onPropertyChange} />
|
|
60
|
+
</PropsGroup>
|
|
61
|
+
<PropsGroup label={$T("constructor.props.group.behavior")}>
|
|
62
|
+
{@render GraphSettings()}
|
|
63
|
+
</PropsGroup>
|
|
64
|
+
{:else}
|
|
65
|
+
<PropsGroup label={$T("constructor.props.group.general")}>
|
|
66
|
+
<CommonSnippets snippet="Identificator" {component} {onPropertyChange} />
|
|
67
|
+
<CommonSnippets snippet="Access" {component} {onPropertyChange} />
|
|
68
|
+
</PropsGroup>
|
|
69
|
+
<PropsGroup label={$T("constructor.props.group.appearance")}>
|
|
70
|
+
<CommonSnippets snippet="Label" {component} {onPropertyChange} />
|
|
71
|
+
<CommonSnippets snippet="LabelClass" initialValue={initialAlign} {component} {onPropertyChange} />
|
|
72
|
+
</PropsGroup>
|
|
73
|
+
<PropsGroup label={$T("constructor.props.group.behavior")}>
|
|
74
|
+
<CommonSnippets snippet="WrapperClass" {component} {onPropertyChange} />
|
|
75
|
+
{@render GraphSettings()}
|
|
76
|
+
</PropsGroup>
|
|
77
|
+
{/if}
|
|
61
78
|
</div>
|
|
62
|
-
|
|
63
|
-
<div class="flex flex-col gap-2">
|
|
64
|
-
<PropsGroup label={$T("constructor.props.group.general")}>
|
|
65
|
-
<CommonSnippets snippet="Identificator" {component} {onPropertyChange} />
|
|
66
|
-
<CommonSnippets snippet="Access" {component} {onPropertyChange} />
|
|
67
|
-
</PropsGroup>
|
|
68
|
-
<PropsGroup label={$T("constructor.props.group.appearance")}>
|
|
69
|
-
<CommonSnippets snippet="Label" {component} {onPropertyChange} />
|
|
70
|
-
<CommonSnippets snippet="LabelClass" initialValue={initialAlign} {component} {onPropertyChange} />
|
|
71
|
-
</PropsGroup>
|
|
72
|
-
<PropsGroup label={$T("constructor.props.group.behavior")}>
|
|
73
|
-
<CommonSnippets snippet="WrapperClass" {component} {onPropertyChange} />
|
|
74
|
-
{@render GraphIsTest()}
|
|
75
|
-
{@render GraphSettings()}
|
|
76
|
-
</PropsGroup>
|
|
77
|
-
</div>
|
|
78
|
-
{/if}
|
|
79
|
+
</div>
|
package/dist/Graph/README.md
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
**Статический.** Если передан непустой `historyData`, график рисует готовый ряд с отметками времени, например энергию за сутки по часам. Точки сортируются по времени сами. Новый массив `historyData` перерисовывает график целиком.
|
|
37
37
|
|
|
38
|
-
`isTest` включает случайные
|
|
38
|
+
`isTest` включает режим имитации: случайные данные, точка каждые 50 мс. Удобно, чтобы посмотреть график без устройства. Пока режим включён, данные устройства и `refreshRate` не учитываются. В конструкторе все остальные свойства становятся бледными и недоступными, пока имитацию не выключат.
|
|
39
39
|
|
|
40
40
|
## Пропсы
|
|
41
41
|
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
| `streamingData.data` | `{ name, value }[] \| null` | `[]` | Текущие значения линий для живого режима |
|
|
48
48
|
| `refreshRate` | `number` | `0` | Период добавления точек, мс. `0` — по изменению значений |
|
|
49
49
|
| `historyData` | `{ name, points: { value, timestamp }[] }[]` | `[]` | Готовый ряд для статического режима. `timestamp` в миллисекундах, как `Date.now()` |
|
|
50
|
-
| `isTest` | `boolean` | `false` |
|
|
50
|
+
| `isTest` | `boolean` | `false` | Режим имитации: случайные данные, точка каждые 50 мс |
|
|
51
51
|
|
|
52
52
|
Колбэков нет.
|
|
53
53
|
|
package/dist/WidgetMap/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# WidgetMap
|
|
2
2
|
|
|
3
|
-
Смарт-виджет «Карта»: где находятся объекты, куда они смотрят и как двигались. Каждый объект это одна группа полей устройства, на одной карте их может быть несколько. Карта на MapLibre.
|
|
3
|
+
Смарт-виджет «Карта»: где находятся объекты, куда они смотрят и как двигались. Каждый объект это одна группа полей устройства, на одной карте их может быть несколько. Ещё два режима строят миссию: «Маршрут» — обычный планировщик из точек с высотами, «Агро» — генератор миссии для агродрона. Аппараты из групп полей видны во всех режимах. Карта на MapLibre.
|
|
4
4
|
|
|
5
5
|
## Назначение
|
|
6
6
|
|
|
@@ -52,6 +52,7 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
|
|
|
52
52
|
- **Траектория.** Точка добавляется только при смене координат. Курс и высота могут меняться чаще.
|
|
53
53
|
- **«Показать все»** в шапке вписывает все видимые объекты в экран, один объект приближает. Сама карта вид не меняет, ведь объектов может быть много.
|
|
54
54
|
- **Клик по маркеру** открывает карточку: имя, группа, координаты, высота, курс, спутники, серийный номер. Кнопки «Копировать» (всё в буфер обмена) и «Скрыть» (до следующего обновления объекта).
|
|
55
|
+
- **Слежение.** Кнопка «Следить» в карточке залипает. Один отслеживаемый объект всегда в центре карты. Несколько вписываются в карту при включении слежения, дальше карта держит в центре их середину. Масштаб остаётся за оператором: карта сама отдаляется, только когда объект уходит за край. Под маркером отслеживаемого объекта точка, она видна и при закрытой карточке. Если объект пропал с карты, слежение за ним продолжится, когда он появится снова. «Скрыть» снимает слежение.
|
|
55
56
|
- **Шапка** показывает, сколько объектов на связи. Зелёный значит все, серый часть, красный ни одного.
|
|
56
57
|
- **Только 2D.** Наклонить карту нельзя. Правая кнопка мыши только поворачивает карту, компас под кнопками масштаба возвращает её на север.
|
|
57
58
|
- Карта светлая или тёмная по теме страницы и переключается вместе с ней.
|
|
@@ -61,7 +62,85 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
|
|
|
61
62
|
|
|
62
63
|
## Режим имитации
|
|
63
64
|
|
|
64
|
-
`isTest` включает
|
|
65
|
+
`isTest` включает имитацию шести аппаратов `SIM-1`-`SIM-6` без устройства. Они летают над одним районом Минска, в пределах пары километров, и обновляются раз в полсекунды. На связи всегда три аппарата. Через 40-100 секунд один из них пропадает, и его сразу сменяет тот, кто молчит дольше всех. Поэтому видно все состояния маркера: свежий, красный устаревший, скрытый и снова появившийся. При включении карта переходит к этому району. Пока режим включён, `value` и `groups` не учитываются. В конструкторе все остальные свойства становятся бледными и недоступными, пока имитацию не выключат.
|
|
66
|
+
|
|
67
|
+
## Режим «Маршрут»
|
|
68
|
+
|
|
69
|
+
`mode="route"` — обычный планировщик миссии: точки по порядку облёта, у каждой своя высота и скорость. Аппараты из `groups` рисуются поверх маршрута, как в режиме «Объекты».
|
|
70
|
+
|
|
71
|
+
1. **«Изменить точки»** включает правку. Клик по карте добавляет точку в конец маршрута. Новая точка берёт высоту и скорость предыдущей, первая получает 30 м и 8 м/с. Esc или двойной клик заканчивают правку.
|
|
72
|
+
2. В режиме правки точки можно перетаскивать. Потяните за середину отрезка, чтобы вставить точку между соседними. Правый клик удаляет точку. Без правки на карте видны только номера точек, их не сдвинуть случайно. Точку взлёта `H` можно перетаскивать всегда.
|
|
73
|
+
3. Блок **«Итог»**: сверху расчёт (число точек, длина пути, время, наибольшая высота), ниже список точек с высотой, скоростью, расстоянием от предыдущей точки и удалением; порядок меняется перетаскиванием строки за ручку, как в списках панелей свойств, под ним флажок возврата с посадкой (RTL). Клик по номеру показывает точку на карте.
|
|
74
|
+
|
|
75
|
+
Миссия в формате QGC WPL 110: точка дома, `NAV_TAKEOFF` на высоту первой точки, точки маршрута со своими высотами, `DO_CHANGE_SPEED` перед точкой, где меняется скорость, в конце `RTL`, если включён возврат. Высоты отсчитываются от точки взлёта. Время: каждый отрезок со скоростью своей точки плюс набор высоты и посадка около 2.5 м/с.
|
|
76
|
+
|
|
77
|
+
План хранит владелец карты через `route` и `onRouteChange`. Без `route` показывается демо-облёт вокруг поля под Минском.
|
|
78
|
+
|
|
79
|
+
| Поле `IRoutePlan` | Описание |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `start` | Точка взлёта, `[lng, lat]` |
|
|
82
|
+
| `points` | Точки `{ point: [lng, lat], alt, speed }`: высота в метрах над точкой взлёта, скорость на пути к точке в м/с |
|
|
83
|
+
| `returnHome` | Вернуться и сесть в конце (RTL) |
|
|
84
|
+
|
|
85
|
+
## Режим «Агро»
|
|
86
|
+
|
|
87
|
+
`mode="agro"` превращает карту в генератор миссии для агродрона. Оператор обводит на карте одно или несколько полей и запретные зоны, задаёт угол проходов и ширину захвата. Карта строит траекторию, которая покрывает все поля, обходит зоны и выключает распылитель на разворотах и переходах. Готовую миссию можно скачать, скопировать или отправить на борт в формате QGC WPL 110 для автопилота ArduPilot.
|
|
88
|
+
|
|
89
|
+
Аппараты из `groups` рисуются поверх миссии так же, как в режиме «Объекты»: маркер, карточка по клику и траектория, если она включена. План хранит владелец карты через `plan` и `onPlanChange`, миссия уходит наружу через `onSend`. Без `plan` показываются два демо-поля под Минском: в большом три запретные зоны, в малом вырез и дерево.
|
|
90
|
+
|
|
91
|
+
### Как пользоваться
|
|
92
|
+
|
|
93
|
+
1. **«Нарисовать поле»**: кликами по карте обведите участок. Контур замыкается кликом по первой точке, двойным кликом, Enter или кнопкой «Замкнуть». Backspace убирает последнюю точку, Esc сбрасывает начатый контур. Когда поле есть, кнопка называется **«Поля»**: в этом режиме клики по карте обводят ещё одно поле.
|
|
94
|
+
2. **«Запретные зоны»**: обведите места, где нельзя лететь и распылять: деревья, опоры ЛЭП, постройки, водоёмы. Зон может быть сколько угодно.
|
|
95
|
+
3. **Точка взлёта** (синяя) видна всегда, её можно перетащить в любой момент.
|
|
96
|
+
4. В блоке **«Маршрут и внесение»** задайте ширину захвата, отступ от границ, высоту, скорость, норму внесения и объём бака. У каждого поля свой угол проходов: новое поле сразу получает лучший угол, «Подобрать» пересчитывает углы всех полей, а ползунок «Угол для всех полей» ставит всем один угол, например чтобы проходы шли вдоль рядов посадки. Угол отдельного поля правится в его строке в блоке «Итог».
|
|
97
|
+
5. Блок **«Итог»** показывает контуры, площадь к обработке, покрытие, длину пути, время, расход раствора и число дозаправок.
|
|
98
|
+
6. **«Скачать»**, **«Копировать»** или **«Отправить»** миссию.
|
|
99
|
+
|
|
100
|
+
Точки контуров видны и перетаскиваются, только пока нажата кнопка «Поля» или «Запретные зоны». Потяните за середину стороны, чтобы добавить точку. Правый клик удаляет точку. Поля и зоны удаляются крестиком в блоке «Итог». Режим выключается той же кнопкой, кнопкой «Готово» или Esc.
|
|
101
|
+
|
|
102
|
+
### Как строится траектория
|
|
103
|
+
|
|
104
|
+
1. Поле переводится в метры и поворачивается так, чтобы проходы шли вдоль оси.
|
|
105
|
+
2. Для каждого прохода считаются свободные отрезки: внутри поля и вне зон, с отступом по всей ширине полосы.
|
|
106
|
+
3. Отрезки собираются в участки: подряд идущие проходы, которые соединяются один к одному. Каждый участок облетается змейкой.
|
|
107
|
+
4. Порядок участков и сторона входа выбираются точным перебором, если участков не больше 10. Если больше, используется жадный выбор с улучшением 2-opt.
|
|
108
|
+
5. Переходы между участками идут по кратчайшему пути в обход зон с соблюдением отступа.
|
|
109
|
+
6. Несколько полей облетаются по очереди: каждый раз ближайшее к текущему положению. Путь к первому полю, переходы между полями и возврат домой строятся по открытой местности в обход всех зон.
|
|
110
|
+
|
|
111
|
+
Расчёт занимает 15-30 мс, траектория пересчитывается на каждое изменение.
|
|
112
|
+
|
|
113
|
+
### Миссия
|
|
114
|
+
|
|
115
|
+
- точка дома (точка взлёта или первая точка поля);
|
|
116
|
+
- `DO_CHANGE_SPEED` с заданной скоростью;
|
|
117
|
+
- точки маршрута на заданной высоте над точкой взлёта;
|
|
118
|
+
- команды распыления: включение в начале прохода, выключение в конце и перед вылетом.
|
|
119
|
+
|
|
120
|
+
| Режим распыления | Команда | Что нужно на борту |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| Распылитель ArduPilot | `DO_SPRAYER` (216) | `SPRAY_ENABLE=1`, выход насоса `SERVOx_FUNCTION=22` |
|
|
123
|
+
| Насос на выходе | `DO_SET_SERVO` (183) | канал и ШИМ вкл./выкл. задаются на карте |
|
|
124
|
+
| Без команд | нет | распылитель работает и на разворотах, участки обработаются дважды |
|
|
125
|
+
|
|
126
|
+
Кнопка «Отправить» неактивна, если не передан `onSend`. Во время отправки на ней «Отправка…», после успеха «Отправлено», при ошибке она краснеет. Время полёта считается по скорости плюс около 4 с на разворот. Покрытие — доля поля без зон, которая попадает под распыление: остальное съедают отступы.
|
|
127
|
+
|
|
128
|
+
### План миссии (IMissionPlan)
|
|
129
|
+
|
|
130
|
+
| Поле | Описание |
|
|
131
|
+
|---|---|
|
|
132
|
+
| `fields` | Поля `{ contour: [lng, lat][], angle }`: контур и угол проходов, ° от севера по часовой |
|
|
133
|
+
| `holes` | Запретные зоны, массив контуров; зона относится к полю, внутри которого лежит её центр |
|
|
134
|
+
| `start` | Точка взлёта, `[lng, lat]` |
|
|
135
|
+
| `spacing` | Ширина захвата, м |
|
|
136
|
+
| `margin` | Отступ от границ и зон, м |
|
|
137
|
+
| `alt`, `speed` | Высота, м, и скорость, м/с |
|
|
138
|
+
| `returnHome` | Вернуться к точке взлёта в конце |
|
|
139
|
+
| `rate`, `tank` | Норма внесения, л/га, и объём бака, л |
|
|
140
|
+
| `sprayControl` | `sprayer`, `servo` или `none` |
|
|
141
|
+
| `servoChannel`, `servoOn`, `servoOff` | Канал и ШИМ насоса для режима `servo` |
|
|
142
|
+
|
|
143
|
+
Расчёт доступен и без карты: `planFields` (несколько полей), `planCoverage` (одно поле), `bestFieldAngle`, `toWaypointsFile` экспортируются из библиотеки.
|
|
65
144
|
|
|
66
145
|
## Пропсы
|
|
67
146
|
|
|
@@ -76,6 +155,12 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
|
|
|
76
155
|
| `trackLength` | `number` | `1000` | Точек траектории. Можно связать через `bind:` |
|
|
77
156
|
| `markerTimeout` | `number` | `30000` | Таймаут маркера, мс. Можно связать через `bind:` |
|
|
78
157
|
| `isTest` | `boolean` | `false` | Режим имитации |
|
|
158
|
+
| `mode` | `"objects" \| "route" \| "agro"` | `"objects"` | Карта объектов, планировщик маршрута или генератор миссии для агродрона |
|
|
159
|
+
| `plan` | `IMissionPlan` | `DEFAULT_MISSION_PLAN` | План миссии в режиме «Агро». Можно связать через `bind:` |
|
|
160
|
+
| `onPlanChange` | `(plan) => void` | | Вызывается при каждом изменении плана |
|
|
161
|
+
| `route` | `IRoutePlan` | `DEFAULT_ROUTE_PLAN` | Маршрут в режиме «Маршрут». Можно связать через `bind:` |
|
|
162
|
+
| `onRouteChange` | `(route) => void` | | Вызывается при каждом изменении маршрута |
|
|
163
|
+
| `onSend` | `(mission, plan) => void \| Promise` | | Отправка миссии, `mission` — текст QGC WPL 110 |
|
|
79
164
|
| `label.name` | `string` | | Заголовок. Пусто — «Карта» на языке пользователя |
|
|
80
165
|
| `wrapperClass` | `string` | `""` | Классы обёртки |
|
|
81
166
|
| `componentClass` | `string` | `""` | Мастер-цвет `bg-*` шапки |
|
|
@@ -86,14 +171,20 @@ Telemetry_SendObject(g_telemetry_stream, g_mcfg.DevSN, "Data", dev, sizeof(dev)
|
|
|
86
171
|
|
|
87
172
|
```svelte
|
|
88
173
|
<UI.WidgetMap groups={["MAV", "GNSS"]} value={{ MAV: mav, GNSS: gnss }} height={400} trackEnabled />
|
|
174
|
+
|
|
175
|
+
<UI.WidgetMap mode="route" bind:route groups={["MAV"]} value={{ MAV: mav }} onSend={(mission) => sendToDevice(mission)} />
|
|
176
|
+
|
|
177
|
+
<UI.WidgetMap mode="agro" bind:plan groups={["MAV"]} value={{ MAV: mav }} onSend={(mission) => sendToDevice(mission)} />
|
|
89
178
|
```
|
|
90
179
|
|
|
91
180
|
В DevCloud и WebApp `value` собирает `GUIPreview`: для каждой группы читает переменные `<ModSN>|<группа>.<ключ>`.
|
|
92
181
|
|
|
93
182
|
## Панель свойств (WidgetMapProps.svelte)
|
|
94
183
|
|
|
95
|
-
В конструкторе задают заголовок, группы через пробел, мастер-цвет, высоту карты (S, M, L, XL: 250, 400, 600, 800 пикселей), иконку маркера и начальные значения траектории.
|
|
184
|
+
В конструкторе задают режим («Объекты», «Маршрут» или «Агро»), заголовок, группы через пробел, мастер-цвет, высоту карты (S, M, L, XL: 250, 400, 600, 800 пикселей), иконку маркера и начальные значения траектории. Группы, иконка маркера, траектория и имитация действуют во всех режимах.
|
|
96
185
|
|
|
97
186
|
## Внутреннее устройство
|
|
98
187
|
|
|
99
188
|
В папке `mapWrapper/` лежат тонкие Svelte-обёртки над MapLibre GL: `MapLibre`, `Marker`, `Popup`, `Line`, элементы управления и `CustomControl` для своих кнопок поверх карты.
|
|
189
|
+
|
|
190
|
+
В папке `mission/` лежат режимы построения миссии: `MapRoute.svelte` и `route.ts` (режим «Маршрут»), `MapAgro.svelte` (интерфейс режима «Агро»), `coverage.ts` (расчёт траектории и выгрузка миссии), `plan.ts` (тип плана и план по умолчанию), `MissionLayers.svelte` (слои карты и перетаскивание точек).
|