aur-openlayers 0.0.1
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 +63 -0
- package/fesm2022/aur-openlayers.mjs +2118 -0
- package/fesm2022/aur-openlayers.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/lib.component.d.ts +5 -0
- package/lib/lib.service.d.ts +6 -0
- package/lib/map-framework/index.d.ts +2 -0
- package/lib/map-framework/public/types.d.ts +658 -0
- package/lib/map-framework/runtime/cluster-utils.d.ts +3 -0
- package/lib/map-framework/runtime/clustered-layer.d.ts +17 -0
- package/lib/map-framework/runtime/feature-registry.d.ts +16 -0
- package/lib/map-framework/runtime/fit-layer.utils.d.ts +3 -0
- package/lib/map-framework/runtime/interaction-manager.d.ts +110 -0
- package/lib/map-framework/runtime/layer-manager.d.ts +17 -0
- package/lib/map-framework/runtime/map-context.d.ts +4 -0
- package/lib/map-framework/runtime/plain-layer.d.ts +6 -0
- package/lib/map-framework/runtime/popup-host.d.ts +31 -0
- package/lib/map-framework/runtime/scheduler.d.ts +21 -0
- package/lib/map-framework/runtime/style/feature-states.d.ts +5 -0
- package/lib/map-framework/runtime/style/style-cache.d.ts +7 -0
- package/lib/map-framework/runtime/style/style-pipeline.d.ts +20 -0
- package/lib/map-framework/runtime/vector-layer-base.d.ts +53 -0
- package/package.json +24 -0
- package/public-api.d.ts +3 -0
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
import type Feature from 'ol/Feature';
|
|
2
|
+
import type Geometry from 'ol/geom/Geometry';
|
|
3
|
+
import type MapBrowserEvent from 'ol/MapBrowserEvent';
|
|
4
|
+
import type { ModifyEvent } from 'ol/interaction/Modify';
|
|
5
|
+
import type OlMap from 'ol/Map';
|
|
6
|
+
import type Style from 'ol/style/Style';
|
|
7
|
+
import type { TranslateEvent } from 'ol/interaction/Translate';
|
|
8
|
+
/**
|
|
9
|
+
* Идентификатор состояния стиля, применяемого к фичам.
|
|
10
|
+
*
|
|
11
|
+
* Используйте строковые константы уровня проекта (например, `"HOVER"`).
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* const state: FeatureStyleState = 'SELECTED';
|
|
15
|
+
*/
|
|
16
|
+
export type FeatureStyleState = string;
|
|
17
|
+
/**
|
|
18
|
+
* Значение или функция, которая его вычисляет.
|
|
19
|
+
*
|
|
20
|
+
* Полезно для ленивых вычислений и адаптации к контексту.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* const width: MaybeFn<number, [zoom: number]> = (zoom) => zoom > 10 ? 3 : 1;
|
|
24
|
+
*/
|
|
25
|
+
export type MaybeFn<T, A extends any[] = []> = T | ((...args: A) => T);
|
|
26
|
+
/**
|
|
27
|
+
* Патч: либо частичный объект, либо функция, вычисляющая патч.
|
|
28
|
+
*
|
|
29
|
+
* Используется для частичных переопределений стиля.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* const patch: Patch<{ color: string }> = { color: 'red' };
|
|
33
|
+
*/
|
|
34
|
+
export type Patch<T> = Partial<T> | ((prev: T) => Partial<T>);
|
|
35
|
+
/**
|
|
36
|
+
* Признак включённости: статическое значение или вычисляемая функция.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const enabled: Enabled = () => isEditMode;
|
|
40
|
+
*/
|
|
41
|
+
export type Enabled = boolean | (() => boolean);
|
|
42
|
+
/**
|
|
43
|
+
* Политика сброса (flush) для батчинга обновлений.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const policy: FlushPolicy = 'raf';
|
|
47
|
+
*/
|
|
48
|
+
export type FlushPolicy = 'microtask' | 'raf';
|
|
49
|
+
/**
|
|
50
|
+
* Опции батчинга для `MapContext.batch`.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ctx.batch(doWork, { policy: 'raf' });
|
|
54
|
+
*/
|
|
55
|
+
export type BatchOptions = {
|
|
56
|
+
/** Политика сброса для конкретного батча. */
|
|
57
|
+
policy?: FlushPolicy;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Параметры текущего вида карты для LOD-стилей.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const view: StyleView = { resolution: 12.5, zoom: 8 };
|
|
64
|
+
*/
|
|
65
|
+
export type StyleView = {
|
|
66
|
+
/** Текущее разрешение OpenLayers (`map.getView().getResolution()`). */
|
|
67
|
+
resolution: number;
|
|
68
|
+
/** Опциональный зум, если он вычисляется в реализации. */
|
|
69
|
+
zoom?: number;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Состояние фичи: одиночное или составное.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* const state: FeatureState = ['HOVER', 'SELECTED'];
|
|
76
|
+
*/
|
|
77
|
+
export type FeatureState = FeatureStyleState | FeatureStyleState[];
|
|
78
|
+
/**
|
|
79
|
+
* Результат hit-test для текущего слоя: модель + соответствующая фича.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const item: HitItem<Model, Geometry> = { model, feature };
|
|
83
|
+
*/
|
|
84
|
+
export type HitItem<M, G extends Geometry> = {
|
|
85
|
+
/** Доменных объект, связанный с фичей. */
|
|
86
|
+
model: M;
|
|
87
|
+
/** Фича OpenLayers. */
|
|
88
|
+
feature: Feature<G>;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Общие настройки для interactions (hover, click, translate и т.д.).
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* const base: InteractionBase = { enabled: true, propagation: 'stop' };
|
|
95
|
+
*/
|
|
96
|
+
export type InteractionBase = {
|
|
97
|
+
/**
|
|
98
|
+
* Включённость интеракции. Если не задано — считается включённой.
|
|
99
|
+
*/
|
|
100
|
+
enabled?: Enabled;
|
|
101
|
+
/**
|
|
102
|
+
* UX: курсор для interaction на DOM-элементе карты.
|
|
103
|
+
*/
|
|
104
|
+
cursor?: string;
|
|
105
|
+
/**
|
|
106
|
+
* Состояния, которые должны применяться при активности интеракции.
|
|
107
|
+
* Если не задано — управление состояниями полностью на стороне пользователя.
|
|
108
|
+
*/
|
|
109
|
+
state?: FeatureState;
|
|
110
|
+
/**
|
|
111
|
+
* Пропагация события на нижележащие слои, если текущий слой обработал событие.
|
|
112
|
+
*/
|
|
113
|
+
propagation?: 'stop' | 'continue' | 'auto';
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Результат обработчика интеракции: `true` — событие обработано.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* const handled: InteractionHandlerResult = true;
|
|
120
|
+
*/
|
|
121
|
+
export type InteractionHandlerResult = boolean | void;
|
|
122
|
+
/**
|
|
123
|
+
* Причина изменения модели, инициированного картой.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* const reason: ModelChangeReason = 'translate';
|
|
127
|
+
*/
|
|
128
|
+
export type ModelChangeReason = 'mutate' | 'translate' | 'modify';
|
|
129
|
+
/**
|
|
130
|
+
* Изменение модели, инициированное картой.
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* onModelsChanged?.((changes) => console.log(changes.length));
|
|
134
|
+
*/
|
|
135
|
+
export type ModelChange<M> = {
|
|
136
|
+
/** Предыдущая версия модели. */
|
|
137
|
+
prev: M;
|
|
138
|
+
/** Новая версия модели (immutable). */
|
|
139
|
+
next: M;
|
|
140
|
+
/** Причина изменения. */
|
|
141
|
+
reason: ModelChangeReason;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Паддинги для операций fit/center.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* const padding: ViewFitPadding = { top: 16, right: 16, bottom: 16, left: 16 };
|
|
148
|
+
*/
|
|
149
|
+
export type ViewFitPadding = {
|
|
150
|
+
all: number;
|
|
151
|
+
} | {
|
|
152
|
+
vertical: number;
|
|
153
|
+
horizontal: number;
|
|
154
|
+
} | {
|
|
155
|
+
top: number;
|
|
156
|
+
right: number;
|
|
157
|
+
bottom: number;
|
|
158
|
+
left: number;
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Опции fit/center операций.
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* layer.centerOnModel(1, { duration: 300, maxZoom: 18 });
|
|
165
|
+
*/
|
|
166
|
+
export type ViewFitOptions = {
|
|
167
|
+
/** Паддинги вокруг области. */
|
|
168
|
+
padding?: ViewFitPadding;
|
|
169
|
+
/** Длительность анимации (мс). */
|
|
170
|
+
duration?: number;
|
|
171
|
+
/** Верхний предел увеличения. */
|
|
172
|
+
maxZoom?: number;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Функция отписки от событий.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* const unsubscribe: Unsubscribe = onModelsChanged(() => {});
|
|
179
|
+
*/
|
|
180
|
+
export type Unsubscribe = () => void;
|
|
181
|
+
/**
|
|
182
|
+
* Публичный API слоя для бизнес-логики и других дескрипторов.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ctx.layers.points.mutate(id, (prev) => ({ ...prev, active: true }));
|
|
186
|
+
*/
|
|
187
|
+
export type VectorLayerApi<M, G extends Geometry> = {
|
|
188
|
+
/** Заменить весь набор моделей в слое. */
|
|
189
|
+
setModels: (models: readonly M[]) => void;
|
|
190
|
+
/** Запросить пересчёт слоя/стилей. */
|
|
191
|
+
invalidate: () => void;
|
|
192
|
+
/** Синхронизировать модель в фичу при внешнем изменении модели. */
|
|
193
|
+
syncFeatureFromModel: (model: M) => void;
|
|
194
|
+
/** Найти модель по фиче слоя. */
|
|
195
|
+
getModelByFeature: (feature: Feature<G>) => M | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Иммутабельное обновление модели по id.
|
|
198
|
+
* `update` обязан вернуть новый объект (или тот же для no-op).
|
|
199
|
+
*/
|
|
200
|
+
mutate: (id: string | number, update: (prev: M) => M, reason?: ModelChangeReason) => void;
|
|
201
|
+
/** Массовая мутация (опционально). */
|
|
202
|
+
mutateMany?: (ids: Array<string | number>, update: (prev: M) => M, reason?: ModelChangeReason) => void;
|
|
203
|
+
/**
|
|
204
|
+
* Переключение кластеризации (если слой её поддерживает).
|
|
205
|
+
*/
|
|
206
|
+
setClusteringEnabled?: (enabled: boolean) => void;
|
|
207
|
+
/** Текущее состояние кластеризации. */
|
|
208
|
+
isClusteringEnabled?: () => boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Уведомления об изменениях моделей, инициированных картой.
|
|
211
|
+
*/
|
|
212
|
+
onModelsChanged?: (cb: (changes: ModelChange<M>[]) => void) => Unsubscribe;
|
|
213
|
+
/**
|
|
214
|
+
* Центрирует карту на всех фичах слоя.
|
|
215
|
+
*/
|
|
216
|
+
centerOnAllModels: (opts?: ViewFitOptions) => void;
|
|
217
|
+
/**
|
|
218
|
+
* Центрирует карту на одной фиче по id.
|
|
219
|
+
*/
|
|
220
|
+
centerOnModel: (id: string | number, opts?: ViewFitOptions) => void;
|
|
221
|
+
/**
|
|
222
|
+
* Центрирует карту на наборе фичей по списку id.
|
|
223
|
+
*/
|
|
224
|
+
centerOnModels: (ids: ReadonlyArray<string | number>, opts?: ViewFitOptions) => void;
|
|
225
|
+
/**
|
|
226
|
+
* Управление видимостью слоя.
|
|
227
|
+
*/
|
|
228
|
+
setVisible: (visible: boolean) => void;
|
|
229
|
+
/**
|
|
230
|
+
* Текущее состояние видимости слоя.
|
|
231
|
+
*/
|
|
232
|
+
isVisible: () => boolean;
|
|
233
|
+
/**
|
|
234
|
+
* Установить прозрачность слоя.
|
|
235
|
+
*/
|
|
236
|
+
setOpacity: (opacity: number) => void;
|
|
237
|
+
/**
|
|
238
|
+
* Получить прозрачность слоя.
|
|
239
|
+
*/
|
|
240
|
+
getOpacity: () => number;
|
|
241
|
+
/**
|
|
242
|
+
* Установить z-index слоя.
|
|
243
|
+
*/
|
|
244
|
+
setZIndex: (z: number) => void;
|
|
245
|
+
/**
|
|
246
|
+
* Получить z-index слоя.
|
|
247
|
+
*/
|
|
248
|
+
getZIndex: () => number | undefined;
|
|
249
|
+
/**
|
|
250
|
+
* Получить модель по id.
|
|
251
|
+
*/
|
|
252
|
+
getModelById: (id: string | number) => M | undefined;
|
|
253
|
+
/**
|
|
254
|
+
* Проверить наличие модели по id.
|
|
255
|
+
*/
|
|
256
|
+
hasModel: (id: string | number) => boolean;
|
|
257
|
+
/**
|
|
258
|
+
* Получить текущий снимок моделей.
|
|
259
|
+
*/
|
|
260
|
+
getAllModels: () => readonly M[];
|
|
261
|
+
/**
|
|
262
|
+
* Получить текущий снимок id моделей.
|
|
263
|
+
*/
|
|
264
|
+
getAllModelIds: () => Array<string | number>;
|
|
265
|
+
/**
|
|
266
|
+
* Применить состояния стиля к фичам по id.
|
|
267
|
+
*/
|
|
268
|
+
setFeatureStates: (ids: string | number | ReadonlyArray<string | number>, states?: FeatureState) => void;
|
|
269
|
+
};
|
|
270
|
+
/**
|
|
271
|
+
* Источник появления popup-элемента.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* const source: PopupItemSource = 'feature';
|
|
275
|
+
*/
|
|
276
|
+
export type PopupItemSource = 'feature' | 'cluster' | 'interaction';
|
|
277
|
+
/**
|
|
278
|
+
* Элемент popup, отображаемый глобальным хостом.
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* const item: PopupItem<Model> = { model, content: 'Hello' };
|
|
282
|
+
*/
|
|
283
|
+
export type PopupItem<M> = {
|
|
284
|
+
/** Модель, связанная с элементом popup. */
|
|
285
|
+
model: M;
|
|
286
|
+
/** Контент popup. */
|
|
287
|
+
content: string | HTMLElement;
|
|
288
|
+
/** CSS-класс для стилизации. */
|
|
289
|
+
className?: string;
|
|
290
|
+
/** Смещение popup относительно координаты. */
|
|
291
|
+
offset?: number[];
|
|
292
|
+
/** Ключ дедупликации элементов. */
|
|
293
|
+
dedupKey?: string | number;
|
|
294
|
+
/** Приоритет сортировки (чем больше, тем выше). */
|
|
295
|
+
priority?: number;
|
|
296
|
+
/** Источник элемента. */
|
|
297
|
+
source?: PopupItemSource;
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Контракт хоста попапов, агрегирующего элементы со всех слоёв.
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ctx.popupHost?.set([item]);
|
|
304
|
+
*/
|
|
305
|
+
export interface PopupHostApi {
|
|
306
|
+
/** Добавить элементы в текущий список. */
|
|
307
|
+
push: (items: PopupItem<any>[]) => void;
|
|
308
|
+
/** Заменить список элементов. */
|
|
309
|
+
set: (items: PopupItem<any>[]) => void;
|
|
310
|
+
/** Очистить список. */
|
|
311
|
+
clear: () => void;
|
|
312
|
+
/** Удалить элемент по ключу. */
|
|
313
|
+
remove: (key: string | number) => void;
|
|
314
|
+
/** Получить текущие элементы. */
|
|
315
|
+
getItems: () => PopupItem<any>[];
|
|
316
|
+
/** Примонтировать popup-хост к DOM-узлу. */
|
|
317
|
+
mount: (target: HTMLElement | (() => HTMLElement)) => void;
|
|
318
|
+
/** Освободить ресурсы и отписки. */
|
|
319
|
+
dispose: () => void;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Минимальный контекст, доступный обработчикам взаимодействий.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* controller.bind({ map, layers, batch });
|
|
326
|
+
*/
|
|
327
|
+
export type MapContext = {
|
|
328
|
+
/** Экземпляр карты OpenLayers. */
|
|
329
|
+
map: OlMap;
|
|
330
|
+
/** Доступ к слоям по id (типизируется реализацией). */
|
|
331
|
+
layers: Record<string, VectorLayerApi<any, any>>;
|
|
332
|
+
/** Глобальный хост попапов, если включён. */
|
|
333
|
+
popupHost?: PopupHostApi;
|
|
334
|
+
/**
|
|
335
|
+
* Батчинг для группировки mutate/invalidate.
|
|
336
|
+
*/
|
|
337
|
+
batch: (fn: () => void, options?: BatchOptions) => void;
|
|
338
|
+
};
|
|
339
|
+
/**
|
|
340
|
+
* Контроллер, который связывается с контекстом карты.
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* controller.bind(ctx);
|
|
344
|
+
*/
|
|
345
|
+
export type MapController = {
|
|
346
|
+
/** Связать контроллер с контекстом. */
|
|
347
|
+
bind: (ctx: MapContext) => void;
|
|
348
|
+
/** Освободить ресурсы при отвязке (опционально). */
|
|
349
|
+
unbind?: () => void;
|
|
350
|
+
};
|
|
351
|
+
/**
|
|
352
|
+
* Описание фичи: геометрия, стиль, взаимодействия и popup.
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* const feature: FeatureDescriptor<Model, Geometry, StyleOpts> = { ... };
|
|
356
|
+
*/
|
|
357
|
+
export interface FeatureDescriptor<M, G extends Geometry, OPTS extends object> {
|
|
358
|
+
/** Получение идентификатора модели. */
|
|
359
|
+
id: (model: M) => string | number;
|
|
360
|
+
/** Синхронизация модели и геометрии. */
|
|
361
|
+
geometry: {
|
|
362
|
+
/** Преобразование модели в геометрию. */
|
|
363
|
+
fromModel: (model: M) => G;
|
|
364
|
+
/** Применение геометрии к модели (immutable). */
|
|
365
|
+
applyGeometryToModel: (prev: M, geometry: G) => M;
|
|
366
|
+
/** Хук после создания фичи. */
|
|
367
|
+
onCreate?: (args: {
|
|
368
|
+
feature: Feature<G>;
|
|
369
|
+
model: M;
|
|
370
|
+
ctx: MapContext;
|
|
371
|
+
}) => void;
|
|
372
|
+
};
|
|
373
|
+
/** Настройка стилей. */
|
|
374
|
+
style: {
|
|
375
|
+
/** Базовые параметры стиля с учётом LOD. */
|
|
376
|
+
base: MaybeFn<OPTS, [model: M, view: StyleView]>;
|
|
377
|
+
/** Патчи по состояниям (объединяются с base). */
|
|
378
|
+
states?: Partial<Record<FeatureStyleState, MaybeFn<Patch<OPTS>, [model: M, view: StyleView]>>>;
|
|
379
|
+
/** Рендер стиля по параметрам. */
|
|
380
|
+
render: (opts: OPTS, view: StyleView) => Style | Style[];
|
|
381
|
+
/** Опциональный ключ кеша. */
|
|
382
|
+
cacheKey?: (opts: OPTS, view: StyleView) => string;
|
|
383
|
+
/** Приоритет слияния состояний. */
|
|
384
|
+
statePriority?: FeatureStyleState[];
|
|
385
|
+
};
|
|
386
|
+
/**
|
|
387
|
+
* Интеракции слоя.
|
|
388
|
+
* Поведение описано в `contract.md`.
|
|
389
|
+
*/
|
|
390
|
+
interactions?: {
|
|
391
|
+
/**
|
|
392
|
+
* Обработка клика по фиче.
|
|
393
|
+
*/
|
|
394
|
+
click?: InteractionBase & {
|
|
395
|
+
/** Переопределение hitTolerance для клика. */
|
|
396
|
+
hitTolerance?: number;
|
|
397
|
+
/** Коллбек клика по фичам текущего слоя. */
|
|
398
|
+
onClick: (args: {
|
|
399
|
+
items: Array<HitItem<M, G>>;
|
|
400
|
+
ctx: MapContext;
|
|
401
|
+
event: MapBrowserEvent<UIEvent>;
|
|
402
|
+
}) => InteractionHandlerResult;
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* Обработка двойного клика по фиче.
|
|
406
|
+
*/
|
|
407
|
+
doubleClick?: InteractionBase & {
|
|
408
|
+
/** Переопределение hitTolerance для doubleClick. */
|
|
409
|
+
hitTolerance?: number;
|
|
410
|
+
/** Коллбек двойного клика по фичам текущего слоя. */
|
|
411
|
+
onDoubleClick: (args: {
|
|
412
|
+
items: Array<HitItem<M, G>>;
|
|
413
|
+
ctx: MapContext;
|
|
414
|
+
event: MapBrowserEvent<UIEvent>;
|
|
415
|
+
}) => InteractionHandlerResult;
|
|
416
|
+
};
|
|
417
|
+
/**
|
|
418
|
+
* Hover-взаимодействие: вход и выход указателя.
|
|
419
|
+
*/
|
|
420
|
+
hover?: InteractionBase & {
|
|
421
|
+
/** Переопределение hitTolerance для hover. */
|
|
422
|
+
hitTolerance?: number;
|
|
423
|
+
/** Указатель вошёл в фичи текущего слоя. */
|
|
424
|
+
onEnter?: (args: {
|
|
425
|
+
items: Array<HitItem<M, G>>;
|
|
426
|
+
ctx: MapContext;
|
|
427
|
+
event: MapBrowserEvent<UIEvent>;
|
|
428
|
+
}) => InteractionHandlerResult;
|
|
429
|
+
/** Указатель вышел из фич текущего слоя. */
|
|
430
|
+
onLeave?: (args: {
|
|
431
|
+
items: Array<HitItem<M, G>>;
|
|
432
|
+
ctx: MapContext;
|
|
433
|
+
event: MapBrowserEvent<UIEvent>;
|
|
434
|
+
}) => InteractionHandlerResult;
|
|
435
|
+
};
|
|
436
|
+
/**
|
|
437
|
+
* Select-взаимодействие: выбор фич и очистка выбора.
|
|
438
|
+
*/
|
|
439
|
+
select?: InteractionBase & {
|
|
440
|
+
/** Переопределение hitTolerance для select. */
|
|
441
|
+
hitTolerance?: number;
|
|
442
|
+
/** Выбраны фичи текущего слоя. */
|
|
443
|
+
onSelect?: (args: {
|
|
444
|
+
items: Array<HitItem<M, G>>;
|
|
445
|
+
ctx: MapContext;
|
|
446
|
+
event: MapBrowserEvent<UIEvent>;
|
|
447
|
+
}) => InteractionHandlerResult;
|
|
448
|
+
/** Очистка выбора текущего слоя. */
|
|
449
|
+
onClear?: (args: {
|
|
450
|
+
ctx: MapContext;
|
|
451
|
+
event: MapBrowserEvent<UIEvent>;
|
|
452
|
+
}) => InteractionHandlerResult;
|
|
453
|
+
};
|
|
454
|
+
/** Перетаскивание фичи целиком. */
|
|
455
|
+
translate?: InteractionBase & {
|
|
456
|
+
/** Переопределение hitTolerance для translate. */
|
|
457
|
+
hitTolerance?: number;
|
|
458
|
+
/** Ограничение частоты обновлений при перемещении (мс). */
|
|
459
|
+
moveThrottleMs?: number;
|
|
460
|
+
/**
|
|
461
|
+
* Выбор цели из списка кандидатов на старте.
|
|
462
|
+
*/
|
|
463
|
+
pickTarget?: (args: {
|
|
464
|
+
candidates: Array<HitItem<M, G>>;
|
|
465
|
+
ctx: MapContext;
|
|
466
|
+
event: TranslateEvent;
|
|
467
|
+
}) => HitItem<M, G> | null | undefined;
|
|
468
|
+
/** Старт перемещения. */
|
|
469
|
+
onStart?: (args: {
|
|
470
|
+
item: HitItem<M, G>;
|
|
471
|
+
ctx: MapContext;
|
|
472
|
+
event: TranslateEvent;
|
|
473
|
+
}) => InteractionHandlerResult;
|
|
474
|
+
/** Перемещение в процессе. */
|
|
475
|
+
onChange?: (args: {
|
|
476
|
+
item: HitItem<M, G>;
|
|
477
|
+
ctx: MapContext;
|
|
478
|
+
event: TranslateEvent;
|
|
479
|
+
}) => InteractionHandlerResult;
|
|
480
|
+
/** Завершение перемещения. */
|
|
481
|
+
onEnd?: (args: {
|
|
482
|
+
item: HitItem<M, G>;
|
|
483
|
+
ctx: MapContext;
|
|
484
|
+
event: TranslateEvent;
|
|
485
|
+
}) => InteractionHandlerResult;
|
|
486
|
+
};
|
|
487
|
+
/** Редактирование геометрии (вершины/сегменты). */
|
|
488
|
+
modify?: InteractionBase & {
|
|
489
|
+
/** Переопределение hitTolerance для modify. */
|
|
490
|
+
hitTolerance?: number;
|
|
491
|
+
/** Ограничение частоты обновлений при редактировании (мс). */
|
|
492
|
+
moveThrottleMs?: number;
|
|
493
|
+
/** Стиль хэндлов вершин нативного Modify. */
|
|
494
|
+
vertexStyle?: Style | Style[];
|
|
495
|
+
/**
|
|
496
|
+
* Выбор цели из списка кандидатов на старте.
|
|
497
|
+
*/
|
|
498
|
+
pickTarget?: (args: {
|
|
499
|
+
candidates: Array<HitItem<M, G>>;
|
|
500
|
+
ctx: MapContext;
|
|
501
|
+
event: ModifyEvent;
|
|
502
|
+
}) => HitItem<M, G> | null | undefined;
|
|
503
|
+
/** Старт редактирования. */
|
|
504
|
+
onStart?: (args: {
|
|
505
|
+
item: HitItem<M, G>;
|
|
506
|
+
ctx: MapContext;
|
|
507
|
+
event: ModifyEvent;
|
|
508
|
+
}) => InteractionHandlerResult;
|
|
509
|
+
/** Обновления в процессе. */
|
|
510
|
+
onChange?: (args: {
|
|
511
|
+
item: HitItem<M, G>;
|
|
512
|
+
ctx: MapContext;
|
|
513
|
+
event: ModifyEvent;
|
|
514
|
+
}) => InteractionHandlerResult;
|
|
515
|
+
/** Завершение редактирования. */
|
|
516
|
+
onEnd?: (args: {
|
|
517
|
+
item: HitItem<M, G>;
|
|
518
|
+
ctx: MapContext;
|
|
519
|
+
event: ModifyEvent;
|
|
520
|
+
}) => InteractionHandlerResult;
|
|
521
|
+
};
|
|
522
|
+
};
|
|
523
|
+
/**
|
|
524
|
+
* Формирование элемента popup для фичи.
|
|
525
|
+
*/
|
|
526
|
+
popup?: {
|
|
527
|
+
/** Включённость popup на фичах. */
|
|
528
|
+
enabled?: Enabled;
|
|
529
|
+
/** Создание popup-элемента. */
|
|
530
|
+
item: (args: {
|
|
531
|
+
model: M;
|
|
532
|
+
feature: Feature<G>;
|
|
533
|
+
ctx: MapContext;
|
|
534
|
+
event?: MapBrowserEvent<UIEvent>;
|
|
535
|
+
}) => PopupItem<M>;
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Конфигурация кластеризации слоя.
|
|
540
|
+
*
|
|
541
|
+
* @example
|
|
542
|
+
* clustering: { enabledByDefault: true, clusterStyle: { render } }
|
|
543
|
+
*/
|
|
544
|
+
export type LayerClustering<M> = {
|
|
545
|
+
/** Кластеризация включена по умолчанию. */
|
|
546
|
+
enabledByDefault?: boolean;
|
|
547
|
+
/** Параметры OL Cluster (px). */
|
|
548
|
+
distance?: number;
|
|
549
|
+
minDistance?: number;
|
|
550
|
+
/** Стиль для cluster-feature. */
|
|
551
|
+
clusterStyle: {
|
|
552
|
+
/** Рендер стиля кластера. */
|
|
553
|
+
render: (args: {
|
|
554
|
+
models: M[];
|
|
555
|
+
size: number;
|
|
556
|
+
view: StyleView;
|
|
557
|
+
}) => Style | Style[];
|
|
558
|
+
/** Опциональный ключ кеша. */
|
|
559
|
+
cacheKey?: (args: {
|
|
560
|
+
models: M[];
|
|
561
|
+
size: number;
|
|
562
|
+
view: StyleView;
|
|
563
|
+
}) => string;
|
|
564
|
+
};
|
|
565
|
+
/** Popup для кластера. */
|
|
566
|
+
popup?: {
|
|
567
|
+
/** Включённость popup на кластерах. */
|
|
568
|
+
enabled?: Enabled;
|
|
569
|
+
/** Создание popup-элемента для кластера. */
|
|
570
|
+
item: (args: {
|
|
571
|
+
models: M[];
|
|
572
|
+
size: number;
|
|
573
|
+
ctx: MapContext;
|
|
574
|
+
event?: MapBrowserEvent<UIEvent>;
|
|
575
|
+
}) => PopupItem<M>;
|
|
576
|
+
/** Лимит элементов для кластера (переопределяет popupHost.maxItems). */
|
|
577
|
+
maxItems?: number;
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* Раскрытие кластера при клике.
|
|
581
|
+
*/
|
|
582
|
+
expandOnClick?: {
|
|
583
|
+
/** Режим раскрытия. */
|
|
584
|
+
mode?: 'zoomToExtent' | 'zoomIn';
|
|
585
|
+
/** Паддинги для fit(extent). */
|
|
586
|
+
padding?: ViewFitPadding;
|
|
587
|
+
/** Максимальный зум при fit/zoomIn. */
|
|
588
|
+
maxZoom?: number;
|
|
589
|
+
/** Шаг увеличения для zoomIn. */
|
|
590
|
+
zoomDelta?: number;
|
|
591
|
+
/** Длительность анимации (мс). */
|
|
592
|
+
durationMs?: number;
|
|
593
|
+
/** Хук после раскрытия кластера. */
|
|
594
|
+
onExpanded?: (args: {
|
|
595
|
+
models: M[];
|
|
596
|
+
ctx: MapContext;
|
|
597
|
+
}) => void;
|
|
598
|
+
};
|
|
599
|
+
};
|
|
600
|
+
/**
|
|
601
|
+
* Дескриптор слоя (тип модели + стиль + интеракции).
|
|
602
|
+
*
|
|
603
|
+
* @example
|
|
604
|
+
* const layer: VectorLayerDescriptor<Model, Geometry, StyleOpts> = { id: 'points', feature };
|
|
605
|
+
*/
|
|
606
|
+
export interface VectorLayerDescriptor<M, G extends Geometry, OPTS extends object, ID extends string = string> {
|
|
607
|
+
/** Идентификатор слоя. */
|
|
608
|
+
id: ID;
|
|
609
|
+
/** Человекочитаемое имя слоя. */
|
|
610
|
+
title?: string;
|
|
611
|
+
/** z-index слоя. */
|
|
612
|
+
zIndex?: number;
|
|
613
|
+
/** Видимость слоя по умолчанию. */
|
|
614
|
+
visibleByDefault?: boolean;
|
|
615
|
+
/** Описание фич и поведения слоя. */
|
|
616
|
+
feature: FeatureDescriptor<M, G, OPTS>;
|
|
617
|
+
/** Кластеризация слоя (опционально). */
|
|
618
|
+
clustering?: LayerClustering<M>;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Схема карты: слои + общие настройки.
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* const schema: MapSchema<typeof layers> = { layers };
|
|
625
|
+
*/
|
|
626
|
+
export interface MapSchema<Layers extends readonly VectorLayerDescriptor<any, any, any, any>[]> {
|
|
627
|
+
/** Список слоёв. */
|
|
628
|
+
layers: Layers;
|
|
629
|
+
/** Глобальные опции карты. */
|
|
630
|
+
options?: {
|
|
631
|
+
/** Глобальное значение hitTolerance по умолчанию. */
|
|
632
|
+
hitTolerance?: number;
|
|
633
|
+
/** Параметры планировщика invalidate/changed. */
|
|
634
|
+
scheduler?: {
|
|
635
|
+
/** Политика flush по умолчанию. */
|
|
636
|
+
policy?: FlushPolicy;
|
|
637
|
+
/** Политика flush для translate/modify. */
|
|
638
|
+
interactionPolicy?: FlushPolicy;
|
|
639
|
+
};
|
|
640
|
+
/**
|
|
641
|
+
* Глобальный popup-хост.
|
|
642
|
+
*/
|
|
643
|
+
popupHost?: {
|
|
644
|
+
/** Включённость popup-хоста. */
|
|
645
|
+
enabled?: Enabled;
|
|
646
|
+
/** Автоматический режим показа. */
|
|
647
|
+
autoMode?: 'off' | 'click' | 'hover';
|
|
648
|
+
/** Максимум элементов в списке. */
|
|
649
|
+
maxItems?: number;
|
|
650
|
+
/** Сортировка popup-элементов. */
|
|
651
|
+
sort?: (a: PopupItem<any>, b: PopupItem<any>) => number;
|
|
652
|
+
/** Куда монтировать popup-хост. */
|
|
653
|
+
mount?: HTMLElement | (() => HTMLElement);
|
|
654
|
+
/** Стек поверх других popup-хостов. */
|
|
655
|
+
stack?: 'stop' | 'continue';
|
|
656
|
+
};
|
|
657
|
+
};
|
|
658
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type Geometry from 'ol/geom/Geometry';
|
|
2
|
+
import type ClusterSource from 'ol/source/Cluster';
|
|
3
|
+
import type VectorSource from 'ol/source/Vector';
|
|
4
|
+
import { VectorLayerBase, VectorLayerBaseOptions } from './vector-layer-base';
|
|
5
|
+
export type ClusteredLayerOptions<M, G extends Geometry, OPTS extends object> = VectorLayerBaseOptions<M, G, OPTS> & {
|
|
6
|
+
clusterSource: ClusterSource;
|
|
7
|
+
};
|
|
8
|
+
export declare class ClusteredVectorLayer<M, G extends Geometry, OPTS extends object> extends VectorLayerBase<M, G, OPTS> {
|
|
9
|
+
private readonly clusterSource;
|
|
10
|
+
private clusteringEnabled;
|
|
11
|
+
constructor(options: ClusteredLayerOptions<M, G, OPTS>);
|
|
12
|
+
setModels(models: readonly M[]): void;
|
|
13
|
+
setClusteringEnabled(enabled: boolean): void;
|
|
14
|
+
isClusteringEnabled(): boolean;
|
|
15
|
+
private clearInteractionStates;
|
|
16
|
+
protected getCenterOnAllModelsSource(): VectorSource<G> | null;
|
|
17
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type Feature from 'ol/Feature';
|
|
2
|
+
import type Geometry from 'ol/geom/Geometry';
|
|
3
|
+
export declare class FeatureRegistry<M, G extends Geometry> {
|
|
4
|
+
private readonly idToModel;
|
|
5
|
+
private readonly idToFeature;
|
|
6
|
+
private readonly featureToId;
|
|
7
|
+
set(id: string | number, model: M, feature: Feature<G>): void;
|
|
8
|
+
updateModel(id: string | number, model: M): void;
|
|
9
|
+
getModel(id: string | number): M | undefined;
|
|
10
|
+
getFeature(id: string | number): Feature<G> | undefined;
|
|
11
|
+
getIdByFeature(feature: Feature<G>): string | number | undefined;
|
|
12
|
+
getModelByFeature(feature: Feature<G>): M | undefined;
|
|
13
|
+
has(id: string | number): boolean;
|
|
14
|
+
remove(id: string | number): Feature<G> | undefined;
|
|
15
|
+
forEachId(fn: (id: string | number) => void): void;
|
|
16
|
+
}
|