mahal_map 1.5.2 → 1.5.4

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
@@ -1,565 +1,571 @@
1
- # Mahal Map
2
-
3
- Mahal Map - JavaScript/TypeScript SDK для работы с картой Mahal поверх MapLibre GL JS.
4
-
5
- Документация ниже описывает только открытые функции карты: создание карты, управление инстансами, стили, язык, камера, маркеры и browser SDK.
6
-
7
- ## Установка
8
-
9
- ```sh
10
- npm install mahal_map maplibre-gl
11
- ```
12
-
13
- `maplibre-gl` является peer dependency. Его нужно установить в приложении или подключить отдельным browser script перед SDK.
14
-
15
- ## Быстрый старт через NPM
16
-
17
- ```ts
18
- import maplibregl from "maplibre-gl";
19
- import "maplibre-gl/dist/maplibre-gl.css";
20
- import { MahalMap } from "mahal_map";
21
-
22
- const map = MahalMap.create(
23
- {
24
- container: "map",
25
- center: [69.624024, 40.279687],
26
- zoom: 12,
27
- theme: "light",
28
- },
29
- maplibregl,
30
- );
31
- ```
32
-
33
- Контейнер должен существовать в HTML:
34
-
35
- ```html
36
- <div id="map" style="width: 100%; height: 500px"></div>
37
- ```
38
-
39
- ## Быстрый старт через Browser SDK
40
-
41
- Сначала подключите MapLibre, затем `mahal_map.sdk.js`:
42
-
43
- ```html
44
- <link
45
- rel="stylesheet"
46
- href="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.css"
47
- />
48
- <script src="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.js"></script>
49
- <script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_API_KEY"></script>
50
- ```
51
-
52
- После этого глобальный объект `MahalMap` доступен в `window`:
53
-
54
- ```html
55
- <div id="map" style="width: 100%; height: 500px"></div>
56
-
57
- <script>
58
- const map = MahalMap.create({
59
- container: "map",
60
- center: [69.624024, 40.279687],
61
- zoom: 12,
62
- });
63
- </script>
64
- ```
65
-
66
- ## Язык стиля карты
67
-
68
- По умолчанию используется таджикский стиль без query-параметра:
69
-
70
- ```txt
71
- https://mtile.gram.tj/custom-styles/mapstyle.json
72
- https://mtile.gram.tj/custom-styles/dark-style.json
73
- ```
74
-
75
- Для русского языка SDK добавляет `?lang=ru` к стандартным стилям:
76
-
77
- ```txt
78
- https://mtile.gram.tj/custom-styles/mapstyle.json?lang=ru
79
- https://mtile.gram.tj/custom-styles/dark-style.json?lang=ru
80
- ```
81
-
82
- Через NPM язык можно передать при создании карты:
83
-
84
- ```ts
85
- const map = MahalMap.create(
86
- {
87
- container: "map",
88
- lang: "ru",
89
- theme: "dark",
90
- },
91
- maplibregl,
92
- );
93
- ```
94
-
95
- Через browser SDK язык можно передать в URL скрипта:
96
-
97
- ```html
98
- <script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_API_KEY&lang=ru"></script>
99
- ```
100
-
101
- Если `lang` не передан или передан `lang=tj`, стили остаются без параметра.
102
-
103
- ## Параметры создания карты
104
-
105
- `MahalMap.create(options, maplibreObject?)`
106
-
107
- ```ts
108
- interface IMahalMapOptions {
109
- container?: string | HTMLElement;
110
- style?: string;
111
- theme?: "dark" | "light";
112
- lang?: "tj" | "ru";
113
- center?: [number, number];
114
- zoom?: number;
115
- autoAddVectorSource?: boolean;
116
- }
117
- ```
118
-
119
- | Параметр | Тип | Описание |
120
- | --- | --- | --- |
121
- | `container` | `string \| HTMLElement` | ID контейнера или DOM-элемент. Если не передан, используется `"map"`. |
122
- | `style` | `string` | Пользовательский URL стиля MapLibre. Если передан, `theme` и `lang` не меняют URL стиля. |
123
- | `theme` | `"dark" \| "light"` | Тема стандартного стиля. По умолчанию используется `light`. |
124
- | `lang` | `"tj" \| "ru"` | Язык стандартного стиля. `tj` оставляет URL без query, `ru` добавляет `?lang=ru`. |
125
- | `center` | `[number, number]` | Центр карты в формате `[lng, lat]`. |
126
- | `zoom` | `number` | Начальный zoom. |
127
- | `autoAddVectorSource` | `boolean` | Использует встроенный vector style и блокирует смену стандартного стиля через `setStyle`. |
128
-
129
- ## MahalMap
130
-
131
- `MahalMap` - основной класс карты. Конструктор закрыт, карту нужно создавать через `MahalMap.create()`.
132
-
133
- ### `MahalMap.create(options, maplibreObject?)`
134
-
135
- Создает новый инстанс карты и сохраняет его по ключу `container`.
136
-
137
- ```ts
138
- const map = MahalMap.create(
139
- {
140
- container: "map",
141
- center: [69.624024, 40.279687],
142
- zoom: 12,
143
- theme: "light",
144
- lang: "tj",
145
- },
146
- maplibregl,
147
- );
148
- ```
149
-
150
- В NPM-версии второй аргумент `maplibreObject` рекомендуется передавать явно. В browser SDK он берется из `window.maplibregl`.
151
-
152
- ### `MahalMap.onReady(container, callback)`
153
-
154
- Вызывает `callback`, когда карта создана и MapLibre завершил загрузку.
155
-
156
- ```ts
157
- MahalMap.onReady("map", (maplibreMap) => {
158
- maplibreMap.resize();
159
- });
160
- ```
161
-
162
- `callback` получает нативный `Map` объект из MapLibre GL JS.
163
-
164
- ### `MahalMap.getInstance(container)`
165
-
166
- Возвращает ранее созданный инстанс карты по ключу контейнера.
167
-
168
- ```ts
169
- const map = MahalMap.getInstance("map");
170
- map.setZoom(14);
171
- ```
172
-
173
- Если инстанс не найден, будет выброшена ошибка.
174
-
175
- ### `MahalMap.hasInstance(container)`
176
-
177
- Проверяет, существует ли карта с таким ключом контейнера.
178
-
179
- ```ts
180
- if (MahalMap.hasInstance("map")) {
181
- const map = MahalMap.getInstance("map");
182
- }
183
- ```
184
-
185
- ### `MahalMap.removeInstance(container)`
186
-
187
- Удаляет инстанс из внутреннего реестра и возвращает `boolean`.
188
-
189
- ```ts
190
- const removed = MahalMap.removeInstance("map");
191
- ```
192
-
193
- Метод удаляет только запись из реестра. Для полного удаления карты используйте `destroy()`.
194
-
195
- ### `MahalMap.setDefaultLanguage(lang)`
196
-
197
- Задает язык по умолчанию для новых карт.
198
-
199
- ```ts
200
- MahalMap.setDefaultLanguage("ru");
201
-
202
- const map = MahalMap.create({ container: "map" }, maplibregl);
203
- ```
204
-
205
- После этого новые карты без `options.lang` будут использовать русский стандартный стиль. Для `tj` или пустого значения стандартные стили будут без query-параметра.
206
-
207
- ## Методы инстанса карты
208
-
209
- ### `map.getMap()`
210
-
211
- Возвращает нативный MapLibre `Map`.
212
-
213
- ```ts
214
- const maplibreMap = map.getMap();
215
- maplibreMap.resize();
216
- ```
217
-
218
- Используйте этот метод, если нужна функция MapLibre, которой нет в Mahal Map SDK.
219
-
220
- ### `map.getCamera()`
221
-
222
- Возвращает `CameraController` для управления камерой.
223
-
224
- ```ts
225
- const camera = map.getCamera();
226
- camera.flyTo({
227
- center: [69.624024, 40.279687],
228
- zoom: 14,
229
- });
230
- ```
231
-
232
- ### `map.setStyle(theme)`
233
-
234
- Переключает стандартную тему карты.
235
-
236
- ```ts
237
- map.setStyle("dark");
238
- map.setStyle("light");
239
- ```
240
-
241
- Если текущий язык `ru`, при переключении темы стиль будет загружен с `?lang=ru`. Если язык `tj`, URL будет без query-параметра.
242
-
243
- Метод не меняет стиль, если карта создана с `autoAddVectorSource: true`. Если карта создана с пользовательским `style`, SDK не переписывает этот URL.
244
-
245
- ### `map.setLanguage(lang)`
246
-
247
- Переключает язык стандартного стиля карты.
248
-
249
- ```ts
250
- map.setLanguage("ru");
251
- map.setLanguage("tj");
252
- ```
253
-
254
- `ru` добавляет `?lang=ru`, `tj` возвращает стандартный URL без параметра. Метод не переписывает пользовательский `options.style` и не меняет vector style при `autoAddVectorSource: true`.
255
-
256
- ### `map.setCenter(center)`
257
-
258
- Меняет центр карты.
259
-
260
- ```ts
261
- map.setCenter([69.624024, 40.279687]);
262
- ```
263
-
264
- Формат координат: `[lng, lat]`.
265
-
266
- ### `map.setZoom(zoom)`
267
-
268
- Меняет zoom карты.
269
-
270
- ```ts
271
- map.setZoom(13);
272
- ```
273
-
274
- ### `map.addMarker(marker)`
275
-
276
- Добавляет маркер на карту.
277
-
278
- ```ts
279
- import { MahalMapDefaultMarker } from "mahal_map";
280
-
281
- const marker = new MahalMapDefaultMarker({
282
- coordinates: [69.624024, 40.279687],
283
- color: "#278960",
284
- });
285
-
286
- map.addMarker(marker);
287
- ```
288
-
289
- Маркер должен реализовать интерфейс:
290
-
291
- ```ts
292
- interface IMapMarker {
293
- getElement(): HTMLElement;
294
- getCoordinates(): [number, number];
295
- isDraggable?(): boolean;
296
- getAnchor?():
297
- | "center"
298
- | "top"
299
- | "bottom"
300
- | "left"
301
- | "right"
302
- | "top-left"
303
- | "top-right"
304
- | "bottom-left"
305
- | "bottom-right";
306
- }
307
- ```
308
-
309
- ### `map.destroy()`
310
-
311
- Удаляет логотип SDK, вызывает `remove()` у MapLibre карты и удаляет инстанс из внутреннего реестра.
312
-
313
- ```ts
314
- map.destroy();
315
- ```
316
-
317
- Используйте при размонтировании страницы или компонента.
318
-
319
- ## Статические методы-обертки
320
-
321
- Для browser SDK и случаев, когда удобнее работать с функциями, доступны статические методы:
322
-
323
- ```ts
324
- MahalMap.getMap(map);
325
- MahalMap.getCamera(map);
326
- MahalMap.setStyle(map, "dark");
327
- MahalMap.setLanguage(map, "ru");
328
- MahalMap.setCenter(map, [69.624024, 40.279687]);
329
- MahalMap.setZoom(map, 14);
330
- MahalMap.addMarker(map, marker);
331
- MahalMap.destroy(map);
332
- ```
333
-
334
- Эти методы вызывают соответствующие методы переданного инстанса.
335
-
336
- ## Browser SDK функции
337
-
338
- При подключении `mahal_map.sdk.js` функции доступны на глобальном объекте `MahalMap`.
339
-
340
- ```js
341
- const map = MahalMap.create({
342
- container: "map",
343
- center: [69.624024, 40.279687],
344
- zoom: 12,
345
- });
346
-
347
- MahalMap.setStyle(map, "dark");
348
- MahalMap.setLanguage(map, "ru");
349
- MahalMap.setZoom(map, 14);
350
- ```
351
-
352
- Доступные функции карты в browser SDK:
353
-
354
- | Функция | Описание |
355
- | --- | --- |
356
- | `create(options)` | Создает карту. |
357
- | `onReady(container, callback)` | Выполняет callback после загрузки карты. |
358
- | `getInstance(container)` | Возвращает инстанс карты. |
359
- | `hasInstance(container)` | Проверяет наличие инстанса. |
360
- | `removeInstance(container)` | Удаляет инстанс из реестра. |
361
- | `getMap(instance)` | Возвращает нативный MapLibre Map. |
362
- | `getCamera(instance)` | Возвращает CameraController. |
363
- | `setStyle(instance, theme)` | Переключает тему стандартного стиля. |
364
- | `setLanguage(instance, lang)` | Переключает язык стандартного стиля. |
365
- | `setCenter(instance, center)` | Меняет центр карты. |
366
- | `setZoom(instance, zoom)` | Меняет zoom карты. |
367
- | `addMarker(instance, marker)` | Добавляет маркер. |
368
- | `destroy(instance)` | Полностью удаляет карту. |
369
- | `loadKeyFromScriptUrl()` | Читает `apikey` из URL SDK скрипта. |
370
- | `loadLanguageFromScriptUrl()` | Читает `lang` из URL SDK скрипта. |
371
-
372
- ## CameraController
373
-
374
- `CameraController` доступен через `map.getCamera()` или `MahalMap.getCamera(map)`.
375
-
376
- ### `camera.setZoom(zoom, smooth?)`
377
-
378
- Меняет zoom. Если `smooth` не передан, используется плавная анимация.
379
-
380
- ```ts
381
- camera.setZoom(14);
382
- camera.setZoom(10, false);
383
- ```
384
-
385
- ### `camera.setBearing(bearing, smooth?)`
386
-
387
- Меняет поворот карты.
388
-
389
- ```ts
390
- camera.setBearing(45);
391
- camera.setBearing(0, false);
392
- ```
393
-
394
- ### `camera.setPitch(pitch, smooth?)`
395
-
396
- Меняет наклон карты.
397
-
398
- ```ts
399
- camera.setPitch(60);
400
- camera.setPitch(0, false);
401
- ```
402
-
403
- ### `camera.toggle3D(is3D)`
404
-
405
- Включает или выключает 3D-вид.
406
-
407
- ```ts
408
- camera.toggle3D(true);
409
- camera.toggle3D(false);
410
- ```
411
-
412
- При включении задается `pitch: 60`, при выключении `pitch: 0` и `bearing: 0`.
413
-
414
- ### `camera.resetNorth()`
415
-
416
- Возвращает карту на север и сбрасывает наклон.
417
-
418
- ```ts
419
- camera.resetNorth();
420
- ```
421
-
422
- ### `camera.flyTo(options)`
423
-
424
- Выполняет плавный перелет камеры. Принимает `FlyToOptions` из MapLibre GL JS.
425
-
426
- ```ts
427
- camera.flyTo({
428
- center: [69.624024, 40.279687],
429
- zoom: 15,
430
- });
431
- ```
432
-
433
- SDK добавляет стандартные значения `speed`, `curve` и `essential`, но переданные значения могут их переопределить.
434
-
435
- ### `camera.getPitch()`
436
-
437
- Возвращает текущий наклон карты.
438
-
439
- ```ts
440
- const pitch = camera.getPitch();
441
- ```
442
-
443
- ## MahalMapDefaultMarker
444
-
445
- `MahalMapDefaultMarker` - готовый маркер, который можно использовать с `map.addMarker()`.
446
-
447
- ```ts
448
- import { MahalMapDefaultMarker } from "mahal_map";
449
-
450
- const marker = new MahalMapDefaultMarker({
451
- coordinates: [69.624024, 40.279687],
452
- color: "#278960",
453
- draggable: true,
454
- anchor: "bottom",
455
- });
456
-
457
- map.addMarker(marker);
458
- ```
459
-
460
- Параметры:
461
-
462
- | Параметр | Тип | Описание |
463
- | --- | --- | --- |
464
- | `coordinates` | `[number, number]` | Координаты маркера в формате `[lng, lat]`. |
465
- | `draggable` | `boolean` | Делает HTML-элемент маркера draggable. |
466
- | `anchor` | `string` | Anchor MapLibre маркера. |
467
- | `color` | `string` | Цвет стандартного SVG маркера или замена `fill` в пользовательском SVG. |
468
- | `svg` | `string` | Полностью пользовательский SVG. |
469
- | `innerSvg` | `string` | SVG внутри стандартного маркера. |
470
- | `innerUrl` | `string` | URL изображения внутри стандартного маркера. |
471
-
472
- Методы маркера:
473
-
474
- ```ts
475
- marker.getElement();
476
- marker.getCoordinates();
477
- marker.isDraggable();
478
- marker.getAnchor();
479
- ```
480
-
481
- ## Несколько карт
482
-
483
- Каждая карта сохраняется по ключу `container`.
484
-
485
- ```ts
486
- const mainMap = MahalMap.create({ container: "main" }, maplibregl);
487
- const miniMap = MahalMap.create({ container: "mini" }, maplibregl);
488
-
489
- MahalMap.getInstance("main").setZoom(14);
490
- MahalMap.getInstance("mini").setStyle("dark");
491
- ```
492
-
493
- Если `container` не передан, ключом будет `"map"`. Для нескольких карт всегда указывайте разные контейнеры.
494
-
495
- ## Пользовательский стиль
496
-
497
- Можно передать любой MapLibre style URL:
498
-
499
- ```ts
500
- const map = MahalMap.create(
501
- {
502
- container: "map",
503
- style: "https://example.com/custom-style.json",
504
- },
505
- maplibregl,
506
- );
507
- ```
508
-
509
- Когда передан `style`, SDK не добавляет `?lang=ru` и не подменяет URL при `setStyle()` или `setLanguage()`.
510
-
511
- ## Жизненный цикл
512
-
513
- Рекомендуемый порядок работы:
514
-
515
- 1. Создать DOM-контейнер.
516
- 2. Создать карту через `MahalMap.create()`.
517
- 3. Дождаться загрузки через `MahalMap.onReady()`, если нужен доступ к загруженной MapLibre карте.
518
- 4. Добавлять маркеры, менять камеру, тему или язык.
519
- 5. Вызвать `destroy()` при удалении страницы или компонента.
520
-
521
- ```ts
522
- const map = MahalMap.create({ container: "map" }, maplibregl);
523
-
524
- MahalMap.onReady("map", () => {
525
- map.setZoom(13);
526
- });
527
-
528
- // При размонтировании:
529
- map.destroy();
530
- ```
531
-
532
- ## Разработка
533
-
534
- ```sh
535
- npm run build
536
- npm run build:sdk
537
- npm run build:all
538
- npm test
539
- ```
540
-
541
- `npm run build` собирает npm entrypoint. `npm run build:sdk` собирает browser IIFE SDK bundle. `npm run build:all` запускает обе сборки.
542
-
543
- ## Структура проекта
544
-
545
- ```text
546
- src/
547
- index.ts
548
- sdk.ts
549
- config/
550
- core/
551
- markers/
552
- services/
553
- types/
554
- utils/
555
- ```
556
-
557
- - `index.ts` - npm entrypoint.
558
- - `sdk.ts` - browser SDK entrypoint.
559
- - `core/` - карта и управление камерой.
560
- - `markers/` - маркеры и адаптеры.
561
- - `types/` - публичные TypeScript типы.
562
-
563
- ## License
564
-
565
- ISC
1
+ # Mahal Map
2
+
3
+ Mahal Map - JavaScript/TypeScript SDK для работы с картой Mahal поверх MapLibre GL JS.
4
+
5
+ Документация ниже описывает только открытые функции карты: создание карты, управление инстансами, стили, язык, камера, маркеры и browser SDK.
6
+
7
+ ## Установка
8
+
9
+ ```sh
10
+ npm install mahal_map maplibre-gl
11
+ ```
12
+
13
+ `maplibre-gl` является peer dependency. Его нужно установить в приложении или подключить отдельным browser script перед SDK.
14
+
15
+ ## Быстрый старт через NPM
16
+
17
+ ```ts
18
+ import maplibregl from "maplibre-gl";
19
+ import "maplibre-gl/dist/maplibre-gl.css";
20
+ import { MahalMap, keyUtils } from "mahal_map";
21
+
22
+ keyUtils.saveKey("YOUR_MAP_API_KEY");
23
+
24
+ const map = MahalMap.create(
25
+ {
26
+ container: "map",
27
+ center: [69.624024, 40.279687],
28
+ zoom: 12,
29
+ theme: "light",
30
+ },
31
+ maplibregl,
32
+ );
33
+ ```
34
+
35
+ Контейнер должен существовать в HTML:
36
+
37
+ ```html
38
+ <div id="map" style="width: 100%; height: 500px"></div>
39
+ ```
40
+
41
+ ## Быстрый старт через Browser SDK
42
+
43
+ Сначала подключите MapLibre, затем `mahal_map.sdk.js`. Для browser SDK параметр `apikey` обязателен: без него карта не инициализируется.
44
+
45
+ ```html
46
+ <link
47
+ rel="stylesheet"
48
+ href="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.css"
49
+ />
50
+ <script src="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.js"></script>
51
+ <script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_MAP_API_KEY"></script>
52
+ ```
53
+
54
+ После этого глобальный объект `MahalMap` доступен в `window`:
55
+
56
+ ```html
57
+ <div id="map" style="width: 100%; height: 500px"></div>
58
+
59
+ <script>
60
+ const map = MahalMap.create({
61
+ container: "map",
62
+ center: [69.624024, 40.279687],
63
+ zoom: 12,
64
+ });
65
+ </script>
66
+ ```
67
+
68
+ ## Язык стиля карты
69
+
70
+ `keyUtils` хранит только токен доступа к карте, стилям и тайлам. Этот токен добавляется в URL стандартного стиля как `token`.
71
+
72
+ По умолчанию используется таджикский стиль:
73
+
74
+ ```txt
75
+ https://mtile.gram.tj/custom-styles/mapstyle.json?token=YOUR_MAP_API_KEY
76
+ https://mtile.gram.tj/custom-styles/dark-style.json?token=YOUR_MAP_API_KEY
77
+ ```
78
+
79
+ Для русского языка SDK добавляет `lang=ru` к стандартным стилям:
80
+
81
+ ```txt
82
+ https://mtile.gram.tj/custom-styles/mapstyle.json?token=YOUR_MAP_API_KEY&lang=ru
83
+ https://mtile.gram.tj/custom-styles/dark-style.json?token=YOUR_MAP_API_KEY&lang=ru
84
+ ```
85
+
86
+ Через NPM язык можно передать при создании карты:
87
+
88
+ ```ts
89
+ const map = MahalMap.create(
90
+ {
91
+ container: "map",
92
+ lang: "ru",
93
+ theme: "dark",
94
+ },
95
+ maplibregl,
96
+ );
97
+ ```
98
+
99
+ Через browser SDK язык можно передать в URL скрипта:
100
+
101
+ ```html
102
+ <script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_MAP_API_KEY&lang=ru"></script>
103
+ ```
104
+
105
+ Если `lang` не передан или передан `lang=tj`, SDK добавляет только `token`.
106
+
107
+ ## Параметры создания карты
108
+
109
+ `MahalMap.create(options, maplibreObject?)`
110
+
111
+ ```ts
112
+ interface IMahalMapOptions {
113
+ container?: string | HTMLElement;
114
+ style?: string;
115
+ theme?: "dark" | "light";
116
+ lang?: "tj" | "ru";
117
+ center?: [number, number];
118
+ zoom?: number;
119
+ autoAddVectorSource?: boolean;
120
+ }
121
+ ```
122
+
123
+ | Параметр | Тип | Описание |
124
+ | --- | --- | --- |
125
+ | `container` | `string \| HTMLElement` | ID контейнера или DOM-элемент. Если не передан, используется `"map"`. |
126
+ | `style` | `string` | Пользовательский URL стиля MapLibre. Если передан, `theme`, `lang` и map token не меняют URL стиля. |
127
+ | `theme` | `"dark" \| "light"` | Тема стандартного стиля. По умолчанию используется `light`. |
128
+ | `lang` | `"tj" \| "ru"` | Язык стандартного стиля. `tj` оставляет URL только с `token`, `ru` добавляет `lang=ru`. |
129
+ | `center` | `[number, number]` | Центр карты в формате `[lng, lat]`. |
130
+ | `zoom` | `number` | Начальный zoom. |
131
+ | `autoAddVectorSource` | `boolean` | Использует встроенный vector style и блокирует смену стандартного стиля через `setStyle`. |
132
+
133
+ ## MahalMap
134
+
135
+ `MahalMap` - основной класс карты. Конструктор закрыт, карту нужно создавать через `MahalMap.create()`.
136
+
137
+ ### `MahalMap.create(options, maplibreObject?)`
138
+
139
+ Создает новый инстанс карты и сохраняет его по ключу `container`. Для стандартных стилей перед созданием карты должен быть сохранен map token через `keyUtils.saveKey()`. В browser SDK token читается из обязательного URL-параметра `apikey`.
140
+
141
+ ```ts
142
+ const map = MahalMap.create(
143
+ {
144
+ container: "map",
145
+ center: [69.624024, 40.279687],
146
+ zoom: 12,
147
+ theme: "light",
148
+ lang: "tj",
149
+ },
150
+ maplibregl,
151
+ );
152
+ ```
153
+
154
+ В NPM-версии второй аргумент `maplibreObject` рекомендуется передавать явно. В browser SDK он берется из `window.maplibregl`.
155
+
156
+ ### `MahalMap.onReady(container, callback)`
157
+
158
+ Вызывает `callback`, когда карта создана и MapLibre завершил загрузку.
159
+
160
+ ```ts
161
+ MahalMap.onReady("map", (maplibreMap) => {
162
+ maplibreMap.resize();
163
+ });
164
+ ```
165
+
166
+ `callback` получает нативный `Map` объект из MapLibre GL JS.
167
+
168
+ ### `MahalMap.getInstance(container)`
169
+
170
+ Возвращает ранее созданный инстанс карты по ключу контейнера.
171
+
172
+ ```ts
173
+ const map = MahalMap.getInstance("map");
174
+ map.setZoom(14);
175
+ ```
176
+
177
+ Если инстанс не найден, будет выброшена ошибка.
178
+
179
+ ### `MahalMap.hasInstance(container)`
180
+
181
+ Проверяет, существует ли карта с таким ключом контейнера.
182
+
183
+ ```ts
184
+ if (MahalMap.hasInstance("map")) {
185
+ const map = MahalMap.getInstance("map");
186
+ }
187
+ ```
188
+
189
+ ### `MahalMap.removeInstance(container)`
190
+
191
+ Удаляет инстанс из внутреннего реестра и возвращает `boolean`.
192
+
193
+ ```ts
194
+ const removed = MahalMap.removeInstance("map");
195
+ ```
196
+
197
+ Метод удаляет только запись из реестра. Для полного удаления карты используйте `destroy()`.
198
+
199
+ ### `MahalMap.setDefaultLanguage(lang)`
200
+
201
+ Задает язык по умолчанию для новых карт.
202
+
203
+ ```ts
204
+ MahalMap.setDefaultLanguage("ru");
205
+ keyUtils.saveKey("YOUR_MAP_API_KEY");
206
+
207
+ const map = MahalMap.create({ container: "map" }, maplibregl);
208
+ ```
209
+
210
+ После этого новые карты без `options.lang` будут использовать русский стандартный стиль. Для `tj` или пустого значения стандартные стили будут только с `token`.
211
+
212
+ ## Методы инстанса карты
213
+
214
+ ### `map.getMap()`
215
+
216
+ Возвращает нативный MapLibre `Map`.
217
+
218
+ ```ts
219
+ const maplibreMap = map.getMap();
220
+ maplibreMap.resize();
221
+ ```
222
+
223
+ Используйте этот метод, если нужна функция MapLibre, которой нет в Mahal Map SDK.
224
+
225
+ ### `map.getCamera()`
226
+
227
+ Возвращает `CameraController` для управления камерой.
228
+
229
+ ```ts
230
+ const camera = map.getCamera();
231
+ camera.flyTo({
232
+ center: [69.624024, 40.279687],
233
+ zoom: 14,
234
+ });
235
+ ```
236
+
237
+ ### `map.setStyle(theme)`
238
+
239
+ Переключает стандартную тему карты.
240
+
241
+ ```ts
242
+ map.setStyle("dark");
243
+ map.setStyle("light");
244
+ ```
245
+
246
+ Если текущий язык `ru`, при переключении темы стиль будет загружен с `token=...&lang=ru`. Если язык `tj`, URL будет только с `token=...`.
247
+
248
+ Метод не меняет стиль, если карта создана с `autoAddVectorSource: true`. Если карта создана с пользовательским `style`, SDK не переписывает этот URL.
249
+
250
+ ### `map.setLanguage(lang)`
251
+
252
+ Переключает язык стандартного стиля карты.
253
+
254
+ ```ts
255
+ map.setLanguage("ru");
256
+ map.setLanguage("tj");
257
+ ```
258
+
259
+ `ru` добавляет `lang=ru`, `tj` возвращает стандартный URL только с `token=...`. Метод не переписывает пользовательский `options.style` и не меняет vector style при `autoAddVectorSource: true`.
260
+
261
+ ### `map.setCenter(center)`
262
+
263
+ Меняет центр карты.
264
+
265
+ ```ts
266
+ map.setCenter([69.624024, 40.279687]);
267
+ ```
268
+
269
+ Формат координат: `[lng, lat]`.
270
+
271
+ ### `map.setZoom(zoom)`
272
+
273
+ Меняет zoom карты.
274
+
275
+ ```ts
276
+ map.setZoom(13);
277
+ ```
278
+
279
+ ### `map.addMarker(marker)`
280
+
281
+ Добавляет маркер на карту.
282
+
283
+ ```ts
284
+ import { MahalMapDefaultMarker } from "mahal_map";
285
+
286
+ const marker = new MahalMapDefaultMarker({
287
+ coordinates: [69.624024, 40.279687],
288
+ color: "#278960",
289
+ });
290
+
291
+ map.addMarker(marker);
292
+ ```
293
+
294
+ Маркер должен реализовать интерфейс:
295
+
296
+ ```ts
297
+ interface IMapMarker {
298
+ getElement(): HTMLElement;
299
+ getCoordinates(): [number, number];
300
+ isDraggable?(): boolean;
301
+ getAnchor?():
302
+ | "center"
303
+ | "top"
304
+ | "bottom"
305
+ | "left"
306
+ | "right"
307
+ | "top-left"
308
+ | "top-right"
309
+ | "bottom-left"
310
+ | "bottom-right";
311
+ }
312
+ ```
313
+
314
+ ### `map.destroy()`
315
+
316
+ Удаляет логотип SDK, вызывает `remove()` у MapLibre карты и удаляет инстанс из внутреннего реестра.
317
+
318
+ ```ts
319
+ map.destroy();
320
+ ```
321
+
322
+ Используйте при размонтировании страницы или компонента.
323
+
324
+ ## Статические методы-обертки
325
+
326
+ Для browser SDK и случаев, когда удобнее работать с функциями, доступны статические методы:
327
+
328
+ ```ts
329
+ MahalMap.getMap(map);
330
+ MahalMap.getCamera(map);
331
+ MahalMap.setStyle(map, "dark");
332
+ MahalMap.setLanguage(map, "ru");
333
+ MahalMap.setCenter(map, [69.624024, 40.279687]);
334
+ MahalMap.setZoom(map, 14);
335
+ MahalMap.addMarker(map, marker);
336
+ MahalMap.destroy(map);
337
+ ```
338
+
339
+ Эти методы вызывают соответствующие методы переданного инстанса.
340
+
341
+ ## Browser SDK функции
342
+
343
+ При подключении `mahal_map.sdk.js` функции доступны на глобальном объекте `MahalMap`.
344
+
345
+ ```js
346
+ const map = MahalMap.create({
347
+ container: "map",
348
+ center: [69.624024, 40.279687],
349
+ zoom: 12,
350
+ });
351
+
352
+ MahalMap.setStyle(map, "dark");
353
+ MahalMap.setLanguage(map, "ru");
354
+ MahalMap.setZoom(map, 14);
355
+ ```
356
+
357
+ Доступные функции карты в browser SDK:
358
+
359
+ | Функция | Описание |
360
+ | --- | --- |
361
+ | `create(options)` | Создает карту. Требует `apikey` в URL SDK скрипта. |
362
+ | `onReady(container, callback)` | Выполняет callback после загрузки карты. |
363
+ | `getInstance(container)` | Возвращает инстанс карты. |
364
+ | `hasInstance(container)` | Проверяет наличие инстанса. |
365
+ | `removeInstance(container)` | Удаляет инстанс из реестра. |
366
+ | `getMap(instance)` | Возвращает нативный MapLibre Map. |
367
+ | `getCamera(instance)` | Возвращает CameraController. |
368
+ | `setStyle(instance, theme)` | Переключает тему стандартного стиля. |
369
+ | `setLanguage(instance, lang)` | Переключает язык стандартного стиля. |
370
+ | `setCenter(instance, center)` | Меняет центр карты. |
371
+ | `setZoom(instance, zoom)` | Меняет zoom карты. |
372
+ | `addMarker(instance, marker)` | Добавляет маркер. |
373
+ | `destroy(instance)` | Полностью удаляет карту. |
374
+ | `loadKeyFromScriptUrl()` | Читает `apikey` из URL SDK скрипта. |
375
+ | `loadLanguageFromScriptUrl()` | Читает `lang` из URL SDK скрипта. |
376
+
377
+ ## CameraController
378
+
379
+ `CameraController` доступен через `map.getCamera()` или `MahalMap.getCamera(map)`.
380
+
381
+ ### `camera.setZoom(zoom, smooth?)`
382
+
383
+ Меняет zoom. Если `smooth` не передан, используется плавная анимация.
384
+
385
+ ```ts
386
+ camera.setZoom(14);
387
+ camera.setZoom(10, false);
388
+ ```
389
+
390
+ ### `camera.setBearing(bearing, smooth?)`
391
+
392
+ Меняет поворот карты.
393
+
394
+ ```ts
395
+ camera.setBearing(45);
396
+ camera.setBearing(0, false);
397
+ ```
398
+
399
+ ### `camera.setPitch(pitch, smooth?)`
400
+
401
+ Меняет наклон карты.
402
+
403
+ ```ts
404
+ camera.setPitch(60);
405
+ camera.setPitch(0, false);
406
+ ```
407
+
408
+ ### `camera.toggle3D(is3D)`
409
+
410
+ Включает или выключает 3D-вид.
411
+
412
+ ```ts
413
+ camera.toggle3D(true);
414
+ camera.toggle3D(false);
415
+ ```
416
+
417
+ При включении задается `pitch: 60`, при выключении `pitch: 0` и `bearing: 0`.
418
+
419
+ ### `camera.resetNorth()`
420
+
421
+ Возвращает карту на север и сбрасывает наклон.
422
+
423
+ ```ts
424
+ camera.resetNorth();
425
+ ```
426
+
427
+ ### `camera.flyTo(options)`
428
+
429
+ Выполняет плавный перелет камеры. Принимает `FlyToOptions` из MapLibre GL JS.
430
+
431
+ ```ts
432
+ camera.flyTo({
433
+ center: [69.624024, 40.279687],
434
+ zoom: 15,
435
+ });
436
+ ```
437
+
438
+ SDK добавляет стандартные значения `speed`, `curve` и `essential`, но переданные значения могут их переопределить.
439
+
440
+ ### `camera.getPitch()`
441
+
442
+ Возвращает текущий наклон карты.
443
+
444
+ ```ts
445
+ const pitch = camera.getPitch();
446
+ ```
447
+
448
+ ## MahalMapDefaultMarker
449
+
450
+ `MahalMapDefaultMarker` - готовый маркер, который можно использовать с `map.addMarker()`.
451
+
452
+ ```ts
453
+ import { MahalMapDefaultMarker } from "mahal_map";
454
+
455
+ const marker = new MahalMapDefaultMarker({
456
+ coordinates: [69.624024, 40.279687],
457
+ color: "#278960",
458
+ draggable: true,
459
+ anchor: "bottom",
460
+ });
461
+
462
+ map.addMarker(marker);
463
+ ```
464
+
465
+ Параметры:
466
+
467
+ | Параметр | Тип | Описание |
468
+ | --- | --- | --- |
469
+ | `coordinates` | `[number, number]` | Координаты маркера в формате `[lng, lat]`. |
470
+ | `draggable` | `boolean` | Делает HTML-элемент маркера draggable. |
471
+ | `anchor` | `string` | Anchor MapLibre маркера. |
472
+ | `color` | `string` | Цвет стандартного SVG маркера или замена `fill` в пользовательском SVG. |
473
+ | `svg` | `string` | Полностью пользовательский SVG. |
474
+ | `innerSvg` | `string` | SVG внутри стандартного маркера. |
475
+ | `innerUrl` | `string` | URL изображения внутри стандартного маркера. |
476
+
477
+ Методы маркера:
478
+
479
+ ```ts
480
+ marker.getElement();
481
+ marker.getCoordinates();
482
+ marker.isDraggable();
483
+ marker.getAnchor();
484
+ ```
485
+
486
+ ## Несколько карт
487
+
488
+ Каждая карта сохраняется по ключу `container`.
489
+
490
+ ```ts
491
+ const mainMap = MahalMap.create({ container: "main" }, maplibregl);
492
+ const miniMap = MahalMap.create({ container: "mini" }, maplibregl);
493
+
494
+ MahalMap.getInstance("main").setZoom(14);
495
+ MahalMap.getInstance("mini").setStyle("dark");
496
+ ```
497
+
498
+ Если `container` не передан, ключом будет `"map"`. Для нескольких карт всегда указывайте разные контейнеры.
499
+
500
+ ## Пользовательский стиль
501
+
502
+ Можно передать любой MapLibre style URL:
503
+
504
+ ```ts
505
+ const map = MahalMap.create(
506
+ {
507
+ container: "map",
508
+ style: "https://example.com/custom-style.json",
509
+ },
510
+ maplibregl,
511
+ );
512
+ ```
513
+
514
+ Когда передан `style`, SDK не добавляет `token` или `lang=ru` и не подменяет URL при `setStyle()` или `setLanguage()`.
515
+
516
+ ## Жизненный цикл
517
+
518
+ Рекомендуемый порядок работы:
519
+
520
+ 1. Создать DOM-контейнер.
521
+ 2. Сохранить map token через `keyUtils.saveKey()` или передать `apikey` в URL browser SDK.
522
+ 3. Создать карту через `MahalMap.create()`.
523
+ 4. Дождаться загрузки через `MahalMap.onReady()`, если нужен доступ к загруженной MapLibre карте.
524
+ 5. Добавлять маркеры, менять камеру, тему или язык.
525
+ 6. Вызвать `destroy()` при удалении страницы или компонента.
526
+
527
+ ```ts
528
+ const map = MahalMap.create({ container: "map" }, maplibregl);
529
+
530
+ MahalMap.onReady("map", () => {
531
+ map.setZoom(13);
532
+ });
533
+
534
+ // При размонтировании:
535
+ map.destroy();
536
+ ```
537
+
538
+ ## Разработка
539
+
540
+ ```sh
541
+ npm run build
542
+ npm run build:sdk
543
+ npm run build:all
544
+ npm test
545
+ ```
546
+
547
+ `npm run build` собирает npm entrypoint. `npm run build:sdk` собирает browser IIFE SDK bundle. `npm run build:all` запускает обе сборки.
548
+
549
+ ## Структура проекта
550
+
551
+ ```text
552
+ src/
553
+ index.ts
554
+ sdk.ts
555
+ config/
556
+ core/
557
+ markers/
558
+ services/
559
+ types/
560
+ utils/
561
+ ```
562
+
563
+ - `index.ts` - npm entrypoint.
564
+ - `sdk.ts` - browser SDK entrypoint.
565
+ - `core/` - карта и управление камерой.
566
+ - `markers/` - маркеры и адаптеры.
567
+ - `types/` - публичные TypeScript типы.
568
+
569
+ ## License
570
+
571
+ ISC