mahal_map 2.0.2 → 2.1.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/README.md CHANGED
@@ -13,7 +13,7 @@ npm install mahal_map maplibre-gl @grammaps/maps3d-web
13
13
  Обе зависимости — `peerDependencies`, в бандл `mahal_map` они не входят. Библиотека их не импортирует: MapLibre и `Maps3D` приходят снаружи, аргументами `create()` либо через `window`.
14
14
 
15
15
  - `maplibre-gl` (`^6.10.0`) — обязателен всегда.
16
- - `@grammaps/maps3d-web` (>=0.5.0) — даёт стили, тайлы, объём, пробки, рельеф, планы этажей, клик по объектам. Помечен `optional`: без него карта поднимется на запасном векторном стиле, но 3D и слоёв платформы на ней не будет.
16
+ - `@grammaps/maps3d-web` (>=0.5.0; рекомендуется 0.8.0 — в ней наведение на здание и починенный пикинг клика) — даёт стили, тайлы, объём, пробки, рельеф, планы этажей, клик по объектам. Помечен `optional`: без него карта поднимется на запасном векторном стиле, но 3D и слоёв платформы на ней не будет.
17
17
 
18
18
  MapLibre можно не класть в свою сборку вовсе — платформа отдаёт согласованную версию вместе с веб-воркером:
19
19
 
