mahal_map 1.5.0 → 1.5.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
@@ -1,66 +1,59 @@
1
- # Mahal Map
2
-
3
- Mahal Map is a JavaScript/TypeScript SDK for working with Mahal map services on top of MapLibre GL JS.
4
-
5
- ## Installation
6
-
7
- ```sh
8
- npm install mahal_map maplibre-gl
9
- ```
10
-
11
- `maplibre-gl` is a peer dependency: the application that uses this SDK must install it or include it through a browser script.
12
-
13
- ## NPM Usage
14
-
15
- ```ts
16
- import maplibregl from "maplibre-gl";
17
- import "maplibre-gl/dist/maplibre-gl.css";
18
- import { MahalMap, MahalMapDefaultMarker } from "mahal_map";
19
-
20
- const mainMap = MahalMap.create(
21
- {
22
- container: "main-map",
23
- center: [69.624024, 40.279687],
24
- zoom: 12,
25
- },
26
- maplibregl,
27
- );
28
-
29
- const marker = new MahalMapDefaultMarker({
30
- coordinates: [69.624024, 40.279687],
31
- });
32
-
33
- mainMap.addMarker(marker);
34
- ```
35
-
36
- ## Multiple Maps
37
-
38
- `MahalMap.create()` always creates and returns a new map instance. The SDK also stores created instances by their `container` key.
39
-
40
- ```ts
41
- const mainMap = MahalMap.create({ container: "main" }, maplibregl);
42
- const miniMap = MahalMap.create({ container: "mini" }, maplibregl);
43
-
44
- MahalMap.getInstance("main").setZoom(14);
45
- MahalMap.addMarker(miniMap, marker);
46
- ```
47
-
48
- ## Browser SDK Usage
49
-
50
- For direct browser usage, include MapLibre first and then the Mahal Map SDK bundle:
51
-
52
- ```html
53
- <link
54
- rel="stylesheet"
55
- href="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.css"
56
- />
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
+ />
57
48
  <script src="https://unpkg.com/maplibre-gl@5.3.0/dist/maplibre-gl.js"></script>
58
- <script src="/dist/mahal_map.sdk.js?apikey=YOUR_API_KEY"></script>
49
+ <script src="https://cp.mahal.tj/sdk/mahal_map.sdk.js?apikey=YOUR_API_KEY"></script>
59
50
  ```
60
51
 
61
- The browser SDK reads `apikey` from its script URL and stores it as the default API key for search and routing requests.
52
+ После этого глобальный объект `MahalMap` доступен в `window`:
62
53
 
63
54
  ```html
55
+ <div id="map" style="width: 100%; height: 500px"></div>
56
+
64
57
  <script>
65
58
  const map = MahalMap.create({
66
59
  container: "map",
@@ -70,67 +63,503 @@ The browser SDK reads `apikey` from its script URL and stores it as the default
70
63
  </script>
71
64
  ```
72
65
 
73
- ## Search
74
-
75
- ```ts
76
- import { Search, SearchByLocation } from "mahal_map";
77
-
78
- const results = await Search("Dushanbe", "");
79
-
80
- const nearby = await SearchByLocation({
81
- lat: 38.5737,
82
- lng: 68.7738,
83
- });
84
- ```
85
-
86
- ## Routing
87
-
88
- ```ts
89
- import { Router } from "mahal_map";
90
-
91
- const routes = await Router(
92
- [
93
- [69.624024, 40.279687],
94
- [68.7738, 38.5737],
95
- ],
96
- "geojson",
97
- "",
98
- );
99
- ```
100
-
101
- ## Development
102
-
103
- ```sh
104
- npm run build
105
- npm run build:sdk
106
- npm run build:all
107
- npm test
108
- ```
109
-
110
- `npm run build` creates the npm package output. `npm run build:sdk` creates the browser IIFE SDK bundle.
111
-
112
- ## Project Structure
113
-
114
- ```text
115
- src/
116
- index.ts
117
- sdk.ts
118
- config/
119
- core/
120
- markers/
121
- services/
122
- types/
123
- utils/
124
- ```
125
-
126
- - `index.ts` is the clean npm entrypoint.
127
- - `sdk.ts` is the browser SDK entrypoint that reads `apikey` from the script URL.
128
- - `core/` contains map and camera classes.
129
- - `markers/` contains marker components and adapters.
130
- - `services/` contains HTTP, auth key, search, and routing logic.
131
- - `types/` contains public TypeScript contracts.
132
- - `utils/` contains shared helpers and polyline utilities.
133
-
134
- ## License
135
-
136
- ISC
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