mahal_map 2.0.1 → 2.0.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/README.md CHANGED
@@ -68,15 +68,15 @@ maplibregl.setWorkerUrl("/maplibre-gl-worker.mjs"); // файл скопиров
68
68
 
69
69
  Собственных URL стилей у `mahal_map` больше нет — их целиком отдаёт `@grammaps/maps3d-web`.
70
70
 
71
- | 1.x | 2.0 |
72
- | ---------------------------------------------- | -------------------------------------------------------------- |
73
- | `engine: "legacy"` (по умолчанию) | Удалён. Единственный путь — платформа через `Maps3D`. |
74
- | `engine: "3d"` | Больше не нужен, опция игнорируется. |
75
- | `autoAddVectorSource: true` | Удалён. Тот же векторный стиль применяется сам, когда нет `Maps3D`. |
76
- | `preset: "standard-night"` | `theme: "dark"`, либо полный URL в `style`. |
77
- | `preset: "road-urban-lab-v2"` | `theme: "light"`, либо полный URL в `style`. |
78
- | `lang` менял URL стиля | Стиль не трогает — язык подписей приходит из самого стиля. |
79
- | `layer.setBuildingsEnabled(...)` напрямую | `map.toggle3DBuildings(...)` или `map.setLayer("buildings", ...)`. |
71
+ | 1.x | 2.0 |
72
+ | ----------------------------------------- | ------------------------------------------------------------------- |
73
+ | `engine: "legacy"` (по умолчанию) | Удалён. Единственный путь — платформа через `Maps3D`. |
74
+ | `engine: "3d"` | Больше не нужен, опция игнорируется. |
75
+ | `autoAddVectorSource: true` | Удалён. Тот же векторный стиль применяется сам, когда нет `Maps3D`. |
76
+ | `preset: "standard-night"` | `theme: "dark"`, либо полный URL в `style`. |
77
+ | `preset: "road-urban-lab-v2"` | `theme: "light"`, либо полный URL в `style`. |
78
+ | `lang` менял URL стиля | Стиль не трогает — язык подписей приходит из самого стиля. |
79
+ | `layer.setBuildingsEnabled(...)` напрямую | `map.toggle3DBuildings(...)` или `map.setLayer("buildings", ...)`. |
80
80
 
81
81
  `engine` и `autoAddVectorSource` оставлены в типах как `@deprecated`, чтобы не ломать компиляцию, но на поведение не влияют.
82
82
 
@@ -203,42 +203,50 @@ interface IMahalMapOptions {
203
203
  antialias?: boolean;
204
204
  workerCheck?: boolean | number;
205
205
  maps3d?: Omit<IMaps3DLayerOptions, "apiKey" | "base">;
206
+ /** @deprecated Оставлена для совместимости, на поведение не влияет. */
207
+ engine?: "legacy" | "3d";
208
+ /** @deprecated Оставлена для совместимости, на поведение не влияет. */
209
+ autoAddVectorSource?: boolean;
206
210
  }
