mahal_map 1.6.22 → 1.6.23

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 CHANGED
@@ -12,10 +12,10 @@ npm install mahal_map maplibre-gl
12
12
 
13
13
  `maplibre-gl` является peer dependency. Его нужно установить в приложении или подключить отдельным browser script перед SDK.
14
14
 
15
- Для нового 3D-движка (`engine: "3d"`) дополнительно нужен `@grammaps/maps3d-web`:
15
+ `@grammaps/maps3d-web` объявлен peer dependency пакета (в `package.json` помечен как `optional` — без него `engine: "legacy"` работает как обычно). Для `engine: "3d"` он обязателен в рантайме: установите его явно.
16
16
 
17
17
  ```sh
18
- npm i @grammaps/maps3d-web maplibre-gl
18
+ npm i mahal_map maplibre-gl @grammaps/maps3d-web
19
19
  ```
20
20
 
21
21
  ## Быстрый старт через NPM
@@ -71,8 +71,6 @@ const map = MahalMap.create(
71
71
  </script>
72
72
  ```
73
73
 
74
- ````
75
-
76
74
  Через NPM язык можно передать при создании карты:
77
75
 
78
76
  ```ts
@@ -84,7 +82,7 @@ const map = MahalMap.create(
84
82
  },
85
83
  maplibregl,
86
84
  );
87
- ````
85
+ ```
88
86
 
89
87
  Через browser SDK язык можно передать в URL скрипта:
90
88
 
@@ -96,9 +94,13 @@ const map = MahalMap.create(
96
94
 
97
95
  ## Параметры создания карты
98
96
 
99
- `MahalMap.create(options, maplibreObject?)`
97
+ `MahalMap.create(options, maplibreObject?, maps3dCtor?)`
98
+
99
+ `maps3dCtor` — импортированный конструктор `Maps3D` (третий, необязательный аргумент). Если не передан, SDK ищет его в `window.Maps3D`.
100
100
 
101
101
  ```ts