@@ -334,11 +334,14 @@ MahalMap.create(
334
334
 
335
335
  Поля независимы, и это главная ловушка реестра:
336
336
 
337
- | Поле | Вопрос |
338
- | ----------- | ---------------------------- |
339
- | `wanted` | чего хочет приложение |
340
- | `available` | что позволяют стиль и данные |
341
- | `active` | что нарисовано прямо сейчас |
337
+ | Поле | Вопрос |
338
+ | ----------- | ------------------------------------------------- |
339
+ | `wanted` | чего хочет приложение |
340
+ | `available` | что позволяют стиль и данные |
341
+ | `active` | что нарисовано прямо сейчас (память SDK) |
342
+ | `rendered` | факт со стороны карты: слой есть в стиле и не погашен |
343
+
344
+ `rendered` появилось в Maps3D 0.8.0; у сборок постарше его нет (`undefined`). Расхождение `active !== rendered` означает, что внутренний признак SDK разошёлся с картой — это видно одной проверкой, без чтения минифицированной сборки.
342
345
 
343
346
  Слой может быть включён и при этом не нарисован — и это не ошибка:
344
347
 
@@ -495,7 +498,65 @@ map.roadAt({ x: 320, y: 240 });
495
498
  map.roadsNamed; // есть ли в текущем стиле названия дорог
496
499
  ```
497
500
 
498
- Подписываться можно сразу после `create()`, до готовности карты.
501
+ Подписываться можно сразу после `create()` даже когда слой ещё не поднят (`enable3D: false`). Подписка и облик выделения запоминаются и переигрываются, как только слой появится:
502
+
503
+ ```ts
504
+ const map = MahalMap.create({ container: "map", enable3D: false }, maplibregl, Maps3D);
505
+
506
+ map.onBuildingClick((b) => console.log(b?.props.osm_id));
507
+ map.setSelectionStyle({ color: "#e23b2f" });
508
+
509
+ map.toggle3DBuildings(true); // подписка и стиль выделения уже применены к новому слою
510
+ ```
511
+
512
+ ### Наведение на здание
513
+
514
+ Требует `@grammaps/maps3d-web` **0.8.0** и старше. Подсветку и курсор рисует сам SDK — приложение задаёт облик и получает уведомления.
515
+
516
+ ```ts
517
+ map.setHoverStyle({ color: "#6b9ed1", opacity: 0.3, cursor: "pointer" });
518
+
519
+ map.onBuildingHover((building) => {
520
+ if (!building) return; // курсор ушёл с домов
521
+ console.log(building.props.osm_id, building.height);
522
+ });
523
+ ```
524
+
525
+ Колбэк приходит **только в момент смены** дома под курсором, а не на каждое движение мыши.
526
+
527
+ Слежение включается самой подпиской: пока `onBuildingHover` не вызван, SDK курсор не трогает и сцену не разбирает. `onBuildingHover(null)` отписывает и гасит подсветку.
528
+
529
+ | Метод | Описание |
530
+ | --- | --- |
531
+ | `onBuildingHover(cb \| null)` | Подписка на наведение; `null` отписывает и гасит подсветку. |
532
+ | `setHoverStyle(s)` | Облик: `color`, `opacity`, `glow`, `durationMs`, `easing`, `cursor`. `cursor: null` — не трогать курсор. |
533
+ | `setHoverEnabled(on)` | Вкл/выкл наведение, не трогая подписку. |
534
+ | `hoverEnabled` | Включено ли наведение сейчас. |
535
+ | `hoverBuilding(id \| null)` | Навести программно — например, с наведения на строку списка. `false` — дома нет на карте. |
536
+ | `hoveredBuilding()` | Идентификатор дома под наведением или `null`. |
537
+
538
+ Слот наведения свой, отдельный от выделения: **выбор всегда главнее**, и на выбранном доме наведение не рисуется. Занимать `setSelectionStyle` ради подсветки под курсором, как приходилось до 0.8.0, больше не нужно.
539
+
540
+ #### Наведение с элементов интерфейса
541
+
542
+ Курсор стоит на строке списка, а не на карте:
543
+
544
+ ```ts
545
+ row.addEventListener("mouseenter", () => map.hoverBuilding(row.dataset.osmId!));
546
+ row.addEventListener("mouseleave", () => map.hoverBuilding(null));
547
+ ```
548
+
549
+ Следующее движение мыши по карте перебивает программное наведение — слежение владеет слотом, пока включено.
550
+
551
+ #### Где наведение выключают
552
+
553
+ Там, где подсветка мешает: режим рисования на карте, открытая карточка объекта, тач-устройство без курсора.
554
+
555
+ ```ts
556
+ map.setHoverEnabled(false); // подписка сохраняется
557
+ ```
558
+
559
+ Цену ограничивает сам SDK: разбор не чаще раза в кадр, пропускается во время движения карты и не трогает сцену, пока курсор на том же доме. Но разбор — это чтение пикселя обратно из GPU, поэтому на слабых устройствах наведение лучше не включать.
499
560
 
500
561
  #### Вкл/выкл 3D-здания на лету
501
562
 
@@ -1114,6 +1175,13 @@ MahalMap.clearSelection(map);
1114
1175
  MahalMap.onRoadClick(map, (road) => console.log(road?.name));
1115
1176
  MahalMap.roadAt(map, { x: 320, y: 240 });
1116
1177
 
1178
+ // Наведение на здание (Maps3D 0.8.0)
1179
+ MahalMap.onBuildingHover(map, (b) => console.log(b?.id));
1180
+ MahalMap.setHoverStyle(map, { color: "#6b9ed1", cursor: "pointer" });
1181
+ MahalMap.setHoverEnabled(map, false);
1182
+ MahalMap.hoverBuilding(map, 123456789);
1183
+ MahalMap.hoveredBuilding(map);
1184
+
1117
1185
  MahalMap.destroy(map);
1118
1186
  ```
1119
1187
 
@@ -1171,6 +1239,11 @@ MahalMap.setZoom(map, 14);
1171
1239
  | `setSelectionStyle(instance, style)` | Облик выделения. |
1172
1240
  | `onRoadClick(instance, callback)` | Клик по дороге. |
1173
1241
  | `roadAt(instance, point, tolPx?)` | Дорога под точкой холста. |
1242
+ | `onBuildingHover(instance, cb)` | Подписка на наведение (Maps3D 0.8.0); `null` отписывает. |
1243
+ | `setHoverStyle(instance, style)` | Облик наведения, включая CSS-курсор. |
1244
+ | `setHoverEnabled(instance, on)` | Вкл/выкл наведение, не трогая подписку. |
1245
+ | `hoverBuilding(instance, id)` | Навести на здание программно; `null` снимает. |
1246
+ | `hoveredBuilding(instance)` | Дом под наведением или `null`. |
1174
1247
  | `destroy(instance)` | Полностью удаляет карту. |
1175
1248
  | `loadKeyFromScriptUrl()` | Читает `apikey` из URL SDK скрипта. |
1176
1249
  | `loadLanguageFromScriptUrl()` | Читает `lang` из URL SDK скрипта. |
package/dist/index.d.mts CHANGED
@@ -91,6 +91,12 @@ interface IMaps3DLayerState {
91
91
  available: boolean;
92
92
  /** Что нарисовано прямо сейчас. Именно это поле показывает, включён слой на деле или нет. */
93
93
  active: boolean;
94
+ /**
95
+ * Факт со стороны карты: слой есть в стиле и не погашен. Появилось в 0.8.0.
96
+ * `active !== rendered` — расхождение внутреннего признака SDK с картой.
97
+ * У слоя, который не умеет ответить фактом, повторяет `active`; у сборок до 0.8.0 — undefined.
98
+ */
99
+ rendered?: boolean;
94
100
  /** Параметры слоя: у зданий — detail, у этажей — level, у рельефа — mode. */
95
101
  params: Record<string, unknown>;
96
102
  }
@@ -101,6 +107,15 @@ interface IMaps3DSelectionStyle {
101
107
  durationMs?: number;
102
108
  easing?: "ease-out" | "linear";
103
109
  }
110
+ /**
111
+ * Облик наведения. Появился в 0.8.0: до него подсветить дом под курсором можно было,
112
+ * только заняв единственный слот выделения. Теперь слот свой, и выбор всегда главнее —
113
+ * на выбранном доме наведение не рисуется.
114
+ */
115
+ interface IMaps3DHoverStyle extends IMaps3DSelectionStyle {
116
+ /** CSS-курсор над зданием. По умолчанию "pointer"; `null` — не трогать курсор вовсе. */
117
+ cursor?: string | null;
118
+ }
104
119
  interface IMaps3DRoadHit {
105
120
  name: string;
106
121
  nameRu?: string;
@@ -175,9 +190,12 @@ interface IMaps3DBuildingsController {
175
190
  }
176
191
  interface IMaps3DBuildingClickInfo {
177
192
  id: string | number;
193
+ /** Атрибуты объекта; `props.osm_id` — идентификатор, который не меняется. */
194
+ props: Record<string, unknown>;
195
+ /** Высота здания в метрах. */
196
+ height: number;
197
+ /** Порядковый номер внутри сцены. Живёт до ближайшей пересборки геометрии. */
178
198
  index?: number;
179
- height?: number;
180
- props?: Record<string, unknown>;
181
199
  [key: string]: unknown;
182
200
  }
183
201
  interface IMaps3DObjectsLightOptions {
@@ -210,6 +228,12 @@ interface IMaps3DLayer {
210
228
  clearSelection?(): void;
211
229
  selectedBuilding?(): number | string | null;
212
230
  setSelectionStyle?(style: IMaps3DSelectionStyle): void;
231
+ onBuildingHover?(callback: ((info: IMaps3DBuildingClickInfo | null) => void) | null): void;
232
+ setHoverEnabled?(enabled: boolean): void;
233
+ readonly hoverEnabled?: boolean;
234
+ setHoverStyle?(style: IMaps3DHoverStyle): void;
235
+ hoverBuilding?(id: number | string | null): boolean;
236
+ hoveredBuilding?(): number | string | null;
213
237
  onRoadClick?(callback: (hit: IMaps3DRoadHit | null) => void): void;
214
238
  roadAt?(point: {
215
239
  x: number;
@@ -461,6 +485,13 @@ declare class MahalMap {
461
485
  private buildingsEnabled;
462
486
  private workerCheckTimer?;
463
487
  private styleChangeHandler?;
488
+ private pendingBuildingClick?;
489
+ private pendingRoadClick?;
490
+ private pendingSelectionStyle?;
491
+ private pendingLayerSubscribers;
492
+ private pendingBuildingHover?;
493
+ private pendingHoverStyle?;
494
+ private pendingHoverEnabled?;
464
495
  private constructor();
465
496
  private static getInstanceKey;
466
497
  private static normalizeLanguage;
@@ -533,6 +564,11 @@ declare class MahalMap {
533
564
  x: number;
534
565
  y: number;
535
566
  }, tolerancePx?: number): IMaps3DRoadHit | null;
567
+ static onBuildingHover(instance: MahalMap, callback: ((info: IMaps3DBuildingClickInfo | null) => void) | null): void;
568
+ static setHoverEnabled(instance: MahalMap, enabled: boolean): void;
569
+ static setHoverStyle(instance: MahalMap, style: IMaps3DHoverStyle): void;
570
+ static hoverBuilding(instance: MahalMap, id: number | string | null): boolean;
571
+ static hoveredBuilding(instance: MahalMap): string | number | null;
536
572
  static setLanguage(instance: MahalMap, lang: MapLanguage): void;
537
573
  static setCenter(instance: MahalMap, center: [number, number]): void;
538
574
  static setZoom(instance: MahalMap, zoom: number): void;
@@ -592,7 +628,10 @@ declare class MahalMap {
592
628
  getLayerState(id: Maps3DLayerId): IMaps3DLayerState | null;
593
629
  /** Снимок всех слоёв — по нему приложение рисует свою панель. */
594
630
  getLayers(): IMaps3DLayerState[];
595
- /** Подписка на изменения слоёв. Возвращает отписку (no-op, если слоя нет). */
631
+ /**
632
+ * Подписка на изменения слоёв. Возвращает отписку. Работает и до появления слоя:
633
+ * подписка переиграется при его подключении, а отписка снимет её в любом случае.
634
+ */
596
635
  onLayers(callback: (state: IMaps3DLayerState) => void): () => void;
597
636
  /** Пере-применить волю клиента ко всем слоям — после полной смены стиля. */
598
637
  refreshLayers(): void;
@@ -608,14 +647,21 @@ declare class MahalMap {
608
647
  * и метка окажется в чужом зале.
609
648
  */
610
649
  showPlace(lon: number, lat: number, level?: number | null, zoom?: number): void;
611
- /** Клик по зданию: { id, height, props } либо null. Повторный вызов заменяет обработчик. */
650
+ /**
651
+ * Клик по зданию: { id, height, props } либо null. Повторный вызов заменяет обработчик.
652
+ * Подписываться можно сразу после create(), даже когда слой ещё не поднят
653
+ * (`enable3D: false`) — подписка переиграется, как только слой появится.
654
+ */
612
655
  onBuildingClick(callback: (info: IMaps3DBuildingClickInfo | null) => void): void;
613
656
  /** Выделить здание по osm_id. `false` — здания сейчас нет в загруженных данных. */
614
657
  selectBuilding(id: number | string | null, style?: IMaps3DSelectionStyle): boolean;
615
658
  clearSelection(): void;
616
659
  selectedBuilding(): number | string | null;
617
660
  setSelectionStyle(style: IMaps3DSelectionStyle): void;
618
- /** Клик по дороге. Приходит независимо от клика по зданию — приоритет решает приложение. */
661
+ /**
662
+ * Клик по дороге. Приходит независимо от клика по зданию — приоритет решает приложение.
663
+ * Как и onBuildingClick, переживает отсутствие слоя на момент подписки.
664
+ */
619
665
  onRoadClick(callback: (hit: IMaps3DRoadHit | null) => void): void;
620
666
  /** Дорога под точкой холста. Допуск по умолчанию — 12 px. */
621
667
  roadAt(point: {
@@ -624,11 +670,45 @@ declare class MahalMap {
624
670
  }, tolerancePx?: number): IMaps3DRoadHit | null;
625
671
  /** Есть ли в текущем стиле названия дорог. Нет — roadAt() всегда вернёт null. */
626
672
  get roadsNamed(): boolean;
673
+ /**
674
+ * Подписаться на наведение. Колбэк приходит только в момент смены дома под курсором,
675
+ * а не на каждое движение мыши. `null` отписывает и гасит подсветку.
676
+ *
677
+ * Слежение за мышью включается самой подпиской: без неё SDK курсор не трогает и
678
+ * разбор сцены не делает.
679
+ */
680
+ onBuildingHover(callback: ((info: IMaps3DBuildingClickInfo | null) => void) | null): void;
681
+ /**
682
+ * Включить/выключить наведение, не трогая подписку. Нужно там, где подсветка мешает:
683
+ * режим рисования, открытая карточка объекта, тач-устройство без курсора.
684
+ */
685
+ setHoverEnabled(enabled: boolean): void;
686
+ /** Включено ли наведение прямо сейчас. */
687
+ get hoverEnabled(): boolean;
688
+ /** Облик наведения: цвет, плотность, свечение, длительность и CSS-курсор. */
689
+ setHoverStyle(style: IMaps3DHoverStyle): void;
690
+ /**
691
+ * Навести на здание программно — например, когда курсор стоит на строке списка.
692
+ * Идентификатор тот же, что у selectBuilding. `null` снимает наведение.
693
+ *
694
+ * Следующее движение мыши по карте перебивает программное наведение.
695
+ *
696
+ * @returns `false`, если такого дома сейчас на карте нет.
697
+ */
698
+ hoverBuilding(id: number | string | null): boolean;
699
+ /** Идентификатор дома под наведением или `null`. */
700
+ hoveredBuilding(): number | string | null;
627
701
  /**
628
702
  * Создаёт слой Maps3D. `buildings` не форсируем в `true`: с 0.7.x видимостью объёма
629
703
  * заведует реестр слоёв, а опции облика зданий приходят из options.maps3d как есть.
630
704
  */
631
705
  private createMaps3DLayer;
706
+ /**
707
+ * Переигрывает волю клиента на только что подключённом слое: подписки на клики,
708
+ * облик выделения и подписчиков реестра. Нужно, когда карта создана без слоя
709
+ * (`enable3D: false`) — тогда всё это было сказано до его появления.
710
+ */
711
+ private applyPendingSubscriptions;
632
712
  private attachMaps3DLayer;
633
713
  /**
634
714
  * Освобождает слой Maps3D одним доступным методом (destroy(), иначе remove()) и ровно один
@@ -936,4 +1016,4 @@ declare namespace index {
936
1016
  export { index_checkCoordinates as checkCoordinates, index_debounce as debounce, index_geojsonPolyline as geojsonPolyline, index_geometryPolyline as geometryPolyline, index_trimValue as trimValue };
937
1017
  }
938
1018
 
939
- 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 };
1019
+ export { CheckJSApi, type IAdditionalParamType, type ICheckJSApiParam, type ICheckJSApiResponse, type IMahalMapOptions, type IMapMarker, type IMaps3DBuildingClickInfo, type IMaps3DBuildingsController, type IMaps3DBuildingsOptions, type IMaps3DClosuresOptions, type IMaps3DDiagnostics, type IMaps3DHoverStyle, 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 };
package/dist/index.d.ts CHANGED
@@ -91,6 +91,12 @@ interface IMaps3DLayerState {
91
91
  available: boolean;
92
92
  /** Что нарисовано прямо сейчас. Именно это поле показывает, включён слой на деле или нет. */
93
93
  active: boolean;
94
+ /**
95
+ * Факт со стороны карты: слой есть в стиле и не погашен. Появилось в 0.8.0.
96
+ * `active !== rendered` — расхождение внутреннего признака SDK с картой.
97
+ * У слоя, который не умеет ответить фактом, повторяет `active`; у сборок до 0.8.0 — undefined.
98
+ */
99
+ rendered?: boolean;
94
100
  /** Параметры слоя: у зданий — detail, у этажей — level, у рельефа — mode. */
95
101
  params: Record<string, unknown>;
96
102
  }
@@ -101,6 +107,15 @@ interface IMaps3DSelectionStyle {
101
107
  durationMs?: number;
102
108
  easing?: "ease-out" | "linear";
103
109
  }
110
+ /**
111
+ * Облик наведения. Появился в 0.8.0: до него подсветить дом под курсором можно было,
112
+ * только заняв единственный слот выделения. Теперь слот свой, и выбор всегда главнее —
113
+ * на выбранном доме наведение не рисуется.
114
+ */
115
+ interface IMaps3DHoverStyle extends IMaps3DSelectionStyle {
116
+ /** CSS-курсор над зданием. По умолчанию "pointer"; `null` — не трогать курсор вовсе. */
117
+ cursor?: string | null;
118
+ }
104
119
  interface IMaps3DRoadHit {
105
120
  name: string;
106
121
  nameRu?: string;
@@ -175,9 +190,12 @@ interface IMaps3DBuildingsController {
175
190
  }
176
191
  interface IMaps3DBuildingClickInfo {
177
192
  id: string | number;
193
+ /** Атрибуты объекта; `props.osm_id` — идентификатор, который не меняется. */
194
+ props: Record<string, unknown>;
195
+ /** Высота здания в метрах. */
196
+ height: number;
197
+ /** Порядковый номер внутри сцены. Живёт до ближайшей пересборки геометрии. */
178
198
  index?: number;
179
- height?: number;
180
- props?: Record<string, unknown>;
181
199
  [key: string]: unknown;
182
200
  }
183
201
  interface IMaps3DObjectsLightOptions {
@@ -210,6 +228,12 @@ interface IMaps3DLayer {
210
228
  clearSelection?(): void;
211
229
  selectedBuilding?(): number | string | null;
212
230
  setSelectionStyle?(style: IMaps3DSelectionStyle): void;
231
+ onBuildingHover?(callback: ((info: IMaps3DBuildingClickInfo | null) => void) | null): void;
232
+ setHoverEnabled?(enabled: boolean): void;
233
+ readonly hoverEnabled?: boolean;
234
+ setHoverStyle?(style: IMaps3DHoverStyle): void;
235
+ hoverBuilding?(id: number | string | null): boolean;
236
+ hoveredBuilding?(): number | string | null;
213
237
  onRoadClick?(callback: (hit: IMaps3DRoadHit | null) => void): void;
214
238
  roadAt?(point: {
215
239
  x: number;
@@ -461,6 +485,13 @@ declare class MahalMap {
461
485
  private buildingsEnabled;
462
486
  private workerCheckTimer?;
463
487
  private styleChangeHandler?;
488
+ private pendingBuildingClick?;
489
+ private pendingRoadClick?;
490
+ private pendingSelectionStyle?;
491
+ private pendingLayerSubscribers;
492
+ private pendingBuildingHover?;
493
+ private pendingHoverStyle?;
494
+ private pendingHoverEnabled?;
464
495
  private constructor();
465
496
  private static getInstanceKey;
466
497
  private static normalizeLanguage;
@@ -533,6 +564,11 @@ declare class MahalMap {
533
564
  x: number;
534
565
  y: number;
535
566
  }, tolerancePx?: number): IMaps3DRoadHit | null;
567
+ static onBuildingHover(instance: MahalMap, callback: ((info: IMaps3DBuildingClickInfo | null) => void) | null): void;
568
+ static setHoverEnabled(instance: MahalMap, enabled: boolean): void;
569
+ static setHoverStyle(instance: MahalMap, style: IMaps3DHoverStyle): void;
570
+ static hoverBuilding(instance: MahalMap, id: number | string | null): boolean;
571
+ static hoveredBuilding(instance: MahalMap): string | number | null;
536
572
  static setLanguage(instance: MahalMap, lang: MapLanguage): void;
537
573
  static setCenter(instance: MahalMap, center: [number, number]): void;
538
574
  static setZoom(instance: MahalMap, zoom: number): void;
@@ -592,7 +628,10 @@ declare class MahalMap {
592
628
  getLayerState(id: Maps3DLayerId): IMaps3DLayerState | null;
593
629
  /** Снимок всех слоёв — по нему приложение рисует свою панель. */
594
630
  getLayers(): IMaps3DLayerState[];
595
- /** Подписка на изменения слоёв. Возвращает отписку (no-op, если слоя нет). */
631
+ /**
632
+ * Подписка на изменения слоёв. Возвращает отписку. Работает и до появления слоя:
633
+ * подписка переиграется при его подключении, а отписка снимет её в любом случае.
634
+ */
596
635
  onLayers(callback: (state: IMaps3DLayerState) => void): () => void;
597
636
  /** Пере-применить волю клиента ко всем слоям — после полной смены стиля. */
598
637
  refreshLayers(): void;
@@ -608,14 +647,21 @@ declare class MahalMap {
608
647
  * и метка окажется в чужом зале.
609
648
  */
610
649
  showPlace(lon: number, lat: number, level?: number | null, zoom?: number): void;
611
- /** Клик по зданию: { id, height, props } либо null. Повторный вызов заменяет обработчик. */
650
+ /**
651
+ * Клик по зданию: { id, height, props } либо null. Повторный вызов заменяет обработчик.
652
+ * Подписываться можно сразу после create(), даже когда слой ещё не поднят
653
+ * (`enable3D: false`) — подписка переиграется, как только слой появится.
654
+ */
612
655
  onBuildingClick(callback: (info: IMaps3DBuildingClickInfo | null) => void): void;
613
656
  /** Выделить здание по osm_id. `false` — здания сейчас нет в загруженных данных. */
614
657
  selectBuilding(id: number | string | null, style?: IMaps3DSelectionStyle): boolean;
615
658
  clearSelection(): void;
616
659
  selectedBuilding(): number | string | null;
617
660
  setSelectionStyle(style: IMaps3DSelectionStyle): void;
618
- /** Клик по дороге. Приходит независимо от клика по зданию — приоритет решает приложение. */
661
+ /**
662
+ * Клик по дороге. Приходит независимо от клика по зданию — приоритет решает приложение.
663
+ * Как и onBuildingClick, переживает отсутствие слоя на момент подписки.
664
+ */
619
665
  onRoadClick(callback: (hit: IMaps3DRoadHit | null) => void): void;
620
666
  /** Дорога под точкой холста. Допуск по умолчанию — 12 px. */
621
667
  roadAt(point: {
@@ -624,11 +670,45 @@ declare class MahalMap {
624
670
  }, tolerancePx?: number): IMaps3DRoadHit | null;
625
671
  /** Есть ли в текущем стиле названия дорог. Нет — roadAt() всегда вернёт null. */
626
672
  get roadsNamed(): boolean;
673
+ /**
674
+ * Подписаться на наведение. Колбэк приходит только в момент смены дома под курсором,
675
+ * а не на каждое движение мыши. `null` отписывает и гасит подсветку.
676
+ *
677
+ * Слежение за мышью включается самой подпиской: без неё SDK курсор не трогает и
678
+ * разбор сцены не делает.
679
+ */
680
+ onBuildingHover(callback: ((info: IMaps3DBuildingClickInfo | null) => void) | null): void;
681
+ /**
682
+ * Включить/выключить наведение, не трогая подписку. Нужно там, где подсветка мешает:
683
+ * режим рисования, открытая карточка объекта, тач-устройство без курсора.
684
+ */
685
+ setHoverEnabled(enabled: boolean): void;
686
+ /** Включено ли наведение прямо сейчас. */
687
+ get hoverEnabled(): boolean;
688
+ /** Облик наведения: цвет, плотность, свечение, длительность и CSS-курсор. */
689
+ setHoverStyle(style: IMaps3DHoverStyle): void;
690
+ /**
691
+ * Навести на здание программно — например, когда курсор стоит на строке списка.
692
+ * Идентификатор тот же, что у selectBuilding. `null` снимает наведение.
693
+ *
694
+ * Следующее движение мыши по карте перебивает программное наведение.
695
+ *
696
+ * @returns `false`, если такого дома сейчас на карте нет.
697
+ */
698
+ hoverBuilding(id: number | string | null): boolean;
699
+ /** Идентификатор дома под наведением или `null`. */
700
+ hoveredBuilding(): number | string | null;
627
701
  /**
628
702
  * Создаёт слой Maps3D. `buildings` не форсируем в `true`: с 0.7.x видимостью объёма
629
703
  * заведует реестр слоёв, а опции облика зданий приходят из options.maps3d как есть.
630
704
  */
631
705
  private createMaps3DLayer;
706
+ /**
707
+ * Переигрывает волю клиента на только что подключённом слое: подписки на клики,
708
+ * облик выделения и подписчиков реестра. Нужно, когда карта создана без слоя
709
+ * (`enable3D: false`) — тогда всё это было сказано до его появления.
710
+ */
711
+ private applyPendingSubscriptions;
632
712
  private attachMaps3DLayer;
633
713
  /**
634
714
  * Освобождает слой Maps3D одним доступным методом (destroy(), иначе remove()) и ровно один
@@ -936,4 +1016,4 @@ declare namespace index {
936
1016
  export { index_checkCoordinates as checkCoordinates, index_debounce as debounce, index_geojsonPolyline as geojsonPolyline, index_geometryPolyline as geometryPolyline, index_trimValue as trimValue };
937
1017
  }
938
1018
 
939
- 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 };
1019
+ export { CheckJSApi, type IAdditionalParamType, type ICheckJSApiParam, type ICheckJSApiResponse, type IMahalMapOptions, type IMapMarker, type IMaps3DBuildingClickInfo, type IMaps3DBuildingsController, type IMaps3DBuildingsOptions, type IMaps3DClosuresOptions, type IMaps3DDiagnostics, type IMaps3DHoverStyle, 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 };