207
211
  ```
208
212
 
209
- | Параметр | Тип | Описание |
210
- | ----------- | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
211
- | `container` | `string \| HTMLElement` | ID контейнера или DOM-элемент. Не передан — берётся `"map"`. |
212
- | `style` | `string` | Полный URL своего стиля. Задан — стиль зафиксирован, `setStyle()` его не меняет. |
213
- | `theme` | `"dark" \| "light"` | Светлая/тёмная внутри выбранного `family`. По умолчанию `light`. |
214
- | `lang` | `"tj" \| "ru"` | Язык для поиска и роутинга. На стиль не влияет — подписи приходят из самого стиля платформы. |
215
- | `center` | `[number, number]` | Центр карты в формате `[lng, lat]`. |
216
- | `zoom` | `number` | Начальный zoom. |
217
- | `pitch` | `number` | Начальный наклон камеры. Не задан и 3D включено — авто `58`: при `pitch: 0` объём зданий не виден, камера смотрит строго сверху. |
218
- | `bearing` | `number` | Начальный поворот камеры. |
219
- | `enable3D` | `boolean` | Подключает Maps3D. По умолчанию `true`, когда `Maps3D` доступен. |
220
- | `base` | `string` | Домен платформы. По умолчанию `https://navi.gram.tj`. |
221
- | `family` | `"default" \| "navigator" \| "mobile"` | Семейство стилей. `theme` выбирает внутри него: `default` → `light`/`dark`, `navigator` → `navigator-light`/`navigator-dark`, `mobile` → `mobile-*`. |
222
- | `preset` | `Maps3DThemeName \| string` | Явное имя темы платформы или полный URL стиля вместо пары `family` + `theme`. Задан — стиль зафиксирован. |
223
- | `antialias` | `boolean` | Сглаживание сцены. По умолчанию `true` при включённом 3D: без него тонкая геометрия (перила, мачты, ряды сидений) на отдалении рассыпается в рябь. |
224
- | `workerCheck` | `boolean \| number` | Диагностика неработающего веб-воркера MapLibre через 8 с после создания карты. `false` отключает, число задаёт свою задержку в мс. См. [Веб-воркер MapLibre](#веб-воркер-maplibre). |
225
- | `maps3d` | `object` | Опции Maps3D: `buildings`, `traffic`, `indoor`, `closures`, `places`, `minZoom`, `lodBias`, `memoryBudget`, `maskReplaced`, `typeReplacements`. |
213
+ | Параметр | Тип | Описание |
214
+ | ------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
215
+ | `container` | `string \| HTMLElement` | ID контейнера или DOM-элемент. Не передан — берётся `"map"`. |
216
+ | `style` | `string` | Полный URL своего стиля. Задан — стиль зафиксирован, `setStyle()` его не меняет. |
217
+ | `theme` | `"dark" \| "light"` | Светлая/тёмная внутри выбранного `family`. По умолчанию `light`. |
218
+ | `lang` | `"tj" \| "ru"` | Язык для поиска и роутинга. На стиль не влияет — подписи приходят из самого стиля платформы. |
219
+ | `center` | `[number, number]` | Центр карты в формате `[lng, lat]`. |
220
+ | `zoom` | `number` | Начальный zoom. |
221
+ | `pitch` | `number` | Начальный наклон камеры. Не задан и 3D включено — авто `58`: при `pitch: 0` объём зданий не виден, камера смотрит строго сверху. |
222
+ | `bearing` | `number` | Начальный поворот камеры. |
223
+ | `enable3D` | `boolean` | Подключает Maps3D. По умолчанию `true`, когда `Maps3D` доступен. |
224
+ | `base` | `string` | Домен платформы. По умолчанию `https://navi.gram.tj`. |
225
+ | `family` | `"default" \| "navigator" \| "mobile"` | Семейство стилей. `theme` выбирает внутри него: `default` → `light`/`dark`, `navigator` → `navigator-light`/`navigator-dark`, `mobile` → `mobile-*`. |
226
+ | `preset` | `Maps3DThemeName \| string` | Явное имя темы платформы или полный URL стиля вместо пары `family` + `theme`. Задан — стиль зафиксирован. |
227
+ | `antialias` | `boolean` | Сглаживание сцены. По умолчанию `true` при включённом 3D: без него тонкая геометрия (перила, мачты, ряды сидений) на отдалении рассыпается в рябь. |
228
+ | `workerCheck` | `boolean \| number` | Диагностика неработающего веб-воркера MapLibre через 8 с после создания карты. `false` отключает, число задаёт свою задержку в мс. См. [Веб-воркер MapLibre](#веб-воркер-maplibre). |
229
+ | `maps3d` | `object` | Опции Maps3D: `buildings`, `traffic`, `indoor`, `closures`, `places`, `minZoom`, `lodBias`, `memoryBudget`, `maskReplaced`, `typeReplacements`. |
226
230
 
227
231
  ### Стили и темы
228
232
 
229
233
  Стили целиком приходят из `@grammaps/maps3d-web` — своего списка URL у `mahal_map` больше нет. Словарь тем один и тот же у SDK и у библиотеки:
230
234
 
231
- | `family` | `theme: "light"` | `theme: "dark"` |
232
- | ------------- | ------------------ | ----------------- |
233
- | `"default"` | `light` | `dark` |
234
- | `"navigator"` | `navigator-light` | `navigator-dark` |
235
- | `"mobile"` | `mobile-light` | `mobile-dark` |
235
+ | `family` | `theme: "light"` | `theme: "dark"` |
236
+ | ------------- | ----------------- | ---------------- |
237
+ | `"default"` | `light` | `dark` |
238
+ | `"navigator"` | `navigator-light` | `navigator-dark` |
239
+ | `"mobile"` | `mobile-light` | `mobile-dark` |
236
240
 
237
241
  Имя темы уходит в `Maps3D.styleUrl()`, адрес строит сам SDK. Неизвестное имя — явная ошибка с префиксом `[MahalMap SDK]`, а не пустая карта.
238
242
 
239
243
  ```ts
240
244
  // Навигаторная тёмная тема
241
- MahalMap.create({ container: "map", family: "navigator", theme: "dark" }, maplibregl, Maps3D);
245
+ MahalMap.create(
246
+ { container: "map", family: "navigator", theme: "dark" },
247
+ maplibregl,
248
+ Maps3D,
249
+ );
242
250
 
243
251
  // Смена темы внутри того же семейства
244
252
  map.setStyle("light"); // → navigator-light
@@ -248,7 +256,10 @@ map.setStyle("light"); // → navigator-light
248
256
  >
249
257
  > ```ts
250
258
  > MahalMap.create(
251
- > { container: "map", style: "https://navi.gram.tj/maps/standard-night.json" },
259
+ > {
260
+ > container: "map",
261
+ > style: "https://navi.gram.tj/maps/standard-night.json",
262
+ > },
252
263
  > maplibregl,
253
264
  > Maps3D,
254
265
  > );
@@ -264,18 +275,18 @@ map.setStyle("light"); // → navigator-light
264
275
 
265
276
  Передаются в `MahalMap.create({ maps3d: {...} })` и уходят в `Maps3D` как есть:
266
277
 
267
- | Опция | Тип | По умолч. | Описание |
268
- | ------------------ | ----------------------------------------------------- | --------- | -------------------------------------------------------------------- |
269
- | `buildings` | `boolean \| { detail?: footprint\|volume\|roofs\|facade }` | `true` | Объёмные здания; объектом — их облик. |
270
- | `traffic` | `boolean \| { raster?, rasterMaxZoom?, graph?, opacity?, arrows? }` | `false` | Слой пробок. `raster: true` — картинкой вместо векторного слоя. |
271
- | `indoor` | `boolean \| { level? }` | `false` | Планы этажей. |
272
- | `closures` | `boolean \| object` | `false` | Перекрытия дорог. |
273
- | `places` | `object` | — | Парковки, заправки, зарядки: `highlight`, `paid`, `free`, `unknown`. |
274
- | `minZoom` | `number` | `16` | Зум появления объёма. |
275
- | `lodBias` | `number` | `1` | `0` — всегда детальная геометрия, `1` — упрощённая вдали. |
276
- | `memoryBudget` | `number` | `30` | Сколько 3D-моделей держать в памяти. |
277
- | `maskReplaced` | `boolean` | `true` | Прятать заменённые OSM-объекты (`anchor=replace`). |
278
- | `typeReplacements` | `boolean` | `true` | Рисовать замены по типу (`natural=tree` → 3D-дерево и т.п.). |
278
+ | Опция | Тип | По умолч. | Описание |
279
+ | ------------------ | ------------------------------------------------------------------- | --------- | -------------------------------------------------------------------- |
280
+ | `buildings` | `boolean \| { detail?: footprint\|volume\|roofs\|facade }` | `true` | Объёмные здания; объектом — их облик. |
281
+ | `traffic` | `boolean \| { raster?, rasterMaxZoom?, graph?, opacity?, arrows? }` | `false` | Слой пробок. `raster: true` — картинкой вместо векторного слоя. |
282
+ | `indoor` | `boolean \| { level? }` | `false` | Планы этажей. |
283
+ | `closures` | `boolean \| object` | `false` | Перекрытия дорог. |
284
+ | `places` | `object` | — | Парковки, заправки, зарядки: `highlight`, `paid`, `free`, `unknown`. |
285
+ | `minZoom` | `number` | `16` | Зум появления объёма. |
286
+ | `lodBias` | `number` | `1` | `0` — всегда детальная геометрия, `1` — упрощённая вдали. |
287
+ | `memoryBudget` | `number` | `30` | Сколько 3D-моделей держать в памяти. |
288
+ | `maskReplaced` | `boolean` | `true` | Прятать заменённые OSM-объекты (`anchor=replace`). |
289
+ | `typeReplacements` | `boolean` | `true` | Рисовать замены по типу (`natural=tree` → 3D-дерево и т.п.). |
279
290
 
280
291
  `apiKey` и `base` в `maps3d` передавать не нужно — их подставляет сам `MahalMap` из сохранённого ключа и `options.base`.
281
292
 
@@ -293,17 +304,19 @@ map.getLayerState("terrain"); // снимок одного слоя или null
293
304
  map.getLayers(); // снимок всех — по нему рисуется панель слоёв
294
305
  ```
295
306
 
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
+ | `buildings` | `detail: footprint\|volume\|roofs\|facade` | включён | зашито |
310
+ | `objects` | — | включён | зашито |
311
+ | `terrain` | `mode: auto\|on\|off` | включён, `mode: "auto"` | зашито |
312
+ | `parking` | `highlight`, `paid`, `free`, `unknown` | включён, `{ highlight: false, paid: true, free: true, unknown: true }` | зашито |
313
+ | `fuel`, `charging` | | включены | зашито |
314
+ | `traffic` | — | выключен | `maps3d.traffic` |
315
+ | `trafficRaster` | — | выключен | `maps3d.traffic.raster` |
316
+ | `indoor` | `level` | выключен | `maps3d.indoor` |
317
+ | `closures` | — | выключен | `maps3d.closures` |
318
+
319
+ У нижних четырёх умолчание не зашито — реестр берёт его из опций `maps3d`, переданных при создании карты. Поэтому «выключен» в таблице значит «выключен, пока вы не передали опцию», а не «выключен всегда».
307
320
 
308
321
  Стартовое состояние можно задать сразу при создании карты — тогда первый кадр уже правильный, без моргания:
309
322
 
@@ -321,11 +334,11 @@ MahalMap.create(
321
334
 
322
335
  Поля независимы, и это главная ловушка реестра:
323
336
 
324
- | Поле | Вопрос |
325
- | ----------- | --------------------------------------- |
326
- | `wanted` | чего хочет приложение |
327
- | `available` | что позволяют стиль и данные |
328
- | `active` | что нарисовано прямо сейчас |
337
+ | Поле | Вопрос |
338
+ | ----------- | ---------------------------- |
339
+ | `wanted` | чего хочет приложение |
340
+ | `available` | что позволяют стиль и данные |
341
+ | `active` | что нарисовано прямо сейчас |
329
342
 
330
343
  Слой может быть включён и при этом не нарисован — и это не ошибка:
331
344
 
@@ -360,15 +373,20 @@ unsubscribe();
360
373
 
361
374
  Подтип парковки берётся из атрибута `fee`:
362
375
 
363
- | Параметр | Условие |
364
- | ----------- | --------------- |
365
- | `paid` | `fee=yes` |
366
- | `free` | `fee=no` |
367
- | `unknown` | атрибута нет |
376
+ | Параметр | Условие |
377
+ | --------- | ------------ |
378
+ | `paid` | `fee=yes` |
379
+ | `free` | `fee=no` |
380
+ | `unknown` | атрибута нет |
368
381
 
369
382
  ```ts
370
383
  // только платные, с подсветкой
371
- map.setLayer("parking", true, { paid: true, free: false, unknown: false, highlight: true });
384
+ map.setLayer("parking", true, {
385
+ paid: true,
386
+ free: false,
387
+ unknown: false,
388
+ highlight: true,
389
+ });
372
390
  ```
373
391
 
374
392
  #### Рельеф
@@ -493,7 +511,15 @@ map.toggle3DBuildings(true); // вкл обратно
493
511
  MahalMap.toggle3DBuildings(map, false);
494
512
  ```
495
513
 
496
- Под капотом это `setLayer("buildings", enabled)`. Штатные здания стиля прячет и возвращает сам `Maps3D` — `mahal_map` их видимость не трогает, поэтому спорить за один слой некому. Эквивалентная запись: `map.setLayer("buildings", false)`.
514
+ Штатные здания стиля прячет и возвращает сам `Maps3D` — `mahal_map` их видимость не трогает, поэтому спорить за один слой некому.
515
+
516
+ Для переключения пользуйтесь именно `toggle3DBuildings()`: он поднимет слой, если его ещё не было (`enable3D: false` при создании), а на сборках Maps3D без реестра слоёв откатится на `setBuildingsEnabled()`.
517
+
518
+ ```ts
519
+ map.toggle3DBuildings(false); // совместимо со всеми сборками
520
+ ```
521
+
522
+ `map.setLayer("buildings", false)` — не замена: он ходит только в реестр и ничего не создаёт. Годится, когда вы точно знаете, что на странице Maps3D с реестром слоёв (0.7.x), и слой уже подключён.
497
523
 
498
524
  #### `map.whenMaps3DReady()`
499
525
 
@@ -660,15 +686,15 @@ onBeforeUnmount(() => {
660
686
 
661
687
  Что библиотека делает за вас против ручного подключения `@grammaps/maps3d-web`:
662
688
 
663
- | Ручной код | Через `mahal_map` |
664
- | --------------------------------------------------- | -------------------------------------------------------------- |
665
- | `...Maps3D.mapOptions({ base, apiKey, style })` | `theme` + `family` (или `preset` / `style` / `base` явно) |
666
- | `antialias: true` не забыть | ставится сам при включённом 3D |
667
- | `Maps3D.enhance(map, opts); await maps3d.ready` | `enable3D: true` + `maps3d: {...}`, `await map.whenMaps3DReady()` |
668
- | `map.setStyle(Maps3D.styleUrl("dark", base))` | `map.setStyle("dark")` — внутри выбранного семейства |
669
- | `maps3d.refreshLayers()` после смены стиля | вызывается сам на `style.load` |
670
- | `maps3d.destroy(); map.remove()` | `map.destroy()` |
671
- | ключ руками в каждый вызов | один `keyUtils.saveKey()` на всё |
689
+ | Ручной код | Через `mahal_map` |
690
+ | ----------------------------------------------- | ----------------------------------------------------------------- |
691
+ | `...Maps3D.mapOptions({ base, apiKey, style })` | `theme` + `family` (или `preset` / `style` / `base` явно) |
692
+ | `antialias: true` не забыть | ставится сам при включённом 3D |
693
+ | `Maps3D.enhance(map, opts); await maps3d.ready` | `enable3D: true` + `maps3d: {...}`, `await map.whenMaps3DReady()` |
694
+ | `map.setStyle(Maps3D.styleUrl("dark", base))` | `map.setStyle("dark")` — внутри выбранного семейства |
695
+ | `maps3d.refreshLayers()` после смены стиля | вызывается сам на `style.load` |
696
+ | `maps3d.destroy(); map.remove()` | `map.destroy()` |
697
+ | ключ руками в каждый вызов | один `keyUtils.saveKey()` на всё |
672
698
 
673
699
  #### То же самое без сборщика (browser SDK)
674
700
 
@@ -684,14 +710,18 @@ onBeforeUnmount(() => {
684
710
  <script type="module">
685
711
  const maplibregl = await Maps3D.maplibre({ base: "https://navi.gram.tj" });
686
712
 
687
- // Maps3D берётся из window.Maps3D третий аргумент передавать не нужно.
688
- const map = MahalMap.create({
689
- container: "map",
690
- theme: "dark",
691
- center: [68.787, 38.573],
692
- zoom: 16.6,
693
- pitch: 58,
694
- });
713
+ // maplibregl обязателен вторым аргументом: window.maplibregl здесь не появляется.
714
+ // Maps3D третьим можно не передавать — SDK возьмёт его из window.Maps3D.
715
+ const map = MahalMap.create(
716
+ {
717
+ container: "map",
718
+ theme: "dark",
719
+ center: [68.787, 38.573],
720
+ zoom: 16.6,
721
+ pitch: 58,
722
+ },
723
+ maplibregl,
724
+ );
695
725
 
696
726
  let enabled = true;
697
727
 
@@ -791,13 +821,13 @@ try {
791
821
 
792
822
  Правила проверки:
793
823
 
794
- | Условие | Поведение |
795
- | ------- | --------- |
796
- | `Maps3D` не передан, сервис ответил `success: true` | Карта создаётся на запасном стиле. |
797
- | `Maps3D` не передан, сервис ответил `success: false` | Карта **не** создаётся, промис отклоняется: `[MahalMap SDK] JSApi subscription is not active for this key: <message>`. |
798
- | `Maps3D` не передан, проверка не дошла (сеть, CORS, таймаут) | Fail-open: `console.warn` и карта создаётся. Падение сервиса проверки не гасит карты. |
799
- | `Maps3D` передан | Проверка **пропускается**, запрос не отправляется. |
800
- | Map token не сохранён | Проверка пропускается, дальше срабатывает обычная ошибка про `apikey`. |
824
+ | Условие | Поведение |
825
+ | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
826
+ | `Maps3D` не передан, сервис ответил `success: true` | Карта создаётся на запасном стиле. |
827
+ | `Maps3D` не передан, сервис ответил `success: false` | Карта **не** создаётся, промис отклоняется: `[MahalMap SDK] JSApi subscription is not active for this key: <message>`. |
828
+ | `Maps3D` не передан, проверка не дошла (сеть, CORS, таймаут) | Fail-open: `console.warn` и карта создаётся. Падение сервиса проверки не гасит карты. |
829
+ | `Maps3D` передан | Проверка **пропускается**, запрос не отправляется. |
830
+ | Map token не сохранён | Проверка пропускается, дальше срабатывает обычная ошибка про `apikey`. |
801
831
 
802
832
  С переданным `Maps3D` вызов `createAsync()` ведёт себя ровно как `create()` — доступ к платформе контролируется параметром `?key=` на её стороне, отдельная подписка JSApi к ней отношения не имеет.
803
833
 
@@ -814,7 +844,9 @@ try {
814
844
  <div ref="mapElement" class="h-[360px] w-full" />
815
845
  </div>
816
846
  <template #fallback>
817
- <div class="flex h-[360px] items-center justify-center">{{ loadingLabel }}</div>
847
+ <div class="flex h-[360px] items-center justify-center">
848
+ {{ loadingLabel }}
849
+ </div>
818
850
  </template>
819
851
  </ClientOnly>
820
852
  </template>
@@ -1105,43 +1137,43 @@ MahalMap.setZoom(map, 14);
1105
1137
 
1106
1138
  Доступные функции карты в browser SDK:
1107
1139
 
1108
- | Функция | Описание |
1109
- | -------------------------------------- | ------------------------------------------------------------- |
1110
- | `create(options)` | Создает карту. Требует `apikey` в URL SDK скрипта. |
1111
- | `createAsync(options)` | Создает карту после проверки подписки JSApi (только без Maps3D). |
1112
- | `onReady(container, callback)` | Выполняет callback после загрузки карты. |
1113
- | `getInstance(container)` | Возвращает инстанс карты. |
1114
- | `hasInstance(container)` | Проверяет наличие инстанса. |
1115
- | `removeInstance(container)` | Удаляет инстанс из реестра. |
1116
- | `getMap(instance)` | Возвращает нативный MapLibre Map. |
1117
- | `getCamera(instance)` | Возвращает CameraController. |
1118
- | `setStyle(instance, theme)` | Переключает тему стандартного стиля. |
1119
- | `setLanguage(instance, lang)` | Переключает язык стандартного стиля. |
1120
- | `setCenter(instance, center)` | Меняет центр карты. |
1121
- | `setZoom(instance, zoom)` | Меняет zoom карты. |
1122
- | `addMarker(instance, marker)` | Добавляет маркер. |
1123
- | `getMaps3DLayer(instance)` | Возвращает инстанс слоя Maps3D (`undefined`, если Maps3D не передан). |
1124
- | `whenMaps3DReady(instance)` | Промис слоя Maps3D после `attach()` (готов `layer.buildings`). |
1125
- | `toggle3DBuildings(instance, enabled)` | Вкл/выкл объёмные здания на лету. |
1126
- | `setLayer(instance, id, on, params?)` | Включить/выключить слой платформы. |
1127
- | `getLayerState(instance, id)` | Снимок состояния одного слоя. |
1128
- | `getLayers(instance)` | Снимок всех слоёв. |
1129
- | `onLayers(instance, callback)` | Подписка на изменения слоёв; возвращает отписку. |
1130
- | `refreshLayers(instance)` | Пере-применить волю клиента ко всем слоям. |
1131
- | `getIndoorLevels(instance)` | Этажи, найденные в текущем виде карты. |
1132
- | `setIndoorLevel(instance, level)` | Переключить этаж (0 — первый наземный). |
1133
- | `refreshIndoor(instance)` | Перечитать планы этажей. |
1134
- | `showPlace(instance, lon, lat, level?, zoom?)` | Показать объект и открыть его этаж. |
1135
- | `onBuildingClick(instance, callback)` | Клик по зданию. |
1136
- | `selectBuilding(instance, id, style?)` | Выделить здание по `osm_id`. |
1137
- | `clearSelection(instance)` | Снять выделение. |
1138
- | `selectedBuilding(instance)` | Идентификатор выделенного здания или `null`. |
1139
- | `setSelectionStyle(instance, style)` | Облик выделения. |
1140
- | `onRoadClick(instance, callback)` | Клик по дороге. |
1141
- | `roadAt(instance, point, tolPx?)` | Дорога под точкой холста. |
1142
- | `destroy(instance)` | Полностью удаляет карту. |
1143
- | `loadKeyFromScriptUrl()` | Читает `apikey` из URL SDK скрипта. |
1144
- | `loadLanguageFromScriptUrl()` | Читает `lang` из URL SDK скрипта. |
1140
+ | Функция | Описание |
1141
+ | ---------------------------------------------- | --------------------------------------------------------------------- |
1142
+ | `create(options)` | Создает карту. Требует `apikey` в URL SDK скрипта. |
1143
+ | `createAsync(options)` | Создает карту после проверки подписки JSApi (только без Maps3D). |
1144
+ | `onReady(container, callback)` | Выполняет callback после загрузки карты. |
1145
+ | `getInstance(container)` | Возвращает инстанс карты. |
1146
+ | `hasInstance(container)` | Проверяет наличие инстанса. |
1147
+ | `removeInstance(container)` | Удаляет инстанс из реестра. |
1148
+ | `getMap(instance)` | Возвращает нативный MapLibre Map. |
1149
+ | `getCamera(instance)` | Возвращает CameraController. |
1150
+ | `setStyle(instance, theme)` | Переключает тему стандартного стиля. |
1151
+ | `setLanguage(instance, lang)` | Переключает язык стандартного стиля. |
1152
+ | `setCenter(instance, center)` | Меняет центр карты. |
1153
+ | `setZoom(instance, zoom)` | Меняет zoom карты. |
1154
+ | `addMarker(instance, marker)` | Добавляет маркер. |
1155
+ | `getMaps3DLayer(instance)` | Возвращает инстанс слоя Maps3D (`undefined`, если Maps3D не передан). |
1156
+ | `whenMaps3DReady(instance)` | Промис слоя Maps3D после `attach()` (готов `layer.buildings`). |
1157
+ | `toggle3DBuildings(instance, enabled)` | Вкл/выкл объёмные здания на лету. |
1158
+ | `setLayer(instance, id, on, params?)` | Включить/выключить слой платформы. |
1159
+ | `getLayerState(instance, id)` | Снимок состояния одного слоя. |
1160
+ | `getLayers(instance)` | Снимок всех слоёв. |
1161
+ | `onLayers(instance, callback)` | Подписка на изменения слоёв; возвращает отписку. |
1162
+ | `refreshLayers(instance)` | Пере-применить волю клиента ко всем слоям. |
1163
+ | `getIndoorLevels(instance)` | Этажи, найденные в текущем виде карты. |
1164
+ | `setIndoorLevel(instance, level)` | Переключить этаж (0 — первый наземный). |
1165
+ | `refreshIndoor(instance)` | Перечитать планы этажей. |
1166
+ | `showPlace(instance, lon, lat, level?, zoom?)` | Показать объект и открыть его этаж. |
1167
+ | `onBuildingClick(instance, callback)` | Клик по зданию. |
1168
+ | `selectBuilding(instance, id, style?)` | Выделить здание по `osm_id`. |
1169
+ | `clearSelection(instance)` | Снять выделение. |
1170
+ | `selectedBuilding(instance)` | Идентификатор выделенного здания или `null`. |
1171
+ | `setSelectionStyle(instance, style)` | Облик выделения. |
1172
+ | `onRoadClick(instance, callback)` | Клик по дороге. |
1173
+ | `roadAt(instance, point, tolPx?)` | Дорога под точкой холста. |
1174
+ | `destroy(instance)` | Полностью удаляет карту. |
1175
+ | `loadKeyFromScriptUrl()` | Читает `apikey` из URL SDK скрипта. |
1176
+ | `loadLanguageFromScriptUrl()` | Читает `lang` из URL SDK скрипта. |
1145
1177
 
1146
1178
  ## CameraController
1147
1179
 
@@ -1372,19 +1404,19 @@ const measureTool = new MeasureTool(map, {
1372
1404
 
1373
1405
  ### Методы
1374
1406
 
1375
- | Метод | Описание |
1376
- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
1377
- | `start(mode?)` | Включает инструмент и начинает/продолжает рисование в указанном режиме. |
1378
- | `stop()` | Выключает инструмент, прячет активный бейдж. Сохраненные фигуры остаются на карте. |
1379
- | `setMode(mode)` | Переключает режим. Если фигура уже рисуется — её точки сохраняются, меняется только тип (линия ⇄ полигон), как в Яндекс.Картах. |
1380
- | `finishDraft()` | Завершает текущую фигуру (если валидна — от 2 точек для линии, от 3 для полигона) и начинает новую. |
1381
- | `removeShape(shapeId)` | Удаляет фигуру (черновик или уже сохраненную) целиком. |
1382
- | `removePoint(shapeId, pointId)` | Удаляет одну точку фигуры. |
1383
- | `clearAll()` | Удаляет все фигуры и черновик. |
1384
- | `getState()` | Возвращает текущий `MeasureState` (снимок, без подписки). |
1407
+ | Метод | Описание |
1408
+ | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1409
+ | `start(mode?)` | Включает инструмент и начинает/продолжает рисование в указанном режиме. |
1410
+ | `stop()` | Выключает инструмент, прячет активный бейдж. Сохраненные фигуры остаются на карте. |
1411
+ | `setMode(mode)` | Переключает режим. Если фигура уже рисуется — её точки сохраняются, меняется только тип (линия ⇄ полигон), как в Яндекс.Картах. |
1412
+ | `finishDraft()` | Завершает текущую фигуру (если валидна — от 2 точек для линии, от 3 для полигона) и начинает новую. |
1413
+ | `removeShape(shapeId)` | Удаляет фигуру (черновик или уже сохраненную) целиком. |
1414
+ | `removePoint(shapeId, pointId)` | Удаляет одну точку фигуры. |
1415
+ | `clearAll()` | Удаляет все фигуры и черновик. |
1416
+ | `getState()` | Возвращает текущий `MeasureState` (снимок, без подписки). |
1385
1417
  | `setStyleOptions(style)` | Обновляет палитру (частично, `Partial<MeasureStyleOptions>`) без пересоздания инструмента: перекрашивает существующие слои и бейджи. Нужен при смене темы карты. |
1386
- | `refresh()` | Пересоздает источники/слои и перерисовывает фигуры. Инструмент делает это сам после `setStyle()`; метод оставлен как страховка. |
1387
- | `destroy()` | Полностью снимает слои, обработчики и DOM-бейджи. Вызывать при размонтировании. Повторный вызов безопасен. |
1418
+ | `refresh()` | Пересоздает источники/слои и перерисовывает фигуры. Инструмент делает это сам после `setStyle()`; метод оставлен как страховка. |
1419
+ | `destroy()` | Полностью снимает слои, обработчики и DOM-бейджи. Вызывать при размонтировании. Повторный вызов безопасен. |
1388
1420
 
1389
1421
  ### Смена стиля карты (тема, язык)
1390
1422
 
@@ -1437,7 +1469,13 @@ interface MeasureShape {
1437
1469
  Сервисы работают независимо от карты: их можно вызывать без `MahalMap.create()`. Токен передаётся аргументом в каждый вызов — сохранённый через `keyUtils.saveKey()` map token для них не используется.
1438
1470
 
1439
1471
  ```ts
1440
- import { Search, SearchPoi, SearchByLocation, CheckJSApi, Router } from "mahal_map";
1472
+ import {
1473
+ Search,
1474
+ SearchPoi,
1475
+ SearchByLocation,
1476
+ CheckJSApi,
1477
+ Router,
1478
+ } from "mahal_map";
1441
1479
  ```
1442
1480
 
1443
1481
  ### `Search(text, token, additionalParam?)`
@@ -1452,13 +1490,13 @@ const results = await Search("Рудаки 33", token, {
1452
1490
  });
1453
1491
  ```
1454
1492
 
1455
- | Параметр | Тип | Описание |
1456
- | -------- | --- | -------- |
1457
- | `text` | `string` | Строка поиска. |
1458
- | `token` | `string` | Токен сервиса. Обязателен, иначе `[MahalMap SDK] Search token is required`. |
1459
- | `additionalParam.lat` / `.lng` | `string` | Точка для сортировки результатов по удалённости. |
1460
- | `additionalParam.limit` | `number` | Максимум результатов. |
1461
- | `additionalParam.type` | `string` | Фильтр по типу объекта. |
1493
+ | Параметр | Тип | Описание |
1494
+ | ------------------------------ | -------- | --------------------------------------------------------------------------- |
1495
+ | `text` | `string` | Строка поиска. |
1496
+ | `token` | `string` | Токен сервиса. Обязателен, иначе `[MahalMap SDK] Search token is required`. |
1497
+ | `additionalParam.lat` / `.lng` | `string` | Точка для сортировки результатов по удалённости. |
1498
+ | `additionalParam.limit` | `number` | Максимум результатов. |
1499
+ | `additionalParam.type` | `string` | Фильтр по типу объекта. |
1462
1500
 
1463
1501
  Возвращает `ISearchResponse[]`.
1464
1502
 
@@ -1467,7 +1505,11 @@ const results = await Search("Рудаки 33", token, {
1467
1505
  Поиск POI (организации, объекты). Сигнатура и дебаунс те же, что у `Search`, таймер отдельный — параллельный ввод в двух полях не перебивает запросы друг друга.
1468
1506
 
1469
1507
  ```ts
1470
- const places = await SearchPoi("кафе", token, { lat: "38.5598", lng: "68.7870", limit: 20 });
1508
+ const places = await SearchPoi("кафе", token, {
1509
+ lat: "38.5598",
1510
+ lng: "68.7870",
1511
+ limit: 20,
1512
+ });
1471
1513
  ```
1472
1514
 
1473
1515
  Возвращает `ISearchResponse[]`.
@@ -1484,12 +1526,12 @@ const res = await SearchByLocation({
1484
1526
  });
1485
1527
  ```
1486
1528
 
1487
- | Поле | Тип | Обязательное |
1488
- | ---- | --- | ------------ |
1489
- | `lat` | `string \| number` | да |
1490
- | `lng` | `string \| number` | да |
1491
- | `token` | `string` | да |
1492
- | `type` | `string` | нет |
1529
+ | Поле | Тип | Обязательное |
1530
+ | ------- | ------------------ | ------------ |
1531
+ | `lat` | `string \| number` | да |
1532
+ | `lng` | `string \| number` | да |
1533
+ | `token` | `string` | да |
1534
+ | `type` | `string` | нет |
1493
1535
 
1494
1536
  ### `CheckJSApi(token)`
1495
1537
 
@@ -1522,11 +1564,11 @@ const routes = await Router(
1522
1564
  );
1523
1565
  ```
1524
1566
 
1525
- | Параметр | Тип | Описание |
1526
- | -------- | --- | -------- |
1527
- | `points` | `number[][]` | Точки в формате `[lng, lat]`. |
1528
- | `typeData` | `string` | `"geojson"` — декодирует polyline в массив координат. Другое значение оставляет `geometry` строкой polyline. |
1529
- | `token` | `string` | Токен сервиса. |
1567
+ | Параметр | Тип | Описание |
1568
+ | ---------- | ------------ | ------------------------------------------------------------------------------------------------------------ |
1569
+ | `points` | `number[][]` | Точки в формате `[lng, lat]`. |
1570
+ | `typeData` | `string` | `"geojson"` — декодирует polyline в массив координат. Другое значение оставляет `geometry` строкой polyline. |
1571
+ | `token` | `string` | Токен сервиса. |
1530
1572
 
1531
1573
  Возвращает `IRoute[]`.
1532
1574
 
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as maplibre_gl from 'maplibre-gl';
1
2
  import { Map, FlyToOptions, Marker } from 'maplibre-gl';
2
3
 
3
4
  declare class CameraController {
@@ -263,10 +264,13 @@ type Maps3DCtor = (new (options: IMaps3DLayerOptions) => IMaps3DLayer) & {
263
264
  styleUrl?(style?: string, base?: string): string;
264
265
  /** Подключение к уже созданной карте; возвращает экземпляр с `ready`. */
265
266
  enhance?(map: Map, options?: IMaps3DLayerOptions): IMaps3DLayer;
266
- /** MapLibre с платформы вместе со своим воркером. */
267
+ /**
268
+ * MapLibre с платформы вместе со своим воркером. Возвращает то же, что
269
+ * `import * as maplibregl from "maplibre-gl"` — декларации гарантирует peerDependency.
270
+ */
267
271
  maplibre?(options?: {
268
272
  base?: string;
269
- }): Promise<unknown>;
273
+ }): Promise<typeof maplibre_gl>;
270
274
  readonly maplibreVersion?: string;
271
275
  };
272
276
 
@@ -456,6 +460,7 @@ declare class MahalMap {
456
460
  private maps3dReady?;
457
461
  private buildingsEnabled;
458
462
  private workerCheckTimer?;
463
+ private styleChangeHandler?;
459
464
  private constructor();
460
465
  private static getInstanceKey;
461
466
  private static normalizeLanguage;
@@ -542,7 +547,21 @@ declare class MahalMap {
542
547
  * Без Maps3D менять нечего — карта на запасном стиле, у него варианта по теме нет.
543
548
  */
544
549
  setStyle(theme: Theme): void;
545
- private refreshLayersOnStyleLoad;
550
+ /**
551
+ * Адрес стиля по имени темы. mapOptions() — основной контракт (есть с 0.5.0);
552
+ * styleUrl остаётся запасным путём для сборок, где mapOptions ещё нет.
553
+ * Раньше здесь был только styleUrl, и сборка с одним mapOptions() тему не меняла.
554
+ */
555
+ private resolvePlatformStyle;
556
+ /**
557
+ * Полная смена стиля уносит слои Maps3D вместе с ним — реестр умеет вернуть волю
558
+ * клиента, но только когда новый стиль уже загружен.
559
+ *
560
+ * Слушаем styledata, а не style.load: setStyle() идёт через дифф и style.load при
561
+ * этом не поднимает — с ним восстановление просто не случалось. styledata приходит
562
+ * многократно, поэтому ждём isStyleLoaded() и снимаем обработчик сами.
563
+ */
564
+ private refreshLayersOnStyleChange;
546
565
  /**
547
566
  * Язык подписей приходит из стиля платформы, отдельных URL по языкам больше нет —
548
567
  * метод только запоминает выбор для остальных сервисов SDK (поиск, роутинг).