mahal_map 2.0.0 → 2.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 +231 -38
- package/dist/index.d.mts +105 -9
- package/dist/index.d.ts +105 -9
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8 -3
- package/dist/index.mjs.map +1 -1
- package/dist/mahal_map.sdk.js +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install mahal_map maplibre-gl @grammaps/maps3d-web
|
|
|
12
12
|
|
|
13
13
|
Обе зависимости — `peerDependencies`, в бандл `mahal_map` они не входят. Библиотека их не импортирует: MapLibre и `Maps3D` приходят снаружи, аргументами `create()` либо через `window`.
|
|
14
14
|
|
|
15
|
-
- `maplibre-gl` (
|
|
15
|
+
- `maplibre-gl` (`^6.10.0`) — обязателен всегда.
|
|
16
16
|
- `@grammaps/maps3d-web` (>=0.5.0) — даёт стили, тайлы, объём, пробки, рельеф, планы этажей, клик по объектам. Помечен `optional`: без него карта поднимется на запасном векторном стиле, но 3D и слоёв платформы на ней не будет.
|
|
17
17
|
|
|
18
18
|
MapLibre можно не класть в свою сборку вовсе — платформа отдаёт согласованную версию вместе с веб-воркером:
|
|
@@ -21,6 +21,49 @@ MapLibre можно не класть в свою сборку вовсе — п
|
|
|
21
21
|
const maplibregl = await Maps3D.maplibre({ base: "https://navi.gram.tj" });
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
## Веб-воркер MapLibre
|
|
25
|
+
|
|
26
|
+
MapLibre разбирает векторные тайлы в веб-воркере и ищет его файл рядом со своим модулем. Сборщик складывает библиотеку в общий бандл, рядом файла не оказывается, и вместо скрипта сервер отдаёт `index.html`.
|
|
27
|
+
|
|
28
|
+
Симптом обманчивый: **карта показывает пустой фон, ошибок про карту нет**. В консоли лежит только `Uncaught SyntaxError: Unexpected token '<'` — ни слова ни про MapLibre, ни про воркер, ни про тайлы.
|
|
29
|
+
|
|
30
|
+
`mahal_map` это распознаёт сам. Если через 8 с после создания карты не разобран ни один векторный тайл, в консоль уходит предупреждение с причиной и обоими решениями:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
[MahalMap SDK] Карта пуста: ни один векторный тайл не разобран — похоже, не запустился веб-воркер MapLibre.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Проверка молчит на растровых стилях (им воркер не нужен), в фоновой вкладке (там MapLibre приостановлен) и когда фичи отрисованы. Отключается через `workerCheck: false`, своя задержка — `workerCheck: 12000`.
|
|
37
|
+
|
|
38
|
+
### Решение 1 — взять библиотеку у платформы
|
|
39
|
+
|
|
40
|
+
Версия согласована с Maps3D, веб-воркер приезжает вместе с ней, настраивать нечего:
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
const maplibregl = await Maps3D.maplibre({ base: "https://navi.gram.tj" });
|
|
44
|
+
|
|
45
|
+
const map = MahalMap.create({ container: "map" }, maplibregl, Maps3D);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Решение 2 — оставить свою сборку
|
|
49
|
+
|
|
50
|
+
Тогда адрес воркера нужно свести с реальным файлом — и в разработке, и в собранной версии:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
// vite.config.ts — чтобы адрес воркера совпал с файлом во время разработки
|
|
54
|
+
export default defineConfig({ optimizeDeps: { exclude: ["maplibre-gl"] } });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
// в приложении — чтобы адрес совпал и в собранной версии
|
|
59
|
+
import * as maplibregl from "maplibre-gl";
|
|
60
|
+
import "maplibre-gl/dist/maplibre-gl.css";
|
|
61
|
+
|
|
62
|
+
maplibregl.setWorkerUrl("/maplibre-gl-worker.mjs"); // файл скопирован в public/ из maplibre-gl/dist
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
> `import * as maplibregl` — не случайность: в MapLibre 6 default-экспорта нет, `import maplibregl from "maplibre-gl"` даёт `undefined`.
|
|
66
|
+
|
|
24
67
|
## Миграция с 1.x на 2.0
|
|
25
68
|
|
|
26
69
|
Собственных URL стилей у `mahal_map` больше нет — их целиком отдаёт `@grammaps/maps3d-web`.
|
|
@@ -58,7 +101,7 @@ const maplibregl = await Maps3D.maplibre({ base: "https://navi.gram.tj" });
|
|
|
58
101
|
## Быстрый старт через NPM
|
|
59
102
|
|
|
60
103
|
```ts
|
|
61
|
-
import maplibregl from "maplibre-gl";
|
|
104
|
+
import * as maplibregl from "maplibre-gl";
|
|
62
105
|
import "maplibre-gl/dist/maplibre-gl.css";
|
|
63
106
|
import { Maps3D } from "@grammaps/maps3d-web";
|
|
64
107
|
import { MahalMap, keyUtils } from "mahal_map";
|
|
@@ -87,28 +130,30 @@ const map = MahalMap.create(
|
|
|
87
130
|
|
|
88
131
|
## Быстрый старт через Browser SDK
|
|
89
132
|
|
|
90
|
-
|
|
133
|
+
Для browser SDK параметр `apikey` обязателен: без него карта не инициализируется.
|
|
134
|
+
|
|
135
|
+
**MapLibre 6 поставляется только как ESM** — классической сборки `dist/maplibre-gl.js` для `<script src>` в ней больше нет. Поэтому библиотеку карты подключают модульным скриптом и передают в `create()` вторым аргументом:
|
|
91
136
|
|
|
92
137
|
```html
|
|
93
138
|
<link
|
|
94
139
|
rel="stylesheet"
|
|
95
|
-
href="https://
|
|
140
|
+
href="https://cdn.jsdelivr.net/npm/maplibre-gl@6.10.0/dist/maplibre-gl.css"
|
|
96
141
|
/>
|
|
97
|
-
<script src="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.js"></script>
|
|
98
142
|
<script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_MAP_API_KEY"></script>
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
После этого глобальный объект `MahalMap` доступен в `window`:
|
|
102
143
|
|
|
103
|
-
```html
|
|
104
144
|
<div id="map" style="width: 100%; height: 500px"></div>
|
|
105
145
|
|
|
106
|
-
<script>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
146
|
+
<script type="module">
|
|
147
|
+
import * as maplibregl from "https://cdn.jsdelivr.net/npm/maplibre-gl@6.10.0/+esm";
|
|
148
|
+
|
|
149
|
+
const map = MahalMap.create(
|
|
150
|
+
{
|
|
151
|
+
container: "map",
|
|
152
|
+
center: [69.624024, 40.279687],
|
|
153
|
+
zoom: 12,
|
|
154
|
+
},
|
|
155
|
+
maplibregl,
|
|
156
|
+
);
|
|
112
157
|
</script>
|
|
113
158
|
```
|
|
114
159
|
|
|
@@ -131,7 +176,7 @@ const map = MahalMap.create(
|
|
|
131
176
|
<script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_MAP_API_KEY&lang=ru"></script>
|
|
132
177
|
```
|
|
133
178
|
|
|
134
|
-
|
|
179
|
+
`lang` влияет на поиск и роутинг, но не на стиль: подписи на карте приходят из самого стиля платформы.
|
|
135
180
|
|
|
136
181
|
## Параметры создания карты
|
|
137
182
|
|
|
@@ -156,6 +201,7 @@ interface IMahalMapOptions {
|
|
|
156
201
|
family?: "default" | "navigator" | "mobile";
|
|
157
202
|
preset?: Maps3DThemeName | string;
|
|
158
203
|
antialias?: boolean;
|
|
204
|
+
workerCheck?: boolean | number;
|
|
159
205
|
maps3d?: Omit<IMaps3DLayerOptions, "apiKey" | "base">;
|
|
160
206
|
}
|
|
161
207
|
```
|
|
@@ -175,6 +221,7 @@ interface IMahalMapOptions {
|
|
|
175
221
|
| `family` | `"default" \| "navigator" \| "mobile"` | Семейство стилей. `theme` выбирает внутри него: `default` → `light`/`dark`, `navigator` → `navigator-light`/`navigator-dark`, `mobile` → `mobile-*`. |
|
|
176
222
|
| `preset` | `Maps3DThemeName \| string` | Явное имя темы платформы или полный URL стиля вместо пары `family` + `theme`. Задан — стиль зафиксирован. |
|
|
177
223
|
| `antialias` | `boolean` | Сглаживание сцены. По умолчанию `true` при включённом 3D: без него тонкая геометрия (перила, мачты, ряды сидений) на отдалении рассыпается в рябь. |
|
|
224
|
+
| `workerCheck` | `boolean \| number` | Диагностика неработающего веб-воркера MapLibre через 8 с после создания карты. `false` отключает, число задаёт свою задержку в мс. См. [Веб-воркер MapLibre](#веб-воркер-maplibre). |
|
|
178
225
|
| `maps3d` | `object` | Опции Maps3D: `buildings`, `traffic`, `indoor`, `closures`, `places`, `minZoom`, `lodBias`, `memoryBudget`, `maskReplaced`, `typeReplacements`. |
|
|
179
226
|
|
|
180
227
|
### Стили и темы
|
|
@@ -234,38 +281,133 @@ map.setStyle("light"); // → navigator-light
|
|
|
234
281
|
|
|
235
282
|
### Реестр слоёв
|
|
236
283
|
|
|
237
|
-
Единая дверь ко всем слоям платформы.
|
|
284
|
+
Единая дверь ко всем слоям платформы. Идентификаторы и параметры типизированы: опечатка в имени слоя или в значении параметра — ошибка компиляции, а не тихий `false` в рантайме.
|
|
238
285
|
|
|
239
286
|
```ts
|
|
240
287
|
map.setLayer("terrain", true, { mode: "on" });
|
|
241
288
|
map.setLayer("traffic", true);
|
|
242
289
|
map.setLayer("indoor", true, { level: 2 });
|
|
290
|
+
map.setLayer("buildings", true, { detail: "facade" });
|
|
243
291
|
|
|
292
|
+
map.getLayerState("terrain"); // снимок одного слоя или null
|
|
293
|
+
map.getLayers(); // снимок всех — по нему рисуется панель слоёв
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
| Слой | Параметры | По умолчанию |
|
|
297
|
+
| ------------------ | ------------------------------------------ | ------------ |
|
|
298
|
+
| `buildings` | `detail: footprint\|volume\|roofs\|facade` | включён |
|
|
299
|
+
| `objects` | — | включён |
|
|
300
|
+
| `traffic` | — | выключен |
|
|
301
|
+
| `trafficRaster` | — | выключен |
|
|
302
|
+
| `parking` | `highlight`, `paid`, `free`, `unknown` | включён |
|
|
303
|
+
| `fuel`, `charging` | — | включены |
|
|
304
|
+
| `closures` | — | выключен |
|
|
305
|
+
| `indoor` | `level` | выключен |
|
|
306
|
+
| `terrain` | `mode: auto\|on\|off` | `auto` |
|
|
307
|
+
|
|
308
|
+
Стартовое состояние можно задать сразу при создании карты — тогда первый кадр уже правильный, без моргания:
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
MahalMap.create(
|
|
312
|
+
{ container: "map", maps3d: { traffic: true, closures: true } },
|
|
313
|
+
maplibregl,
|
|
314
|
+
Maps3D,
|
|
315
|
+
);
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Полный список — в разделе [Опции `maps3d`](#опции-maps3d-расширенные).
|
|
319
|
+
|
|
320
|
+
#### `wanted`, `available`, `active` — три разных вопроса
|
|
321
|
+
|
|
322
|
+
Поля независимы, и это главная ловушка реестра:
|
|
323
|
+
|
|
324
|
+
| Поле | Вопрос |
|
|
325
|
+
| ----------- | --------------------------------------- |
|
|
326
|
+
| `wanted` | чего хочет приложение |
|
|
327
|
+
| `available` | что позволяют стиль и данные |
|
|
328
|
+
| `active` | что нарисовано прямо сейчас |
|
|
329
|
+
|
|
330
|
+
Слой может быть включён и при этом не нарисован — и это не ошибка:
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
map.setLayer("terrain", true); // wanted: true
|
|
334
|
+
const state = map.getLayerState("terrain");
|
|
335
|
+
|
|
336
|
+
state?.available; // false — в стиле нет ключа maps3d:terrain
|
|
337
|
+
state?.active; // false — либо режим auto, а зум слишком близкий
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Поэтому галочку в интерфейсе рисуют по `wanted`, а пометку «сейчас не видно» — по `active`. Проверять сразу после `setLayer()` бесполезно: тайлы ещё едут. Правильный способ — подписка.
|
|
341
|
+
|
|
342
|
+
#### Панель слоёв: подписка и отписка
|
|
343
|
+
|
|
344
|
+
`onLayers()` возвращает функцию отписки. Звать её обязательно — иначе колбэк переживёт компонент и будет дёргать размонтированное состояние:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
244
347
|
const unsubscribe = map.onLayers((state) => {
|
|
245
348
|
console.log(state.id, state.wanted, state.available, state.active);
|
|
246
349
|
});
|
|
247
350
|
|
|
248
|
-
|
|
249
|
-
|
|
351
|
+
// при размонтировании компонента
|
|
352
|
+
unsubscribe();
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
`map.destroy()` снимает слой Maps3D целиком, так что после него подписка всё равно мертва — но до него отписываться нужно самим.
|
|
356
|
+
|
|
357
|
+
#### Парковки, заправки, зарядки
|
|
358
|
+
|
|
359
|
+
`Maps3D` рисует их сам, забирая эти классы у POI-слоёв стиля. Поэтому выключение слоя убирает объекты с карты полностью, а не оставляет значок стиля.
|
|
360
|
+
|
|
361
|
+
Подтип парковки берётся из атрибута `fee`:
|
|
362
|
+
|
|
363
|
+
| Параметр | Условие |
|
|
364
|
+
| ----------- | --------------- |
|
|
365
|
+
| `paid` | `fee=yes` |
|
|
366
|
+
| `free` | `fee=no` |
|
|
367
|
+
| `unknown` | атрибута нет |
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
// только платные, с подсветкой
|
|
371
|
+
map.setLayer("parking", true, { paid: true, free: false, unknown: false, highlight: true });
|
|
250
372
|
```
|
|
251
373
|
|
|
252
|
-
|
|
253
|
-
| ------------------ | ---------------------------------------- | ------------ |
|
|
254
|
-
| `buildings` | `detail: footprint\|volume\|roofs\|facade` | включён |
|
|
255
|
-
| `objects` | — | включён |
|
|
256
|
-
| `traffic` | — | выключен |
|
|
257
|
-
| `trafficRaster` | — | выключен |
|
|
258
|
-
| `parking` | `highlight`, `paid`, `free`, `unknown` | включён |
|
|
259
|
-
| `fuel`, `charging` | — | включены |
|
|
260
|
-
| `closures` | — | выключен |
|
|
261
|
-
| `indoor` | `level` | выключен |
|
|
262
|
-
| `terrain` | `mode: auto\|on\|off` | `auto` |
|
|
374
|
+
#### Рельеф
|
|
263
375
|
|
|
264
|
-
|
|
376
|
+
`auto` показывает рельеф на обзорных зумах, `on` — всегда. Режим `on` заметно дороже по трафику и времени кадра, чем `auto`.
|
|
265
377
|
|
|
266
|
-
|
|
378
|
+
```ts
|
|
379
|
+
map.setLayer("terrain", true, { mode: "auto" });
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
#### Планы этажей
|
|
383
|
+
|
|
384
|
+
Слой включается реестром, но одного этого мало — без переключения этажа он бесполезен:
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
map.setLayer("indoor", true);
|
|
388
|
+
|
|
389
|
+
const levels = map.getIndoorLevels(); // этажи в текущем виде карты, [] — данных нет
|
|
390
|
+
map.setIndoorLevel(1); // нумерация OSM: 0 — первый наземный
|
|
391
|
+
map.refreshIndoor(); // перечитать после правки картографом
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
После поиска показать найденный объект вместе с его этажом:
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
// level приходит у объектов внутри зданий; без него откроется первый этаж
|
|
398
|
+
// и метка окажется в чужом зале
|
|
399
|
+
map.showPlace(68.787, 38.573, place.level, 18);
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
#### Слой, которого нет в списке
|
|
267
403
|
|
|
268
|
-
`setLayer()`
|
|
404
|
+
`setLayer()` принимает только известные идентификаторы. Если в новой сборке Maps3D появится слой, которого ещё нет в типах, — он доступен напрямую через слой, там `id` остаётся строкой:
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
map.getMaps3DLayer()?.setLayer?.("новый-слой", true);
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`setLayer()` возвращает `false`, если такого слоя в подключённой сборке Maps3D нет или Maps3D не передан вовсе. После полной смены стиля волю клиента возвращает `map.refreshLayers()` — при `setStyle()` библиотека вызывает его сама.
|
|
269
411
|
|
|
270
412
|
### 3D-здания
|
|
271
413
|
|
|
@@ -367,15 +509,16 @@ layer?.buildings?.setWindowStyle(4);
|
|
|
367
509
|
|
|
368
510
|
### Подключение и выключение 3D-слоя: полный пример (Vue 3)
|
|
369
511
|
|
|
370
|
-
Кнопка-переключатель «3D ⇄ контуры»,
|
|
512
|
+
Кнопка-переключатель «3D ⇄ контуры», панель слоёв на живом состоянии реестра и корректная очистка при размонтировании. Слой `Maps3D` поднимает и цепляет сама библиотека — вручную `Maps3D.enhance(...)`, `transformRequest` и `attach()` писать не нужно.
|
|
371
513
|
|
|
372
514
|
```vue
|
|
373
515
|
<script setup lang="ts">
|
|
374
516
|
import { computed, onBeforeUnmount, onMounted, ref, shallowRef } from "vue";
|
|
375
|
-
import maplibregl from "maplibre-gl";
|
|
517
|
+
import * as maplibregl from "maplibre-gl";
|
|
376
518
|
import "maplibre-gl/dist/maplibre-gl.css";
|
|
377
519
|
import { Maps3D } from "@grammaps/maps3d-web";
|
|
378
520
|
import { MahalMap, keyUtils } from "mahal_map";
|
|
521
|
+
import type { IMaps3DLayerState, Maps3DLayerId } from "mahal_map";
|
|
379
522
|
|
|
380
523
|
const API_KEY = "YOUR_MAP_API_KEY";
|
|
381
524
|
|
|
@@ -383,6 +526,15 @@ const mahalMap = shallowRef<MahalMap | null>(null);
|
|
|
383
526
|
const is3dEnabled = ref(true);
|
|
384
527
|
const isLayerReady = ref(false);
|
|
385
528
|
|
|
529
|
+
// Панель слоёв рисуется по живому снимку реестра
|
|
530
|
+
const layers = ref<IMaps3DLayerState[]>([]);
|
|
531
|
+
let unsubscribeLayers: (() => void) | null = null;
|
|
532
|
+
|
|
533
|
+
function toggleLayer(id: Maps3DLayerId, on: boolean) {
|
|
534
|
+
// Опечатка в id или в параметрах не скомпилируется
|
|
535
|
+
mahalMap.value?.setLayer(id, on);
|
|
536
|
+
}
|
|
537
|
+
|
|
386
538
|
const buildingModeText = computed(() =>
|
|
387
539
|
is3dEnabled.value ? "3D включено" : "Контуры",
|
|
388
540
|
);
|
|
@@ -433,11 +585,21 @@ onMounted(async () => {
|
|
|
433
585
|
buildings.setWindowGlow?.(0.22);
|
|
434
586
|
buildings.setEdgeRadius(1.2);
|
|
435
587
|
|
|
588
|
+
// Слои: стартовый снимок плюс подписка на изменения.
|
|
589
|
+
// Состояние приходит асинхронно — сразу после setLayer() проверять бесполезно.
|
|
590
|
+
layers.value = map.getLayers();
|
|
591
|
+
unsubscribeLayers = map.onLayers(() => {
|
|
592
|
+
layers.value = map.getLayers();
|
|
593
|
+
});
|
|
594
|
+
|
|
436
595
|
isLayerReady.value = true;
|
|
437
596
|
});
|
|
438
597
|
|
|
439
598
|
onBeforeUnmount(() => {
|
|
440
599
|
isLayerReady.value = false;
|
|
600
|
+
// Отписку снимаем сами: иначе колбэк переживёт компонент.
|
|
601
|
+
unsubscribeLayers?.();
|
|
602
|
+
unsubscribeLayers = null;
|
|
441
603
|
// destroy() сам снимает слой Maps3D и удаляет карту MapLibre.
|
|
442
604
|
mahalMap.value?.destroy();
|
|
443
605
|
mahalMap.value = null;
|
|
@@ -458,6 +620,24 @@ onBeforeUnmount(() => {
|
|
|
458
620
|
>
|
|
459
621
|
{{ buildingToggleText }}
|
|
460
622
|
</button>
|
|
623
|
+
|
|
624
|
+
<ul class="layers">
|
|
625
|
+
<li v-for="layer in layers" :key="layer.id">
|
|
626
|
+
<label>
|
|
627
|
+
<!-- галочка по wanted: это воля приложения -->
|
|
628
|
+
<input
|
|
629
|
+
type="checkbox"
|
|
630
|
+
:checked="layer.wanted"
|
|
631
|
+
:disabled="!layer.available"
|
|
632
|
+
@change="toggleLayer(layer.id as Maps3DLayerId, !layer.wanted)"
|
|
633
|
+
/>
|
|
634
|
+
{{ layer.id }}
|
|
635
|
+
</label>
|
|
636
|
+
<!-- слой включён, но не нарисован — это норма, а не ошибка -->
|
|
637
|
+
<small v-if="layer.wanted && !layer.active">сейчас не видно</small>
|
|
638
|
+
<small v-else-if="!layer.available">нет в стиле</small>
|
|
639
|
+
</li>
|
|
640
|
+
</ul>
|
|
461
641
|
</section>
|
|
462
642
|
</main>
|
|
463
643
|
</template>
|
|
@@ -492,15 +672,18 @@ onBeforeUnmount(() => {
|
|
|
492
672
|
|
|
493
673
|
#### То же самое без сборщика (browser SDK)
|
|
494
674
|
|
|
675
|
+
Библиотеку карты проще взять у платформы: версия согласована с Maps3D, веб-воркер приезжает вместе с ней, про ESM-сборку думать не нужно.
|
|
676
|
+
|
|
495
677
|
```html
|
|
496
|
-
<script src="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.js"></script>
|
|
497
678
|
<script src="https://cdn.jsdelivr.net/npm/@grammaps/maps3d-web/dist/maps3d.global.js"></script>
|
|
498
679
|
<script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_MAP_API_KEY"></script>
|
|
499
680
|
|
|
500
681
|
<div id="map" style="width: 100%; height: 500px"></div>
|
|
501
682
|
<button id="toggle3d" type="button">Выключить 3D</button>
|
|
502
683
|
|
|
503
|
-
<script>
|
|
684
|
+
<script type="module">
|
|
685
|
+
const maplibregl = await Maps3D.maplibre({ base: "https://navi.gram.tj" });
|
|
686
|
+
|
|
504
687
|
// Maps3D берётся из window.Maps3D — третий аргумент передавать не нужно.
|
|
505
688
|
const map = MahalMap.create({
|
|
506
689
|
container: "map",
|
|
@@ -637,7 +820,7 @@ try {
|
|
|
637
820
|
</template>
|
|
638
821
|
|
|
639
822
|
<script setup lang="ts">
|
|
640
|
-
import maplibregl from "maplibre-gl";
|
|
823
|
+
import * as maplibregl from "maplibre-gl";
|
|
641
824
|
import "maplibre-gl/dist/maplibre-gl.css";
|
|
642
825
|
import type { MahalMap as MahalMapInstance } from "mahal_map";
|
|
643
826
|
import { onBeforeUnmount, onMounted, ref } from "vue";
|
|
@@ -884,6 +1067,12 @@ MahalMap.getLayers(map);
|
|
|
884
1067
|
MahalMap.onLayers(map, (state) => console.log(state.id, state.active));
|
|
885
1068
|
MahalMap.refreshLayers(map);
|
|
886
1069
|
|
|
1070
|
+
// Планы этажей
|
|
1071
|
+
MahalMap.getIndoorLevels(map);
|
|
1072
|
+
MahalMap.setIndoorLevel(map, 1);
|
|
1073
|
+
MahalMap.refreshIndoor(map);
|
|
1074
|
+
MahalMap.showPlace(map, 68.787, 38.573, 2, 18);
|
|
1075
|
+
|
|
887
1076
|
// Выделение зданий и клики
|
|
888
1077
|
MahalMap.onBuildingClick(map, (building) => console.log(building?.id));
|
|
889
1078
|
MahalMap.selectBuilding(map, 123456789);
|
|
@@ -939,6 +1128,10 @@ MahalMap.setZoom(map, 14);
|
|
|
939
1128
|
| `getLayers(instance)` | Снимок всех слоёв. |
|
|
940
1129
|
| `onLayers(instance, callback)` | Подписка на изменения слоёв; возвращает отписку. |
|
|
941
1130
|
| `refreshLayers(instance)` | Пере-применить волю клиента ко всем слоям. |
|
|
1131
|
+
| `getIndoorLevels(instance)` | Этажи, найденные в текущем виде карты. |
|
|
1132
|
+
| `setIndoorLevel(instance, level)` | Переключить этаж (0 — первый наземный). |
|
|
1133
|
+
| `refreshIndoor(instance)` | Перечитать планы этажей. |
|
|
1134
|
+
| `showPlace(instance, lon, lat, level?, zoom?)` | Показать объект и открыть его этаж. |
|
|
942
1135
|
| `onBuildingClick(instance, callback)` | Клик по зданию. |
|
|
943
1136
|
| `selectBuilding(instance, id, style?)` | Выделить здание по `osm_id`. |
|
|
944
1137
|
| `clearSelection(instance)` | Снять выделение. |
|
package/dist/index.d.mts
CHANGED
|
@@ -26,17 +26,64 @@ interface IAdditionalParamType {
|
|
|
26
26
|
* более старая сборка на странице не ломала типы у потребителя.
|
|
27
27
|
*/
|
|
28
28
|
type Maps3DThemeName = "light" | "dark" | "navigator-light" | "navigator-dark" | "mobile-light" | "mobile-dark";
|
|
29
|
-
/** Идентификатор слоя в реестре: buildings, objects, traffic, terrain, indoor, closures, parking, fuel, charging. */
|
|
30
|
-
type Maps3DLayerId = string;
|
|
31
29
|
/** Уровень детализации зданий. */
|
|
32
30
|
type Maps3DBuildingDetail = "footprint" | "volume" | "roofs" | "facade";
|
|
31
|
+
/** Режим рельефа: `auto` показывает его на обзорных зумах, `on` — всегда (дороже по трафику и кадру). */
|
|
32
|
+
type Maps3DTerrainMode = "auto" | "on" | "off";
|
|
33
|
+
/**
|
|
34
|
+
* Параметры каждого слоя реестра. Служит и справочником, и источником типов:
|
|
35
|
+
* ключи дают список id, значения — допустимые `params` в setLayer().
|
|
36
|
+
*
|
|
37
|
+
* У самой Maps3D id слоя типизирован как `string`, поэтому опечатка там проходит
|
|
38
|
+
* компиляцию и проваливается в рантайме (setLayer вернёт false). Здесь список
|
|
39
|
+
* фиксирован по таблице слоёв 0.7.3 — промах ловится на сборке.
|
|
40
|
+
*/
|
|
41
|
+
interface IMaps3DLayerParams {
|
|
42
|
+
/** Объёмные здания. По умолчанию включён. */
|
|
43
|
+
buildings: {
|
|
44
|
+
detail?: Maps3DBuildingDetail;
|
|
45
|
+
};
|
|
46
|
+
/** Расставленные 3D-объекты. По умолчанию включён. */
|
|
47
|
+
objects: Record<string, never>;
|
|
48
|
+
/** Пробки векторным слоем. По умолчанию выключен. */
|
|
49
|
+
traffic: Record<string, never>;
|
|
50
|
+
/** Пробки картинкой с сервера, без клика по дороге. По умолчанию выключен. */
|
|
51
|
+
trafficRaster: Record<string, never>;
|
|
52
|
+
/**
|
|
53
|
+
* Парковки. По умолчанию включён. Подтип берётся из атрибута `fee`:
|
|
54
|
+
* `paid` — `fee=yes`, `free` — `fee=no`, `unknown` — атрибута нет.
|
|
55
|
+
*/
|
|
56
|
+
parking: {
|
|
57
|
+
highlight?: boolean;
|
|
58
|
+
paid?: boolean;
|
|
59
|
+
free?: boolean;
|
|
60
|
+
unknown?: boolean;
|
|
61
|
+
};
|
|
62
|
+
/** Заправки. По умолчанию включён. */
|
|
63
|
+
fuel: Record<string, never>;
|
|
64
|
+
/** Зарядки. По умолчанию включён. */
|
|
65
|
+
charging: Record<string, never>;
|
|
66
|
+
/** Перекрытия дорог. По умолчанию выключен, требует своего тайлсета. */
|
|
67
|
+
closures: Record<string, never>;
|
|
68
|
+
/** Планы этажей. По умолчанию выключен, требует данных по зданию. */
|
|
69
|
+
indoor: {
|
|
70
|
+
level?: number;
|
|
71
|
+
};
|
|
72
|
+
/** Рельеф. По умолчанию `auto`. */
|
|
73
|
+
terrain: {
|
|
74
|
+
mode?: Maps3DTerrainMode;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Идентификатор слоя в реестре Maps3D. */
|
|
78
|
+
type Maps3DLayerId = keyof IMaps3DLayerParams;
|
|
33
79
|
/**
|
|
34
80
|
* Снимок состояния слоя. Три поля независимы: слой может быть включён клиентом (`wanted`),
|
|
35
81
|
* но не нарисован — рельеф в режиме auto ждёт обзорного зума, перекрытия ждут своего
|
|
36
82
|
* тайлсета, планы этажей — данных по зданию.
|
|
37
83
|
*/
|
|
38
84
|
interface IMaps3DLayerState {
|
|
39
|
-
|
|
85
|
+
/** Не сужен до Maps3DLayerId: сборка Maps3D может отдать слой, которого нет в нашем списке. */
|
|
86
|
+
id: string;
|
|
40
87
|
/** Чего хочет клиент: последний setLayer либо умолчание стиля. */
|
|
41
88
|
wanted: boolean;
|
|
42
89
|
/** Что позволяет стиль: объявлен ли слой и есть ли под него данные. */
|
|
@@ -150,8 +197,8 @@ interface IMaps3DLayer {
|
|
|
150
197
|
readonly ready?: Promise<void>;
|
|
151
198
|
destroy?(): void;
|
|
152
199
|
remove?(): void;
|
|
153
|
-
setLayer?(id:
|
|
154
|
-
layer?(id:
|
|
200
|
+
setLayer?(id: string, on: boolean, params?: Record<string, unknown>): boolean;
|
|
201
|
+
layer?(id: string): IMaps3DLayerState | null;
|
|
155
202
|
layers?(): IMaps3DLayerState[];
|
|
156
203
|
onLayers?(callback: (state: IMaps3DLayerState) => void): () => void;
|
|
157
204
|
refreshLayers?(): void;
|
|
@@ -255,6 +302,12 @@ interface IMahalMapOptions {
|
|
|
255
302
|
antialias?: boolean;
|
|
256
303
|
/** Опции Maps3D: buildings, traffic, indoor, closures, terrain, minZoom, lodBias, memoryBudget, ... */
|
|
257
304
|
maps3d?: Omit<IMaps3DLayerOptions, "apiKey" | "base">;
|
|
305
|
+
/**
|
|
306
|
+
* Диагностика неработающего веб-воркера MapLibre: если через 8 с после создания карты
|
|
307
|
+
* не разобран ни один векторный тайл, в консоль уходит предупреждение с причиной и
|
|
308
|
+
* решением. `false` отключает проверку, число задаёт свою задержку в мс.
|
|
309
|
+
*/
|
|
310
|
+
workerCheck?: boolean | number;
|
|
258
311
|
/**
|
|
259
312
|
* @deprecated Игнорируется с 2.0.0. Движок один — платформа MahalMaps через
|
|
260
313
|
* @grammaps/maps3d-web. Без переданного Maps3D карта поднимается на запасном стиле.
|
|
@@ -382,6 +435,8 @@ declare class MahalMap {
|
|
|
382
435
|
private static instances;
|
|
383
436
|
private static defaultLanguage;
|
|
384
437
|
private static disposedMaps3DLayers;
|
|
438
|
+
/** Через сколько мс после создания карты проверяем, ожил ли веб-воркер MapLibre. */
|
|
439
|
+
private static readonly WORKER_CHECK_DELAY;
|
|
385
440
|
private isReady;
|
|
386
441
|
private readyCallbacks;
|
|
387
442
|
private map;
|
|
@@ -400,6 +455,7 @@ declare class MahalMap {
|
|
|
400
455
|
private maps3dLayer?;
|
|
401
456
|
private maps3dReady?;
|
|
402
457
|
private buildingsEnabled;
|
|
458
|
+
private workerCheckTimer?;
|
|
403
459
|
private constructor();
|
|
404
460
|
private static getInstanceKey;
|
|
405
461
|
private static normalizeLanguage;
|
|
@@ -453,11 +509,15 @@ declare class MahalMap {
|
|
|
453
509
|
static getMaps3DLayer(instance: MahalMap): IMaps3DLayer | undefined;
|
|
454
510
|
static whenMaps3DReady(instance: MahalMap): Promise<IMaps3DLayer | undefined>;
|
|
455
511
|
static toggle3DBuildings(instance: MahalMap, enabled: boolean): void;
|
|
456
|
-
static setLayer(instance: MahalMap, id:
|
|
512
|
+
static setLayer<Id extends Maps3DLayerId>(instance: MahalMap, id: Id, on: boolean, params?: IMaps3DLayerParams[Id]): boolean;
|
|
457
513
|
static getLayerState(instance: MahalMap, id: Maps3DLayerId): IMaps3DLayerState | null;
|
|
458
514
|
static getLayers(instance: MahalMap): IMaps3DLayerState[];
|
|
459
515
|
static onLayers(instance: MahalMap, callback: (state: IMaps3DLayerState) => void): () => void;
|
|
460
516
|
static refreshLayers(instance: MahalMap): void;
|
|
517
|
+
static getIndoorLevels(instance: MahalMap): number[];
|
|
518
|
+
static setIndoorLevel(instance: MahalMap, level: number): void;
|
|
519
|
+
static refreshIndoor(instance: MahalMap): void;
|
|
520
|
+
static showPlace(instance: MahalMap, lon: number, lat: number, level?: number | null, zoom?: number): void;
|
|
461
521
|
static onBuildingClick(instance: MahalMap, callback: (info: IMaps3DBuildingClickInfo | null) => void): void;
|
|
462
522
|
static selectBuilding(instance: MahalMap, id: number | string | null, style?: IMaps3DSelectionStyle): boolean;
|
|
463
523
|
static clearSelection(instance: MahalMap): void;
|
|
@@ -500,8 +560,15 @@ declare class MahalMap {
|
|
|
500
560
|
* Резолвится в undefined, если слой выключен, Maps3D не передан или подключение упало.
|
|
501
561
|
*/
|
|
502
562
|
whenMaps3DReady(): Promise<IMaps3DLayer | undefined>;
|
|
503
|
-
/**
|
|
504
|
-
|
|
563
|
+
/**
|
|
564
|
+
* Включить/выключить слой. `params` типизирован под конкретный слой: `terrain` ждёт
|
|
565
|
+
* `{ mode }`, `buildings` — `{ detail }`, `indoor` — `{ level }`, у остальных параметров нет.
|
|
566
|
+
*
|
|
567
|
+
* Возвращает `false`, если такого слоя в подключённой сборке Maps3D нет или Maps3D не передан.
|
|
568
|
+
* Слой, которого ещё нет в нашем списке id, доступен напрямую:
|
|
569
|
+
* `map.getMaps3DLayer()?.setLayer?.("новый", true)`.
|
|
570
|
+
*/
|
|
571
|
+
setLayer<Id extends Maps3DLayerId>(id: Id, on: boolean, params?: IMaps3DLayerParams[Id]): boolean;
|
|
505
572
|
/** Состояние слоя: wanted (воля клиента), available (позволяет стиль), active (нарисовано). */
|
|
506
573
|
getLayerState(id: Maps3DLayerId): IMaps3DLayerState | null;
|
|
507
574
|
/** Снимок всех слоёв — по нему приложение рисует свою панель. */
|
|
@@ -510,6 +577,18 @@ declare class MahalMap {
|
|
|
510
577
|
onLayers(callback: (state: IMaps3DLayerState) => void): () => void;
|
|
511
578
|
/** Пере-применить волю клиента ко всем слоям — после полной смены стиля. */
|
|
512
579
|
refreshLayers(): void;
|
|
580
|
+
/** Этажи, найденные в текущем виде карты. Пусто — данных по зданию нет. */
|
|
581
|
+
getIndoorLevels(): number[];
|
|
582
|
+
/** Переключить этаж. Нумерация OSM: 0 — первый наземный. */
|
|
583
|
+
setIndoorLevel(level: number): void;
|
|
584
|
+
/** Перечитать планы этажей — после правки картографом. */
|
|
585
|
+
refreshIndoor(): void;
|
|
586
|
+
/**
|
|
587
|
+
* Показать найденный объект и открыть его этаж. Ровно то, что нужно после поиска:
|
|
588
|
+
* у объектов внутри зданий приходит `level` — без него карта откроет первый этаж
|
|
589
|
+
* и метка окажется в чужом зале.
|
|
590
|
+
*/
|
|
591
|
+
showPlace(lon: number, lat: number, level?: number | null, zoom?: number): void;
|
|
513
592
|
/** Клик по зданию: { id, height, props } либо null. Повторный вызов заменяет обработчик. */
|
|
514
593
|
onBuildingClick(callback: (info: IMaps3DBuildingClickInfo | null) => void): void;
|
|
515
594
|
/** Выделить здание по osm_id. `false` — здания сейчас нет в загруженных данных. */
|
|
@@ -539,6 +618,23 @@ declare class MahalMap {
|
|
|
539
618
|
* вызов teardown попал бы на уже освобождённый объект.
|
|
540
619
|
*/
|
|
541
620
|
private static teardownMaps3DLayer;
|
|
621
|
+
/**
|
|
622
|
+
* Диагностика неработающего веб-воркера MapLibre.
|
|
623
|
+
*
|
|
624
|
+
* Симптом злой: тайлы приходят, но разобрать их некому — карта показывает пустой фон,
|
|
625
|
+
* а в консоли лежит только `Uncaught SyntaxError: Unexpected token '<'`, где нет ни слова
|
|
626
|
+
* ни про MapLibre, ни про воркер. Причина почти всегда одна: сборщик не перенёс файл
|
|
627
|
+
* воркера рядом со сборкой, и вместо скрипта сервер отдаёт index.html.
|
|
628
|
+
*
|
|
629
|
+
* Проверку вешаем на таймер от создания карты, а НЕ на событие "load": при мёртвом
|
|
630
|
+
* воркере стиль не дозагружается и "load" не приходит вовсе.
|
|
631
|
+
*
|
|
632
|
+
* Смотрим на результат, а не на события: у Maps3D свой сторож (`gn`) слушает
|
|
633
|
+
* `data{sourceDataType:"content"}`, но это событие приходит при регистрации источника,
|
|
634
|
+
* за ~30 мс и без единого тайла — тревога снимается раньше, чем что-то могло сломаться.
|
|
635
|
+
*/
|
|
636
|
+
private watchWorkerHealth;
|
|
637
|
+
private reportBrokenWorker;
|
|
542
638
|
/**
|
|
543
639
|
* Приводит объём зданий к желаемому состоянию. Реестр слоёв (0.7.x) — основная дверь:
|
|
544
640
|
* он же прячет и возвращает штатные здания стиля. setBuildingsEnabled — путь для
|
|
@@ -821,4 +917,4 @@ declare namespace index {
|
|
|
821
917
|
export { index_checkCoordinates as checkCoordinates, index_debounce as debounce, index_geojsonPolyline as geojsonPolyline, index_geometryPolyline as geometryPolyline, index_trimValue as trimValue };
|
|
822
918
|
}
|
|
823
919
|
|
|
824
|
-
export { CheckJSApi, type IAdditionalParamType, type ICheckJSApiParam, type ICheckJSApiResponse, type IMahalMapOptions, type IMapMarker, type IMaps3DBuildingClickInfo, type IMaps3DBuildingsController, type IMaps3DBuildingsOptions, type IMaps3DClosuresOptions, type IMaps3DDiagnostics, type IMaps3DIndoorOptions, type IMaps3DLayer, type IMaps3DLayerOptions, type IMaps3DLayerState, type IMaps3DMapOptionsInput, type IMaps3DMapOptionsResult, type IMaps3DObjectsLightOptions, type IMaps3DPlacesOptions, type IMaps3DRoadHit, type IMaps3DSelectionStyle, type IMaps3DTrafficOptions, type IMaps3DTransformRequestOptions, type IResponse, type IRoute, type ISearchByLocationParam, type ISearchParam, type ISearchResponse, MahalMap, MahalMapDefaultMarker, type MahalMapDefaultMarkerProps, type MapEngine, type MapLanguage, type MapStyleFamily, type Maps3DBuildingDetail, type Maps3DCtor, type Maps3DLayerId, type Maps3DThemeName, type Maps3DTransformRequest, type MeasureIcons, type MeasureLabels, type MeasureMode, type MeasurePoint, type MeasureShape, type MeasureState, type MeasureStyleOptions, MeasureTool, type MeasureToolOptions, Router, Search, SearchByLocation, SearchPoi, type Theme, index$2 as keyUtils, index$1 as measureUtils, index as utils };
|
|
920
|
+
export { CheckJSApi, type IAdditionalParamType, type ICheckJSApiParam, type ICheckJSApiResponse, type IMahalMapOptions, type IMapMarker, type IMaps3DBuildingClickInfo, type IMaps3DBuildingsController, type IMaps3DBuildingsOptions, type IMaps3DClosuresOptions, type IMaps3DDiagnostics, type IMaps3DIndoorOptions, type IMaps3DLayer, type IMaps3DLayerOptions, type IMaps3DLayerParams, type IMaps3DLayerState, type IMaps3DMapOptionsInput, type IMaps3DMapOptionsResult, type IMaps3DObjectsLightOptions, type IMaps3DPlacesOptions, type IMaps3DRoadHit, type IMaps3DSelectionStyle, type IMaps3DTrafficOptions, type IMaps3DTransformRequestOptions, type IResponse, type IRoute, type ISearchByLocationParam, type ISearchParam, type ISearchResponse, MahalMap, MahalMapDefaultMarker, type MahalMapDefaultMarkerProps, type MapEngine, type MapLanguage, type MapStyleFamily, type Maps3DBuildingDetail, type Maps3DCtor, type Maps3DLayerId, type Maps3DTerrainMode, type Maps3DThemeName, type Maps3DTransformRequest, type MeasureIcons, type MeasureLabels, type MeasureMode, type MeasurePoint, type MeasureShape, type MeasureState, type MeasureStyleOptions, MeasureTool, type MeasureToolOptions, Router, Search, SearchByLocation, SearchPoi, type Theme, index$2 as keyUtils, index$1 as measureUtils, index as utils };
|