102
+ import type { IMaps3DLayerOptions } from "mahal_map";
103
+
102
104
  interface IMahalMapOptions {
103
105
  container?: string | HTMLElement;
104
106
  style?: string;
@@ -113,7 +115,7 @@ interface IMahalMapOptions {
113
115
  enable3D?: boolean;
114
116
  base?: string;
115
117
  preset?: string;
116
- maps3d?: IMaps3DOptions;
118
+ maps3d?: Omit<IMaps3DLayerOptions, "apiKey" | "base" | "buildings">;
117
119
  }
118
120
  ```
119
121
 
@@ -190,14 +192,26 @@ MahalMap.getMaps3DLayer(map);
190
192
 
191
193
  ### 3D-здания
192
194
 
193
- `Maps3D` рисует процедурные 3D-здания (three.js) вместо плоской `fill-extrusion` стиля: фаска кромок, вертикальный градиент и базовый цвет берутся из стиля, окна — из `metadata` пресета. При `engine: "3d"` слой создаётся и `attach`-ится к карте автоматически (`enable3D` по умолчанию `true`) — вручную поднимать `new Maps3D(...)` не нужно, только если требуется отдельный кастомный инстанс:
195
+ `Maps3D` рисует процедурные 3D-здания (three.js) вместо плоской `fill-extrusion` стиля: фаска кромок, вертикальный градиент и базовый цвет берутся из стиля, окна — из `metadata` пресета. При `engine: "3d"` слой создаётся и `attach`-ится к карте автоматически (`enable3D` по умолчанию `true`) — вручную поднимать `new Maps3D(...)` не нужно, только если требуется отдельный кастомный инстанс.
196
+
197
+ **Ручной `new Maps3D(...)` — отдельный сценарий.** Карту при этом создавайте с `enable3D: false`, иначе на неё повиснут два слоя Maps3D сразу (автоматический от `MahalMap` + ваш ручной) — дублирование зданий и лишний расход ресурсов:
194
198
 
195
199
  ```ts
200
+ const apiKey = "YOUR_MAP_API_KEY";
201
+ const base = "https://navi.gram.tj";
202
+
203
+ const map = MahalMap.create(
204
+ { container: "map", engine: "3d", enable3D: false },
205
+ maplibregl,
206
+ );
207
+
196
208
  const layer = new Maps3D({ apiKey, base, buildings: true });
197
- await layer.attach(map); // attach асинхронный, дожидается load карты сам
209
+ await layer.attach(map.getMap()); // attach ждёт нативную карту MapLibre, не обёртку MahalMap
198
210
  ```
199
211
 
200
- Тема (окна/свет) приходит из `metadata` пресета стиля и применяется автоматически при `map.setStyle()` — пересоздавать слой не нужно. Ручные сеттеры перебивают её:
212
+ Тема (окна/свет) приходит из `metadata` пресета стиля и применяется автоматически при `map.setStyle()` — пересоздавать слой не нужно. Ручные сеттеры перебивают её.
213
+
214
+ Это работает только для встроенных пресетов **без** явного `options.preset`: `setStyle()` меняет пресет по теме (`light`/`dark` → `GRAM_PRESETS`), а при заданном `preset` считает стиль зафиксированным и ничего не делает (см. [`MahalMap.ts`](src/core/MahalMap.ts:363)). Чтобы сменить пресет/тему в этом случае — пересоздайте карту с другим `preset` или вызовите `map.getMap().setStyle(...)` напрямую.
201
215
 
202
216
  ```ts
203
217
  const layer = map.getMaps3DLayer();
@@ -222,13 +236,7 @@ layer?.onBuildingClick((info) => {
222
236
 
223
237
  #### Вкл/выкл 3D-здания на лету
224
238
 
225
- Переключение 3D-здания ⇄ штатные здания стиля, без пересоздания карты:
226
-
227
- ```ts
228
- layer?.setBuildingsEnabled(false); // напрямую через слой
229
- ```
230
-
231
- Либо через обёртку `MahalMap` — она же умеет пересоздать слой, если его не было (`enable3D: false` при создании):
239
+ Переключение 3D-здания ⇄ штатные здания стиля, без пересоздания карты — через обёртку `MahalMap`. Она же умеет пересоздать слой, если его не было (`enable3D: false` при создании):
232
240
 
233
241
  ```ts
234
242
  const map = MahalMap.getInstance("map");
@@ -240,6 +248,8 @@ map.toggle3DBuildings(true); // вкл обратно
240
248
  MahalMap.toggle3DBuildings(map, false);
241
249
  ```
242
250
 
251
+ `layer?.setBuildingsEnabled(false)` напрямую через слой **не используйте** — он не знает про штатный слой стиля `building-3d`, который `MahalMap` прячет при включённом 3D. Вызов только слоя оставит эти штатные здания скрытыми и одновременно выключит процедурные — в итоге зданий не будет видно вообще, до следующей перезагрузки стиля.
252
+
243
253
  #### `map.whenMaps3DReady()`
244
254
 
245
255
  `attach()` слоя асинхронный: сразу после `create()` слой уже есть, но `layer.buildings` (окна, свет, кромки) появляется только после attach. Чтобы не гадать — дождитесь готовности:
@@ -313,12 +323,12 @@ onMounted(async () => {
313
323
  return;
314
324
  }
315
325
 
316
- buildings.setWindowMinZoom(16);
326
+ buildings.setWindowMinZoom?.(16);
317
327
  buildings.setWindowStyle(4);
318
328
  buildings.setWindowDepth(0.85);
319
329
  buildings.setWindowColor("#6b9ed1");
320
330
  buildings.setWindowFrameColor("#f2f2f4");
321
- buildings.setWindowGlow(0.22);
331
+ buildings.setWindowGlow?.(0.22);
322
332
  buildings.setEdgeRadius(1.2);
323
333
 
324
334
  isLayerReady.value = true;
@@ -437,18 +447,17 @@ layer?.setMinZoom(15);
437
447
  layer?.setObjectsLight({ sun: 1.8, ambient: 0.45, sky: 1.1, exposure: 1.15 });
438
448
  await layer?.refresh(); // перечитать модели после правок
439
449
  await layer?.clearCache(); // сбросить IndexedDB-кеш ассетов
440
- layer?.destroy?.(); // отцепить слой (также вызывается автоматически в map.destroy())
441
450
  ```
442
451
 
443
- `map.destroy()` / `MahalMap.destroy(map)` сами вызывают `destroy()`/`remove()` у Maps3D слоя, если он был подключенотдельно чистить не нужно.
452
+ Для полной остановки карты используйте только `map.destroy()` / `MahalMap.destroy(map)` — они сами вызывают `destroy()`/`remove()` у Maps3D слоя. **Не вызывайте `layer.destroy()`/`layer.remove()` напрямую**: `MahalMap` не узнает об этом и продолжит считать слой активным (внутренний `maps3dLayer`, `buildingsEnabled`, видимость штатных зданий стиля разойдутся с реальностью). Нужно временно выключить только 3D-здания используйте `map.toggle3DBuildings(false)` (см. выше).
444
453
 
445
454
  ## MahalMap
446
455
 
447
456
  `MahalMap` - основной класс карты. Конструктор закрыт, карту нужно создавать через `MahalMap.create()`.
448
457
 
449
- ### `MahalMap.create(options, maplibreObject?)`
458
+ ### `MahalMap.create(options, maplibreObject?, maps3dCtor?)`
450
459
 
451
- Создает новый инстанс карты и сохраняет его по ключу `container`. Для стандартных стилей перед созданием карты должен быть сохранен map token через `keyUtils.saveKey()`. В browser SDK token читается из обязательного URL-параметра `apikey`.
460
+ Создает новый инстанс карты и сохраняет его по ключу `container`. Для стандартных стилей перед созданием карты должен быть сохранен map token через `keyUtils.saveKey()`. В browser SDK token читается из обязательного URL-параметра `apikey`. Третий аргумент — необязательный конструктор `Maps3D`; без него SDK использует `window.Maps3D`.
452
461
 
453
462
  ```ts
454
463
  const map = MahalMap.create(
package/dist/index.d.mts CHANGED
@@ -216,6 +216,7 @@ type MapLibreApi = {
216
216
  declare class MahalMap {
217
217
  private static instances;
218
218
  private static defaultLanguage;
219
+ private static disposedMaps3DLayers;
219
220
  private isReady;
220
221
  private readyCallbacks;
221
222
  private map;
@@ -275,13 +276,22 @@ declare class MahalMap {
275
276
  */
276
277
  whenMaps3DReady(): Promise<IMaps3DLayer | undefined>;
277
278
  private attachMaps3DLayer;
279
+ /**
280
+ * Освобождает слой Maps3D одним доступным методом (destroy(), иначе remove()) и ровно один
281
+ * раз: destroy()/attach-catch/toggle3DBuildings(false) все могут метить в один и тот же layer
282
+ * (напр. map.destroy() случился, пока attach() ещё не резолвился) — без WeakSet-гварда второй
283
+ * вызов teardown попал бы на уже освобождённый объект.
284
+ */
285
+ private static teardownMaps3DLayer;
278
286
  private applyMaps3DBuildingMode;
279
287
  /**
280
- * Прячет/показывает нативные здания стиля GramMaps ("building-3d" и прочие
281
- * fill/fill-extrusion слои зданий), не задевая слои самого Maps3D. Нужно, иначе плоский слой
282
- * стиля рисуется поверх процедурных 3D-зданий и визуально их перекрывает.
283
- * Проверяем именно "здание" (id или source-layer), чтобы не гасить чужую экструзию
284
- * в пользовательском стиле.
288
+ * Прячет/показывает нативный слой зданий GramMaps-пресетов ("building-3d"), не задевая слои
289
+ * самого Maps3D. Нужно, иначе плоский слой стиля рисуется поверх процедурных 3D-зданий и
290
+ * визуально их перекрывает.
291
+ *
292
+ * Только для встроенных пресетов (buildGramStyleUrl) — при пользовательском `options.style`
293
+ * мы не знаем структуру стиля, гасить слои по имени/source-layer небезопасно (можно случайно
294
+ * погасить чужую fill-extrusion, никак не связанную со зданиями GramMaps).
285
295
  */
286
296
  private setNativeBuildingsVisible;
287
297
  setCenter(center: [number, number]): void;
package/dist/index.d.ts CHANGED
@@ -216,6 +216,7 @@ type MapLibreApi = {
216
216
  declare class MahalMap {
217
217
  private static instances;
218
218
  private static defaultLanguage;
219
+ private static disposedMaps3DLayers;
219
220
  private isReady;
220
221
  private readyCallbacks;
221
222
  private map;
@@ -275,13 +276,22 @@ declare class MahalMap {
275
276
  */
276
277
  whenMaps3DReady(): Promise<IMaps3DLayer | undefined>;
277
278
  private attachMaps3DLayer;
279
+ /**
280
+ * Освобождает слой Maps3D одним доступным методом (destroy(), иначе remove()) и ровно один
281
+ * раз: destroy()/attach-catch/toggle3DBuildings(false) все могут метить в один и тот же layer
282
+ * (напр. map.destroy() случился, пока attach() ещё не резолвился) — без WeakSet-гварда второй
283
+ * вызов teardown попал бы на уже освобождённый объект.
284
+ */
285
+ private static teardownMaps3DLayer;
278
286
  private applyMaps3DBuildingMode;
279
287
  /**
280
- * Прячет/показывает нативные здания стиля GramMaps ("building-3d" и прочие
281
- * fill/fill-extrusion слои зданий), не задевая слои самого Maps3D. Нужно, иначе плоский слой
282
- * стиля рисуется поверх процедурных 3D-зданий и визуально их перекрывает.
283
- * Проверяем именно "здание" (id или source-layer), чтобы не гасить чужую экструзию
284
- * в пользовательском стиле.
288
+ * Прячет/показывает нативный слой зданий GramMaps-пресетов ("building-3d"), не задевая слои
289
+ * самого Maps3D. Нужно, иначе плоский слой стиля рисуется поверх процедурных 3D-зданий и
290
+ * визуально их перекрывает.
291
+ *
292
+ * Только для встроенных пресетов (buildGramStyleUrl) — при пользовательском `options.style`
293
+ * мы не знаем структуру стиля, гасить слои по имени/source-layer небезопасно (можно случайно
294
+ * погасить чужую fill-extrusion, никак не связанную со зданиями GramMaps).
285
295
  */
286
296
  private setNativeBuildingsVisible;
287
297
  setCenter(center: [number, number]): void;