/** * Types camera của MDS 3DMap SDK. * * Quy ước từ vựng theo chuẩn web-map quen thuộc (center `[lng, lat]`, * `heading`/`pitch`/`roll` tính bằng độ, `height` tính bằng mét so với ellipsoid). */ /** Toạ độ địa lý `[kinh độ, vĩ độ]` (WGS84, độ thập phân). */ type LngLat = [number, number]; /** Bounding box địa lý `[[lngTây, latNam], [lngĐông, latBắc]]`. */ type LngLatBounds = [LngLat, LngLat]; /** Vị trí camera hiện tại (đầy đủ, luôn xác định). */ interface CameraPosition { /** Điểm camera đang nhìn tới trên mặt đất. */ center: LngLat; /** Độ cao camera (mét). */ height: number; /** Hướng quay quanh trục đứng, 0 = bắc, tăng theo chiều kim đồng hồ (độ). */ heading: number; /** Góc nghiêng so với phương thẳng đứng nhìn xuống: -90 = nhìn thẳng xuống (độ). */ pitch: number; /** Góc xoay quanh trục nhìn (độ). */ roll: number; } /** Đích di chuyển camera — mọi field optional, field thiếu giữ giá trị hiện tại. */ interface CameraTarget { /** * Điểm camera nhìn tới trên mặt đất — CÙNG ngữ nghĩa `CameraPosition.center`, * bảo đảm `jumpTo(getPosition())` đưa camera về đúng khung nhìn hiện tại * (getPosition ↔ jumpTo là nghịch đảo của nhau). */ center?: LngLat; /** Độ cao camera (mét). Ưu tiên hơn `zoom` nếu cả hai cùng có. */ height?: number; /** * Mức zoom kiểu web-map (0–22) — tiện cho người quen SDK 2D; SDK tự quy đổi * sang độ cao tương đương. */ zoom?: number; heading?: number; pitch?: number; roll?: number; } /** Tuỳ chọn animation khi di chuyển camera. */ interface CameraFlyOptions { /** Thời gian bay (giây). Mặc định do SDK chọn theo khoảng cách. */ duration?: number; } /** API camera trên một instance map. */ interface CameraApi { /** Vị trí camera hiện tại. */ getPosition(): CameraPosition; /** Bay mượt tới đích. Promise resolve khi kết thúc (kể cả bị ngắt bởi lệnh mới). */ flyTo(target: CameraTarget, options?: CameraFlyOptions): Promise; /** Nhảy tức thời tới đích, không animation. */ jumpTo(target: CameraTarget): void; /** Đưa toàn bộ bounds vào khung nhìn. */ fitBounds(bounds: LngLatBounds, options?: CameraFlyOptions): Promise; } /** * Hệ thống lỗi công khai của MDS 3DMap SDK. * * Mọi lỗi SDK ném ra hoặc phát qua event `error` đều là `MDSMapError` với * `code` thuộc bộ mã cố định dưới đây — người dùng SDK không bao giờ thấy * lỗi thô của engine hay của tầng HTTP. */ /** Bộ mã lỗi công khai của SDK. */ declare const MDS_ERROR_CODES: readonly ["MDS_INVALID_OPTIONS", "MDS_ENGINE_INIT_FAILED", "MDS_DESTROYED", "MDS_LAYER_INVALID", "MDS_LAYER_LOAD_FAILED", "MDS_AUTH_REQUIRED", "MDS_AUTH_FAILED", "MDS_NETWORK_ERROR", "MDS_UPLOAD_INVALID_FILE", "MDS_UPLOAD_FAILED", "MDS_PROCESSING_FAILED", "MDS_CANCELLED", "MDS_PUBLISH_FAILED", "MDS_NOT_FOUND", "MDS_CONFLICT", "MDS_NOT_IMPLEMENTED", "MDS_MISSING_PEER", "MDS_INTERNAL"]; /** Mã lỗi SDK. */ type MDSErrorCode = (typeof MDS_ERROR_CODES)[number]; /** Lỗi chuẩn của MDS 3DMap SDK. */ declare class MDSMapError extends Error { /** Mã lỗi cố định — dùng để phân nhánh xử lý. */ readonly code: MDSErrorCode; /** Chi tiết bổ sung an toàn để hiển thị/log (không chứa object engine). */ readonly detail?: Record; constructor(code: MDSErrorCode, message: string, detail?: Record, cause?: unknown); } /** Type guard cho lỗi SDK. */ declare function isMDSMapError(err: unknown): err is MDSMapError; /** * Types công khai cho `map.measure` — đo điểm / chiều dài / diện tích / * chênh cao / góc / bán kính / thể tích / chiều cao công trình. */ /** Chế độ đo. */ type MeasureMode = 'point' | 'distance' | 'area' | 'height' | 'building-height' | 'angle' | 'radius' | 'volume' | 'volumeBox'; /** Nguồn cao độ của một điểm pick. */ type MeasureHeightSource = 'scene' | 'terrain' | 'ellipsoid' | 'unavailable' | 'attribute'; /** Một điểm đo WGS84. */ interface MeasurePoint { lon: number; lat: number; height: number | null; heightSource: MeasureHeightSource; } /** * Công trình 3D Tiles đã khoá cho `building-height`. * Chỉ dữ liệu serialize được — không giữ đối tượng Cesium. */ interface MeasureLockedFeature { /** Khoá so-cùng-feature (`tilesetUrl:featureId`). */ key: string; /** Tên đọc từ thuộc tính feature nếu có. */ name: string | null; /** Chiều cao (m) đọc từ thuộc tính tile (LoD1) nếu bộ dữ liệu mang sẵn. */ attributeHeightMeters: number | null; } /** Phiên đo đang soạn (kèm điểm xem trước khi rê chuột). */ interface MeasureSession { mode: MeasureMode; points: MeasurePoint[]; previewPoint: MeasurePoint | null; /** * Chiều cao lăng trụ / hộp (m) — `volume` và `volumeBox`. * Mặc định 3. Kéo chuột nâng khối ghi đè giá trị này. */ prismHeightMeters?: number; /** `draw` = khoanh đáy; `extrude` = kéo nâng khối. */ phase?: 'draw' | 'extrude'; /** Công trình đã khoá — chỉ `building-height`. */ lockedFeature?: MeasureLockedFeature | null; } /** Field chung mọi kết quả đo đã hoàn tất. */ interface MeasureResultMeta { id: string; createdAt: number; } /** Kết quả đo đã hoàn tất — union theo mode. */ type MeasureResult = (MeasureResultMeta & { mode: 'point'; point: MeasurePoint; }) | (MeasureResultMeta & { mode: 'distance'; points: MeasurePoint[]; distanceMeters: number; }) | (MeasureResultMeta & { mode: 'area'; points: MeasurePoint[]; areaSquareMeters: number; }) | (MeasureResultMeta & { mode: 'height'; points: [MeasurePoint, MeasurePoint]; heightMeters: number; }) | (MeasureResultMeta & { mode: 'building-height'; points: [MeasurePoint, MeasurePoint]; heightMeters: number; feature: MeasureLockedFeature | null; }) | (MeasureResultMeta & { mode: 'angle'; points: [MeasurePoint, MeasurePoint, MeasurePoint]; angleDegrees: number; }) | (MeasureResultMeta & { mode: 'radius'; points: [MeasurePoint, MeasurePoint]; radiusMeters: number; }) | (MeasureResultMeta & { mode: 'volume'; points: MeasurePoint[]; areaSquareMeters: number; heightMeters: number; volumeCubicMeters: number; }) | (MeasureResultMeta & { mode: 'volumeBox'; points: [MeasurePoint, MeasurePoint]; widthMeters: number; depthMeters: number; heightMeters: number; volumeCubicMeters: number; }); /** API namespace `map.measure`. */ interface MeasureApi { /** Bắt đầu (hoặc đổi) chế độ đo. */ start(mode: MeasureMode): void; /** Thêm điểm tại toạ độ pixel trong container — chủ yếu cho test. */ addPointAtScreen(screen: [number, number]): void; /** Xoá điểm vừa thêm. */ undo(): void; /** Kết thúc phép đo hiện tại nếu đủ điểm. */ finish(): void; /** Huỷ phiên đang soạn (giữ các kết quả đã hoàn tất). */ cancel(): void; /** Xoá mọi phép đo trên bản đồ. */ clear(): void; /** * Chiều cao lăng trụ / hộp (m) cho `volume` và `volumeBox`. * Không có hiệu lực ở mode khác. Mặc định 3 khi `start`. */ setPrismHeight(meters: number): void; /** * Đặt bán kính (m) sau khi đã bấm tâm ở mode `radius` — tự chốt phép đo. * Kéo chuột tới vành vẫn dùng được. */ setRadius(meters: number): void; /** Hiện / ẩn nhãn số trên overlay. */ setLabelsVisible(visible: boolean): void; /** Nhãn số đang hiện? */ readonly labelsVisible: boolean; /** Xoá một kết quả đã hoàn tất theo `id`. */ removeResult(id: string): void; /** Danh sách kết quả đã hoàn tất (readonly). */ readonly results: readonly MeasureResult[]; /** Chế độ đang đo; `null` khi không đo. */ readonly mode: MeasureMode | null; } /** * Types sự kiện của MDS 3DMap SDK. * * Đăng ký qua `map.on(type, handler)` — type-safe theo `MapEventMap`. */ /** Feature được pick trên bản đồ (một công trình trong tileset MDS...). */ interface PickedFeature { /** Id layer chứa feature. */ layerId: string; /** * Feature id trong tileset (`_FEATURE_ID_0` với tileset MDS). * `null` khi đối tượng pick không mang feature id. */ featureId: number | null; /** * Id công trình bền vững của MDS (map từ feature-map của publication). * `null` với tileset không phải của MDS hoặc chưa resolve được. */ buildingId: string | null; /** * Id asset MDS đứng sau layer chứa feature — chìa khoá để lấy * `map.assets.get(assetId)` rồi GHI thuộc tính. `null` với layer không phải * `type: 'asset'` (tileset3d/geojson/raster trỏ thẳng URL), tức panel chỉ * xem được chứ không sửa được. */ assetId: string | null; /** * Thuộc tính công trình theo schema 10 trường CityGML của MDS * (chỉ có với feature thuộc layer `asset`/tileset MDS đã publish). */ attributes: Partial> | null; /** * `objectId` Digital Twin 3DCityDB khi layer là `catalogLayer`. * `null`/`undefined` với layer MDS processing hoặc tileset URL thuần. */ objectId?: string | null; /** Mã lớp 3DCityDB nếu feature nằm trên `catalogLayer`. */ layerCode?: string | null; /** Custom fields đã resolve từ Data API (layer `catalogLayer`). */ customFields?: Record | null; /** * Cao độ đáy mô hình (WGS84 m) từ envelope Data API — panel dùng đặt gizmo đúng * chân khi anchor không ở đáy. Chỉ có sau khi resolve chi tiết feature. */ footHeight?: number | null; } /** Sự kiện click trên bản đồ. */ interface MapClickEvent { /** Toạ độ địa lý tại điểm click (null khi click ra ngoài globe). */ lngLat: LngLat | null; /** Toạ độ pixel trong container. */ screen: [number, number]; } /** Sự kiện click trúng một feature (chỉ bắn khi pick trúng). */ interface FeatureClickEvent extends MapClickEvent { feature: PickedFeature; } /** Sự kiện liên quan một layer. */ interface LayerEvent { layerId: string; } /** Sự kiện lỗi layer. */ interface LayerErrorEvent extends LayerEvent { error: MDSMapError; } /** Bảng sự kiện công khai của map. */ interface MapEventMap { /** * Map đã khởi tạo xong và render khung hình đầu tiên. * STICKY (audit P2.1): `createMap` resolve SAU khi `ready` đã bắn; handler * đăng ký sau thời điểm đó vẫn được gọi ngay (đồng bộ hoá với microtask). */ ready: void; /** Click bất kỳ trên bản đồ. LUÔN bắn trước `featureClick` cho cùng cú click. */ click: MapClickEvent; /** Click trúng feature có thể pick — bắn SAU `click` của cùng cú click. */ featureClick: FeatureClickEvent; /** Camera dừng sau khi thay đổi (debounced — không bắn từng frame). */ cameraChange: CameraPosition; /** Một layer tải xong. */ layerLoaded: LayerEvent; /** Một layer lỗi khi tải/render. */ layerError: LayerErrorEvent; /** Lỗi runtime không gắn với layer cụ thể. */ error: MDSMapError; /** Phiên đo đang soạn; `null` khi vừa huỷ / Escape / xoá hết. */ measureUpdate: MeasureSession | null; /** Một phép đo vừa hoàn tất. */ measureComplete: MeasureResult; } /** Tên sự kiện hợp lệ. */ type MapEventType = keyof MapEventMap; /** Handler cho một loại sự kiện. */ type MapEventHandler = (payload: MapEventMap[T]) => void; /** Hàm huỷ đăng ký trả về từ `on`. */ type Unsubscribe = () => void; /** * Types quản trị nội dung 3D (upload GLB → xử lý → publish → hiển thị). * * Đây là facade công khai bọc pipeline xử lý mô hình của MDS. Người dùng SDK * chỉ thấy vòng đời đơn giản `uploading → processing → ready`; chi tiết stage * pipeline nằm sau `progress`/`statusChange`. */ /** 10 trường thuộc tính công trình của MDS. */ declare const BUILDING_ATTRIBUTE_FIELDS: readonly ["ten_cong_trinh", "ma_cong_trinh", "chuc_nang", "dia_chi", "so_tang", "chieu_cao_m", "dien_tich_san_m2", "nam_xay_dung", "chu_so_huu", "ghi_chu"]; /** Tên một trường thuộc tính hợp lệ. */ type BuildingAttributeKey = (typeof BUILDING_ATTRIBUTE_FIELDS)[number]; /** * Giới hạn kích thước file GLB SDK chấp nhận (khớp `max_upload_mb=500` của * backend). Nguồn chân lý DUY NHẤT — transport và UI cùng đọc (v2 — D6). */ declare const MAX_UPLOAD_BYTES: number; /** Đuôi file mô hình hợp lệ. */ declare const GLB_FILE_EXTENSION = ".glb"; /** Giá trị một trường thuộc tính. */ type BuildingAttributeValue = string | number | null; /** * Trạng thái asset nhìn từ SDK — GIÁ TRỊ DẪN XUẤT từ backend theo bảng * NORMATIVE dưới đây (audit P1.3). Lane C implement đúng thứ tự ưu tiên; * lane D/E chỉ dựa vào bảng này, không tự suy diễn: * * | Ưu tiên | Điều kiện backend | AssetStatus | * |---------|--------------------------------------------------------------|--------------| * | 1 | File đang truyền (chưa có response upload) | `uploading` | * | 2 | `latestJob.state` ∈ {queued, leased, running} (mọi mode) | `processing` | * | 3 | `latestJob.state = 'cancelled'` | `cancelled` | * | 4 | `asset.status = 'failed'` hoặc `latestJob.state = 'failed'` | `failed` | * | 5 | `activePublicationId != null` | `published` | * | 6 | `asset.status = 'ready'` | `ready` | * | 7 | còn lại (`uploaded`/không job) | `processing` | * * Hệ quả có chủ đích: asset đã publish mà chạy lại job (rebuild/publish mới) * → tạm về `processing` (quy tắc 2 thắng 5) rồi quay lại `published`. * `refresh()` sau này chỉ tin `latestJob` hiện có — đúng bảng, không đoán quá khứ. */ type AssetStatus = 'uploading' | 'processing' | 'ready' | 'published' | 'failed' | 'cancelled'; /** Tuỳ chọn upload. */ interface UploadOptions { /** Tên hiển thị của mô hình. Mặc định lấy từ tên file. */ name?: string; /** Callback tiến độ truyền file 0–100. */ onUploadProgress?: (percent: number) => void; /** Huỷ upload/polling. */ signal?: AbortSignal; } /** Tiến độ tổng hợp của asset. */ interface AssetProgress { status: AssetStatus; /** 0–100 cho pha hiện tại (upload hoặc processing). */ percent: number; /** Mô tả ngắn pha đang chạy, an toàn để hiển thị cho end-user. */ message: string; } /** * Dịch chuyển tinh (mét) trong hệ East-North-Up tại điểm neo. * * Tách khỏi `lng/lat` vì đây là bước CHỈNH TAY sau khi đã đặt điểm neo: người * dùng nhích mô hình vài mét cho khớp hiện trạng mà không phải sửa toạ độ neo. */ interface PlacementOffsetEnu { east: number; north: number; up: number; } /** Vị trí đặt mô hình lên bản đồ (quick-path placement). */ interface PlacementInput { /** Kinh độ điểm neo (WGS84). */ lng: number; /** Vĩ độ điểm neo (WGS84). */ lat: number; /** Độ cao điểm neo so với ellipsoid (mét). Mặc định 0. */ height?: number; /** Hướng xoay quanh trục đứng (độ, 0 = bắc, theo chiều kim đồng hồ). Mặc định 0. */ heading?: number; /** Góc nghiêng (độ). Mặc định 0. */ pitch?: number; /** Góc lăn (độ). Mặc định 0. */ roll?: number; /** Tỷ lệ phóng. Mặc định 1. */ scale?: number; /** Nhích mô hình trong hệ ENU tại điểm neo (mét). Mặc định (0, 0, 0). */ offsetEnu?: PlacementOffsetEnu; } /** Một công trình trong asset (định danh để cập nhật thuộc tính / map pick). */ interface AssetBuildingRef { /** Id công trình bền vững của MDS. */ buildingId: string; /** Feature id trong tileset đã publish (null nếu chưa gán). */ featureId: number | null; } /** Kết quả publish. */ interface PublishResult { publicationId: string; /** * URL tileset công khai TUYỆT ĐỐI — dùng được ngay với * `layers.add({type:'tileset3d'})` từ bất kỳ origin nào. */ tilesetUrl: string; /** Số công trình đã tách được (null nếu backend chưa trả). */ featureCount: number | null; /** * Danh sách công trình của publication này — nguồn `buildingId` cho * `updateBuildingAttributes` ngay sau publish (audit P1.2). */ buildings: AssetBuildingRef[]; } /** Thông tin tóm tắt một asset. */ interface AssetInfo { id: string; name: string; status: AssetStatus; /** Kích thước file gốc (byte). */ sizeBytes: number; createdAt: string; /** Publication đang active (nếu đã publish). */ activePublicationId: string | null; } /** Bảng sự kiện của một asset. */ interface AssetEventMap { /** Trạng thái đổi. */ statusChange: AssetStatus; /** Tiến độ cập nhật (upload % hoặc processing %). */ progress: AssetProgress; } /** Handle theo dõi và điều khiển một asset. */ interface AssetHandle { readonly id: string; readonly name: string; readonly status: AssetStatus; readonly progress: AssetProgress; /** Đăng ký sự kiện. */ on(type: T, handler: (payload: AssetEventMap[T]) => void): Unsubscribe; /** * Chờ asset xử lý xong (`ready`). * Reject `MDS_PROCESSING_FAILED` / `MDS_CANCELLED`. */ waitUntilReady(): Promise; /** * Publish mô hình tại vị trí chỉ định (tạo placement → publication → activate). * Yêu cầu asset `ready`. Resolve khi tileset công khai sẵn sàng. * `options.signal` huỷ việc CHỜ phía client (reject `MDS_CANCELLED`) — * KHÔNG rollback các bước backend đã chạy. (v1 — C4) */ publish(placement: PlacementInput, options?: { signal?: AbortSignal; }): Promise; /** * Danh sách công trình của asset (theo publication active nếu đã publish, * ngược lại theo kết quả build mới nhất). */ listBuildings(): Promise; /** Cập nhật thuộc tính cho các công trình của asset (theo buildingId). */ updateBuildingAttributes(buildingId: string, attributes: Partial>): Promise; /** Yêu cầu huỷ pipeline đang chạy. */ cancel(): Promise; /** Làm mới thông tin từ server. */ refresh(): Promise; /** * Dừng theo dõi asset: huỷ vòng poll trạng thái và gỡ mọi listener của handle. * Mọi `waitUntilReady()` đang chờ reject `MDS_CANCELLED`. Sau khi dispose, * `on()` không khởi động lại vòng poll. Idempotent; các getter đồng bộ * (`status`/`progress`/`name`) vẫn đọc được giá trị cuối cùng đã biết. (v1 — C5) */ dispose(): void; } /** Tham số liệt kê asset. */ interface AssetListParams { page?: number; pageSize?: number; search?: string; } /** Kết quả liệt kê asset. */ interface AssetListResult { items: AssetInfo[]; total: number; page: number; pageSize: number; } /** API quản trị asset trên một instance map. */ interface AssetsApi { /** * Upload file GLB kèm tuỳ chọn. Resolve ngay khi server nhận xong file và * pipeline bắt đầu chạy — theo dõi tiếp qua `AssetHandle`. * Reject `MDS_UPLOAD_INVALID_FILE` / `MDS_UPLOAD_FAILED` / `MDS_AUTH_REQUIRED`. */ upload(file: File | Blob, options?: UploadOptions): Promise; /** Lấy handle của asset đã tồn tại. */ get(assetId: string): Promise; /** Liệt kê asset của tài khoản. */ list(params?: AssetListParams): Promise; } /** * Types công khai cho `map.catalog` — client Digital Twin 3DCityDB V2. * * Tách khỏi `map.assets` vì mô hình dữ liệu khác hoàn toàn * (layer / model / feature / customFields, không có asset/job/publication). */ type CatalogFieldDataType = 'string' | 'int' | 'double' | 'boolean'; /** Cách vẽ ô nhập trên form (schema `viewType`). */ type CatalogFieldViewType = 'text' | 'textarea' | 'number' | 'checkbox' | 'date' | 'datetime'; /** Ràng buộc số của custom field. */ interface CatalogFieldConstraints { min?: number; max?: number; } /** Giá trị primitive mà custom field chấp nhận. */ type CatalogFieldPrimitive = string | number | boolean | null; /** Schema một trường nghiệp vụ của lớp. */ interface CatalogCustomField { id?: string; code: string; name: string; dataType: CatalogFieldDataType; required?: boolean; nullable?: boolean; writable?: boolean; constraints?: CatalogFieldConstraints; viewType?: CatalogFieldViewType; note?: string; group?: string; } /** Cặp code/value khi ghi custom field. */ interface CatalogFieldValue { code: string; value: CatalogFieldPrimitive; } /** * 16 tham số định vị không gian (Universal Spatial Placement). * Field bắt buộc khi upload: `lon`, `lat`. Còn lại SDK điền smart default. */ interface CatalogPlacement { lon: number; lat: number; height?: number; heightOffset?: number; heading?: number; pitch?: number; roll?: number; scale?: number; scaleX?: number; scaleY?: number; scaleZ?: number; altitudeMode?: 'clampToGround' | 'relativeToGround' | 'absolute'; anchorMode?: 'bottomCenter' | 'center' | 'origin'; sourceUpAxis?: 'Y_UP' | 'Z_UP'; sourceUnit?: 'METER' | 'CENTIMETER' | 'MILLIMETER' | 'FOOT'; address?: string; } /** * Placement dạng bộ phận — dùng cho CẢ HAI chiều: * - request: patch của `PUT .../placement` (chỉ gửi field muốn đổi); * - response: server chỉ ECHO các field liên quan (ví dụ `PUT .../placement` * không trả lại `lon`/`lat`), nên mọi placement đọc về đều là bộ phận. * * SDK dịch `scaleUniform` của server thành `scale` trước khi trả ra. */ type CatalogPlacementPatch = Partial; /** Bounding box WGS84 do discovery trả về. */ interface CatalogBoundingBox { minLon: number; minLat: number; maxLon: number; maxLat: number; minZ?: number; maxZ?: number; } /** Lớp dữ liệu được cấp quyền. */ interface CatalogLayerInfo { layerId: string; layerCode: string; layerName: string; is3DCityDBEnabled: boolean; totalFeatures: number; activeMasterRevisionId: string | null; activePatchCount: number; boundingBox: CatalogBoundingBox | null; /** URL tuyệt đối tới tileset.json, đã gắn đúng tiền tố `/api/data`. */ tilesetUrl: string; allowedActions: string[]; isPublic: boolean; } /** Đối tượng 3D trên một lớp. */ interface CatalogFeature { objectId: string; externalId: string | null; layerCode: string; status: string | null; placement: CatalogPlacementPatch | null; /** * Cao độ ĐÁY mô hình trong hệ WGS84 (mét), từ `envelope.minHeight` server trả. * Dùng đặt gizmo đúng chân khi `anchorMode` không đưa anchor về đáy. `null` nếu * API không trả envelope. */ footHeight?: number | null; /** ISO 8601 thời điểm tạo/cập nhật (nếu API trả) — dùng chọn model mới nhất. */ createdAt?: string | null; updatedAt?: string | null; customFields: CatalogFieldValue[]; /** Bản đồ code → value, tiện bind form. */ customFieldMap: Record; } /** Tham số liệt kê feature. */ interface CatalogFeatureListParams { page?: number; pageSize?: number; sortBy?: string; sortDirection?: 'asc' | 'desc'; q?: string; bbox?: string; status?: string; } interface CatalogFeatureListResult { items: CatalogFeature[]; total: number; page: number; pageSize: number; } /** Kết quả upload model. */ interface CatalogUploadResult { objectId: string; externalId: string | null; layerCode: string; assetId: string | null; sizeBytes: number | null; placement: CatalogPlacementPatch | null; customFieldsApplied: boolean; status: string | null; jobId: string | null; } /** Tuỳ chọn upload. */ interface CatalogUploadOptions { /** Bỏ trống → dùng `MapOptions.catalogLayerCode`. */ layerCode?: string; placement: CatalogPlacement; customFields?: CatalogFieldValue[]; externalId?: string; /** Upload bất đồng bộ rồi poll `GET /jobs/{jobId}`. */ asyncMode?: boolean; onUploadProgress?: (percent: number) => void; signal?: AbortSignal; } /** * Tuỳ chọn tạo lớp dữ liệu mới (bước 2 của tài liệu tích hợp). * * Cần API key có scope `citydb.layers.manage` — thiếu scope thì server trả * 403 `INSUFFICIENT_SCOPE` và SDK ném `MDS_AUTH_FAILED`. */ interface CatalogCreateLayerOptions { /** Tên hiển thị của lớp (bắt buộc). */ name: string; nameEn?: string; /** * Mã lớp mong muốn. * * Tài liệu bàn giao KHÔNG khai field này trong request nhưng response lại * trả `layerCode` — nghĩa là server tự sinh mã. SDK gửi kèm nếu bạn truyền, * và luôn đọc `layerCode` THẬT từ response thay vì giả định. */ code?: string; /** Mặc định `http://www.opengis.net/citygml/building/2.0`. */ semanticNamespaceUri?: string; /** Mặc định `Building`. */ semanticClassIdentifier?: string; /** Mặc định `http://www.opengis.net/citygml/building/2.0`. */ geometryPropertyNamespaceUri?: string; /** Mặc định `lod2Solid`. */ geometryPropertyName?: string; /** Mặc định `Solid`. */ geometryDatatypeIdentifier?: string; /** Mặc định `'2'`. */ geometryLod?: string; /** Mặc định `false` — lớp chỉ đọc được bằng key có quyền. */ isPublic?: boolean; /** Schema thuộc tính nghiệp vụ khai ngay lúc tạo lớp. */ customFields?: CatalogCustomField[]; signal?: AbortSignal; } /** Kết quả tạo lớp. */ interface CatalogCreateLayerResult { layerId: string; layerCode: string; layerName: string; customFieldsCount: number; allowedActions: string[]; } /** Tuỳ chọn cập nhật custom fields. */ interface CatalogUpdateFieldsOptions { layerCode?: string; /** File GLB mới — chỉ cần khi thay geometry, không cần khi chỉ sửa metadata. */ modelFile?: File; /** `merge` (mặc định) hoặc `replace` tuỳ backend. */ attributeUpdateMode?: 'merge' | 'replace'; signal?: AbortSignal; } /** Tuỳ chọn xoá mô hình. */ interface CatalogDeleteOptions { layerCode?: string; /** * Gọi `POST .../consolidate` sau khi xoá. Mặc định `true`. * Lỗi consolidate không làm `deleteModel` reject. */ consolidate?: boolean; signal?: AbortSignal; } /** Kết quả xoá mô hình. */ interface CatalogDeleteResult { /** `true` khi bước consolidate thành công. */ consolidated: boolean; /** Có khi `consolidated: false` vì bước consolidate hỏng — mô hình đã xoá. */ consolidateError?: MDSMapError; } /** API namespace `map.catalog`. */ interface CatalogApi { /** Danh sách lớp được cấp quyền (Discovery). */ listLayers(signal?: AbortSignal): Promise; /** Tạo lớp dữ liệu mới kèm schema custom fields. Cần scope `citydb.layers.manage`. */ createLayer(options: CatalogCreateLayerOptions): Promise; /** Chi tiết một lớp theo `layerCode`. */ getLayer(layerCode: string, signal?: AbortSignal): Promise; /** Schema custom fields của lớp (cache trong bộ nhớ theo `layerCode`, không dùng ETag). */ getCustomFields(layerCode: string, signal?: AbortSignal): Promise; listFeatures(layerCode: string, params?: CatalogFeatureListParams, signal?: AbortSignal): Promise; getFeature(layerCode: string, objectId: string, signal?: AbortSignal): Promise; /** Upload GLB kèm placement + custom fields. */ upload(file: File, options: CatalogUploadOptions): Promise; /** * Cập nhật định vị không gian (độ trễ thấp). * * Trả về placement mà server echo — BỘ PHẬN, chỉ gồm field vừa đổi. */ updatePlacement(objectId: string, patch: CatalogPlacementPatch, options?: { layerCode?: string; signal?: AbortSignal; }): Promise; /** Cập nhật custom fields (và tuỳ chọn thay geometry). */ updateCustomFields(objectId: string, fields: CatalogFieldValue[], options?: CatalogUpdateFieldsOptions): Promise; /** * Xoá mô hình. Mặc định gọi tiếp `consolidate` (hỏng consolidate không làm * lời gọi reject — mô hình đã xoá thật). */ deleteModel(objectId: string, options?: CatalogDeleteOptions): Promise; /** Hợp nhất Active Patch vào master tileset của lớp. */ consolidate(layerCode?: string, signal?: AbortSignal): Promise; /** * URL tuyệt đối `tileset.json` của lớp, kèm header xác thực cho Cesium Resource. * Dùng khi tự thêm layer `type: 'tileset3d'` thay vì `type: 'catalogLayer'`. */ resolveTileset(layerCode: string, signal?: AbortSignal): Promise<{ url: string; headers: Record; boundingBox: CatalogBoundingBox | null; }>; /** * Trạng thái một job xử lý bất đồng bộ (`GET /jobs/{jobId}`). * * Upload lớn (point-cloud / mesh vượt ngưỡng async) trả `jobId`; `upload()` tự * poll tới trạng thái terminal nên thường không cần gọi trực tiếp, trừ khi tự * dựng luồng upload riêng. */ getJob(jobId: string, signal?: AbortSignal): Promise; /** * Ma trận đặt chỗ (ECEF column-major) của mọi feature — áp placement API lên * tileset sau khi nạp (server không re-bake khi `updatePlacement`), qua đường * runtime `setFeatureModelMatrix`. Chỉ feature có placement thật. */ listPlacementMatrices(layerCode: string, signal?: AbortSignal): Promise>; /** * Đợi tileset giao hàng phản ánh thay đổi KHÔNG có `jobId` (chủ yếu là xoá → * consolidate). Truyền `baseline` chụp bằng `getLayer` TRƯỚC khi thay đổi; poll * tới khi chữ ký revision khác baseline rồi hãy reload lớp. Hết `timeoutMs` vẫn * trả bản mới nhất (không throw). Upload dùng `getJob`/poll trong `upload()`. */ waitForDelivery(layerCode: string, baseline: Pick, options?: { timeoutMs?: number; intervalMs?: number; signal?: AbortSignal; }): Promise; /** Header xác thực hiện tại — gắn vào request tileset con. */ authHeaders(): Promise>; } /** Trạng thái job xử lý mô hình phía backend (`GET /api/citydb/v2/jobs/{jobId}`). */ interface CatalogJobStatus { jobId: string; /** `Queued | Running | RetryWait | Completed | Failed | Cancelled`. */ status: string; /** 0–100 nếu backend báo tiến trình. */ progress: number | null; errorCode: string | null; errorMessage: string | null; } /** Job kết thúc — không cần poll tiếp. */ declare const CATALOG_TERMINAL_JOB_STATUSES: readonly ["Completed", "Failed", "Cancelled"]; /** * Types GeoJSON tối giản, SDK-owned (RFC 7946). * * Cố ý không dùng `@types/geojson` để public `.d.ts` tự chứa — * người dùng SDK không phải cài thêm bất kỳ package types nào. */ /** Toạ độ một điểm `[lng, lat]` hoặc `[lng, lat, alt]`. */ type GeoJsonPosition = [number, number] | [number, number, number]; interface GeoJsonPoint { type: 'Point'; coordinates: GeoJsonPosition; } interface GeoJsonMultiPoint { type: 'MultiPoint'; coordinates: GeoJsonPosition[]; } interface GeoJsonLineString { type: 'LineString'; coordinates: GeoJsonPosition[]; } interface GeoJsonMultiLineString { type: 'MultiLineString'; coordinates: GeoJsonPosition[][]; } interface GeoJsonPolygon { type: 'Polygon'; coordinates: GeoJsonPosition[][]; } interface GeoJsonMultiPolygon { type: 'MultiPolygon'; coordinates: GeoJsonPosition[][][]; } /** Union các geometry hỗ trợ (không gồm GeometryCollection ở v1). */ type GeoJsonGeometry = GeoJsonPoint | GeoJsonMultiPoint | GeoJsonLineString | GeoJsonMultiLineString | GeoJsonPolygon | GeoJsonMultiPolygon; interface GeoJsonFeature { type: 'Feature'; geometry: GeoJsonGeometry | null; properties: Record | null; id?: string | number; } interface GeoJsonFeatureCollection { type: 'FeatureCollection'; features: GeoJsonFeature[]; } /** Một tài liệu GeoJSON hợp lệ cho `GeoJsonLayerDescriptor.data`. */ type GeoJsonObject = GeoJsonGeometry | GeoJsonFeature | GeoJsonFeatureCollection; /** * Types layer của MDS 3DMap SDK. * * Layer được khai báo bằng `LayerDescriptor` (discriminated union theo `type`) * và điều khiển qua `LayerHandle` — instance-scoped, không dùng id string toàn cục. */ /** Thuộc tính chung của mọi layer. */ interface LayerCommonOptions { /** * Id tuỳ chọn do người dùng đặt (duy nhất trong một map instance). * Bỏ trống → SDK tự sinh. */ id?: string; /** Tên hiển thị (dùng trong LayerPanel). */ name?: string; /** Hiển thị ngay khi thêm. Mặc định `true`. */ visible?: boolean; /** Ẩn layer khi zoom nhỏ hơn mức này. */ minZoom?: number; /** Ẩn layer khi zoom lớn hơn mức này. */ maxZoom?: number; } /** Layer 3D Tiles (mô hình thành phố, kết quả publish của MDS...). */ interface Tileset3dLayerDescriptor extends LayerCommonOptions { type: 'tileset3d'; /** URL tới `tileset.json`. */ url: string; /** * Header đính vào mọi request của tileset (tileset.json và tile con). * Bắt buộc khi tileset Digital Twin yêu cầu `X-API-Key`. */ headers?: Record; } /** Layer từ lớp 3DCityDB — SDK tự discovery tilesetUrl và gắn header auth. */ interface CatalogLayerDescriptor extends LayerCommonOptions { type: 'catalogLayer'; /** Mã lớp (ví dụ `8uY3LTiDRy`). */ layerCode: string; /** Bay camera tới bbox của lớp sau khi tải. Mặc định `true`. */ fit?: boolean; } /** * Vị trí + hướng + tỉ lệ của một mô hình đơn lẻ. * * Cùng ngôn ngữ với placement của Digital Twin (`map.catalog.updatePlacement`) * nên xem trước tại chỗ và bản sau khi upload dùng CHUNG một bộ số — không * phải quy đổi giữa hai hệ. */ interface ModelPlacement { lon: number; lat: number; /** Cao độ so với ellipsoid (m). Mặc định 0. */ height?: number; /** Xoay quanh trục đứng (độ). Mặc định 0. */ heading?: number; /** Ngẩng/cúi quanh trục Bắc (độ). Mặc định 0. */ pitch?: number; /** Nghiêng quanh trục Đông (độ). Mặc định 0. */ roll?: number; /** Hệ số phóng to đều. Mặc định 1. */ scale?: number; } /** * Layer một mô hình glTF/GLB. * * Dùng cho XEM TRƯỚC file người dùng vừa chọn (`URL.createObjectURL(file)`) * trước khi upload, và cho mô hình lẻ đã có URL. Đổi vị trí sau khi thêm bằng * `map.layers.setModelPlacement(layerId, placement)` — không cần gỡ và thêm lại. */ interface ModelLayerDescriptor extends LayerCommonOptions { type: 'model'; /** URL `.glb`/`.gltf`. Nhận cả `blob:` của file cục bộ. */ url: string; placement: ModelPlacement; /** Header đính vào request tải model (model sau gateway cần `X-API-Key`). */ headers?: Record; } /** Style cơ bản cho layer GeoJSON. */ interface GeoJsonStyle { /** Màu nét (CSS color). */ strokeColor?: string; /** Bề rộng nét (px). */ strokeWidth?: number; /** Màu tô vùng (CSS color, hỗ trợ alpha). */ fillColor?: string; /** Đùn polygon thành khối theo chiều cao (mét) — đọc từ thuộc tính này của feature. */ extrudeHeightProperty?: string; /** * Màu ghim mặc định cho Point (CSS color). Từng feature vẫn có thể ghi đè * bằng simplestyle `properties['marker-color']`. */ markerColor?: string; /** Kích thước ghim mặc định (px). Feature ghi đè bằng `marker-size` (`small`/`medium`/`large`). */ markerSize?: number; /** * Ký hiệu ghim mặc định: 1 ký tự, hoặc id icon Maki. * Feature ghi đè bằng `properties['marker-symbol']`. */ markerSymbol?: string; /** URL ảnh billboard áp cho mọi điểm sau khi nạp (ghi đè ghim). */ iconUrl?: string; /** Tên thuộc tính feature chứa URL ảnh billboard (ưu tiên hơn `iconUrl` khi có giá trị). */ iconProperty?: string; /** Tên thuộc tính feature dùng làm nhãn cạnh điểm. */ labelProperty?: string; } /** Layer GeoJSON (điểm/đường/vùng). */ interface GeoJsonLayerDescriptor extends LayerCommonOptions { type: 'geojson'; /** URL tới file GeoJSON. Dùng một trong `url` hoặc `data`. */ url?: string; /** Dữ liệu GeoJSON inline. */ data?: GeoJsonObject; style?: GeoJsonStyle; } /** Layer raster dạng XYZ template hoặc WMS. */ interface RasterLayerDescriptor extends LayerCommonOptions { type: 'raster'; /** * XYZ: URL template chứa `{z}/{x}/{y}`. * WMS: URL gốc của service (kèm `wmsLayers`). */ url: string; /** Danh sách layer WMS (phân tách bằng dấu phẩy). Có mặt → hiểu là WMS. */ wmsLayers?: string; /** Độ mờ 0–1. Mặc định 1. */ opacity?: number; } /** Layer từ asset đã upload qua MDS (tự resolve publication đang active). */ interface AssetLayerDescriptor extends LayerCommonOptions { type: 'asset'; /** Id asset trả về từ `map.assets.upload()`. */ assetId: string; /** Ghim một publication cụ thể thay vì bản active. */ publicationId?: string; } /** * Layer mô hình 3D từ tile điểm (ví dụ `terrain_3d_model_gis`). * * Mỗi feature điểm mang `model_url` trỏ tệp mô hình (OBJ/GLB) trên storage; SDK * đọc điểm trong khung nhìn rồi tải mô hình từng công trình, có trần số lượng. * Model OBJ được chuyển sang GLB bằng bộ chuyển đổi tải-lười đi kèm SDK. */ interface TilemapModelLayerDescriptor extends LayerCommonOptions { type: 'tilemapModel'; /** Tên source-layer trong tile. Bỏ trống → `terrain_3d_model_gis`. */ layerName?: string; /** Base URL server vector tile. Bỏ trống → nguồn công khai của MDS. */ url?: string; /** Tên map chứa lớp. Bỏ trống → `gis_data`. */ mapName?: string; /** Base URL storage để giải `model_url` tương đối. Bỏ trống → storage MDS. */ storageBaseUrl?: string; /** Header đính vào request tải mô hình (nếu storage cần auth). */ headers?: Record; /** Mức zoom lấy tile đối tượng. Mặc định 14. */ featureTileZoom?: number; /** Trần số mô hình dựng đồng thời. Mặc định 40. */ maxModels?: number; /** Bán kính vùng tải quanh điểm nhìn (m). Mặc định 700. */ focusRadius?: number; /** Cao độ camera tối đa còn dựng mô hình (m). Mặc định 2000. */ maxCameraHeight?: number; } /** * Lớp nhãn địa danh tiếng Việt từ vector tile (Tegola / GoMaps mapsrv). * * Giai đoạn 1: quốc gia + hành chính + đảo (`world_point_label`, `admin_point` / * `_province` / `_ward`). * Không tránh chồng chữ như MapLibre, và không gom cụm (`EntityCluster` thay chữ * bằng con số) — chỉ lọc theo zoom, gộp nhãn cùng tên đè nhau, và giới hạn số nhãn. */ interface PlaceLabelsLayerDescriptor extends LayerCommonOptions { type: 'placeLabels'; /** * Base URL server vector tile. Bỏ trống → Tegola công khai * (`https://bansaoso.vnptit.vn/vector-tiles`). * GoMaps mapsrv: `https://gomaps.vnpt.vn/mapsrv` kèm `tileExtension` + `apiKey`. */ url?: string; /** Tên map chứa lớp nhãn. Bỏ trống → `basemap`. */ mapName?: string; /** * Đuôi file tile. Tegola: `pbf` (mặc định). GoMaps mapsrv: `vector.pbf`. */ tileExtension?: string; /** API key khi nguồn mapsrv yêu cầu `?apiKey=`. Tegola không cần. */ apiKey?: string; /** Header đính vào request tile (nếu nguồn cần auth). */ headers?: Record; /** Trần số nhãn được vẽ sau khi xét va chạm màn hình. Mặc định 80. */ maxLabels?: number; /** Trần số tile tải mỗi lượt (ưu tiên ô gần tâm nhìn). Mặc định 24. */ maxTiles?: number; /** * Preset màu style GoMaps. `'gomaps'` giữ màu gốc (đường trong suốt 30%). * `'google'` đổi màu theo nhóm, giữ nguyên độ rộng / zoom / filter. * Mặc định `'gomaps'`. Nên trùng với lớp `roads`. */ stylePreset?: 'gomaps' | 'google'; } /** * Lớp đường VNPT từ vector tile Tegola `transportation` (cùng nguồn với GoMaps). * * Vẽ thành ImageryLayer trong suốt phủ nền `satellite`. Nền `streets`/`hybrid` * đã có đường/chữ sẵn — lớp này tự ẩn, không huỷ; đổi về satellite thì hiện lại. * Mặc định bật lúc `createMap()` qua `defaultLayers.roads`. Gồm đường, cầu, hầm, * ranh giới, tên sông, mũi tên một chiều. Khiên số hiệu vẽ ở lớp `placeLabels`. */ interface RoadsLayerDescriptor extends LayerCommonOptions { type: 'roads'; /** * Base URL server vector tile. Bỏ trống → Tegola công khai * (`https://bansaoso.vnptit.vn/vector-tiles`). */ url?: string; /** Tên map chứa lớp đường. Bỏ trống → `transportation`. */ mapName?: string; /** Tên map chứa ranh giới / tên khu vực. Bỏ trống → `basemap`. */ basemapMapName?: string; /** Đuôi file tile. Tegola: `pbf` (mặc định). GoMaps mapsrv: `vector.pbf`. */ tileExtension?: string; /** API key khi nguồn mapsrv yêu cầu `?apiKey=`. Tegola không cần. */ apiKey?: string; /** Header đính vào request tile (nếu nguồn cần auth). */ headers?: Record; /** * Preset màu. `'gomaps'` (mặc định) giữ màu gốc; `'google'` đổi màu theo nhóm. * Nên trùng với lớp `placeLabels`. */ stylePreset?: 'gomaps' | 'google'; } /** Union khai báo layer. */ type LayerDescriptor = Tileset3dLayerDescriptor | ModelLayerDescriptor | GeoJsonLayerDescriptor | RasterLayerDescriptor | AssetLayerDescriptor | CatalogLayerDescriptor | TilemapModelLayerDescriptor | PlaceLabelsLayerDescriptor | RoadsLayerDescriptor; /** Loại layer. */ type LayerType = LayerDescriptor['type']; /** * Trạng thái tải của layer. * Quy ước (audit P2.3): `layers.add` REJECT → layer KHÔNG vào `list()`/`get()` * (không có "xác" `error` từ add-fail); `'error'` chỉ dành cho lỗi runtime * sau khi layer đã `ready` (kèm event `layerError`). */ type LayerStatus = 'loading' | 'ready' | 'error' | 'removed'; /** * Handle điều khiển một layer đã thêm vào map. * Quy ước sau `remove()` (audit P2.2): getters (`id/type/name/status/visible`) * LUÔN đọc được (`status = 'removed'`); `remove()` idempotent như * `map.destroy()`; các mutation khác (`setVisible/setZoomRange/flyTo`) ném * `MDS_DESTROYED`. */ interface LayerHandle { /** Id layer (do người dùng đặt hoặc SDK sinh). */ readonly id: string; readonly type: LayerType; readonly name: string | undefined; /** Trạng thái hiện tại. */ readonly status: LayerStatus; /** Bật/tắt hiển thị. */ setVisible(visible: boolean): void; readonly visible: boolean; /** Đặt khoảng zoom hiển thị (undefined = bỏ giới hạn phía đó). */ setZoomRange(minZoom?: number, maxZoom?: number): void; /** Bay camera tới phạm vi của layer (khi đã ready). */ flyTo(): Promise; /** Gỡ layer khỏi map. Idempotent. */ remove(): void; } /** API quản lý layer trên một instance map. */ interface LayersApi { /** * Thêm layer. Promise resolve khi layer sẵn sàng hiển thị * (reject `MDS_LAYER_LOAD_FAILED` / `MDS_LAYER_INVALID`; reject * `MDS_DESTROYED` nếu map bị huỷ trong lúc chờ — v2, B2). */ add(descriptor: LayerDescriptor): Promise; /** Lấy handle theo id. */ get(id: string): LayerHandle | undefined; /** Danh sách layer hiện có (theo thứ tự thêm). */ list(): LayerHandle[]; /** Gỡ layer theo id. No-op nếu không tồn tại. */ remove(id: string): void; /** * Đổi vị trí/hướng/tỉ lệ của layer `type: 'model'` mà KHÔNG tải lại model. * * Dành cho kéo slider xem trước: mỗi nhịp chỉ là một phép nhân ma trận. Trả * `false` khi layer không còn (người dùng vừa gỡ) — bên gọi không phải bọc * try/catch quanh mỗi khung hình. Ném `MDS_LAYER_INVALID` nếu placement sai. */ setModelPlacement(layerId: string, placement: ModelPlacement): boolean; } /** * Cấu hình xác thực với API MDS. * * Đúng MỘT mode: khai `options.auth` **hoặc** lối tắt `options.apiKey`, không * cả hai. Không có precedence ẩn — khai trùng thì ném `MDS_INVALID_OPTIONS`. * * - `token`: host app cấp short-lived access token (khuyến nghị cho production). * Provider được gọi tại thời điểm request — SDK không cache token. * - `apiKey` / `apiKeyHeader`: publishable/browser key do MDS cấp. * * `auth` bỏ trống (và không có `options.apiKey`) = môi trường dev cục bộ không xác thực. */ type AuthOptions = { type: 'token'; /** Trả về access token hợp lệ tại thời điểm gọi. */ getAccessToken: () => string | Promise; } | { type: 'apiKey'; /** * Publishable key. * - `map.assets` (MDS processing): gửi `Authorization: Bearer`. * - `map.catalog` (3DCityDB): gửi `X-API-Key` (đúng tài liệu Digital Twin). */ apiKey: string; } | { type: 'apiKeyHeader'; /** * API Key V3 `dtk_...`. * - `map.catalog` (3DCityDB): gửi `X-API-Key`. * - `map.assets` (MDS processing): gửi `Authorization: Bearer`. */ apiKey: string; }; /** * Bản đồ nền dựng sẵn của MDS. * - `satellite`: ảnh vệ tinh thuần, không chữ (không cần key). **Mặc định** — * nhãn tiếng Việt đến từ lớp `placeLabels` (Tegola), không từ Google. * - `streets`: nền giao thông GoMaps — CẦN `gomapsKey`. * - `hybrid`: ảnh vệ tinh + nhãn Google (`lyrs=y`). Nhãn Google có tên nước * ngoài ở Hoàng Sa / Trường Sa — **không dùng cho bản giao khách**. Giữ lại * chỉ để đối chiếu nội bộ; đừng đổi sang `hybrid` để lấy nhãn. */ type BasemapId = 'streets' | 'satellite' | 'hybrid'; /** * Tự nạp lớp dựng sẵn khi init: * - `terrain`: địa hình 3D, * - `models3d`: lớp mô hình công trình 3D công khai (`terrain_3d_model_gis`), * - `placeLabels`: nhãn địa danh tiếng Việt từ vector tile Tegola, * - `roads`: lớp đường VNPT (chỉ hiện trên nền `satellite`). * Mặc định: `terrain` / `placeLabels` / `roads` bật, `models3d` tắt. * `true` bật cả bốn; `false` tắt hết. */ type DefaultLayersOption = boolean | { terrain?: boolean; models3d?: boolean; placeLabels?: boolean; roads?: boolean; }; /** Vị trí neo widget UI. */ type WidgetPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'; /** Options khởi tạo map — mọi field optional trừ khi ghi chú khác. */ interface MapOptions { /** Cấu hình xác thực (bắt buộc khi dùng tính năng assets ở production). */ auth?: AuthOptions; /** * Lối tắt của `auth: { type: 'apiKeyHeader', apiKey }`. * Không được khai cùng `auth` — khai cả hai thì ném `MDS_INVALID_OPTIONS`. */ apiKey?: string; /** * Endpoint API MDS (phần quản trị nội dung 3D). * Bỏ trống → dùng origin của trang hiện tại (triển khai same-origin qua * reverse proxy). Ngoài môi trường trình duyệt hoặc khi API ở origin khác * thì BẮT BUỘC truyền — thiếu sẽ ném `MDS_INVALID_OPTIONS` khi dùng assets. */ baseUrl?: string; /** * Mã lớp 3DCityDB mặc định cho `map.catalog` — tên "Hệ thống" dữ liệu * (ví dụ `8uY3LTiDRy`). Đi cặp với `apiKey`/`auth`: `apiKey` xác thực, còn * `catalogLayerCode` chọn Hệ thống. Bỏ trống thì mỗi lời gọi catalog phải tự * truyền `layerCode`. */ catalogLayerCode?: string; /** * URL gốc chứa static assets của engine 3D (worker, bảng địa hình, decoder wasm). * * * Bỏ trống = SDK TỰ DÒ `dist/engine-assets/` từ vị trí bundle đang chạy * (KHÔNG có CDN mặc định). Tự dò đúng khi trình duyệt nạp thẳng file trong * `dist/` của gói; SAI khi bundler của app đóng gói lại SDK (Vite dev * pre-bundle, `vite build`, Angular) vì file JS bị dời còn `engine-assets/` * không đi theo. Khi đó phải copy assets ra thư mục tĩnh rồi trỏ tay — xem * README §Assets (3 cách: field này, `window.MDS_MAP3D_ASSETS_BASE_URL`, * hoặc cấu hình copy của bundler). * * LƯU Ý (audit P2.6): giá trị này là per-PAGE — map ĐẦU TIÊN trong trang * quyết định; map sau init với giá trị khác sẽ ném `MDS_INVALID_OPTIONS`. */ assetsBaseUrl?: string; /** * Bản đồ nền. Mặc định `'satellite'` (ảnh thuần, không chữ) — nhãn tiếng Việt * đến từ lớp `placeLabels`, đừng đổi sang `'hybrid'` để lấy nhãn Google. */ basemap?: BasemapId; /** * API key GoMaps cho nền `'streets'` (nền giao thông). * BẮT BUỘC khi `basemap: 'streets'` hoặc khi gọi `map.setBasemap('streets')`; * thiếu sẽ ném `MDS_INVALID_OPTIONS`. Nền `'satellite'` / `'hybrid'` không cần key. */ gomapsKey?: string; /** * Domain GoMaps phát tile. Bỏ trống = `https://gomaps.vnpt.vn`. * Tile được dựng từ `{url}/tiles/mapvnpt/v1/{z}/{x}/{y}.png?apiKey={gomapsKey}`. */ gomapsUrl?: string; /** * Bật địa hình 3D. Mặc định `true`. * Truyền `false` để giữ quả cầu phẳng. */ terrain?: boolean; /** * URL nguồn địa hình tự host. * Bỏ trống = nguồn địa hình MDS (`https://bansaoso.vnptit.vn/storage/tiles/terrain/`). */ terrainUrl?: string; /** * Tự nạp lớp dựng sẵn khi init. Mặc định bật địa hình, nhãn địa danh và lớp * đường (trên nền satellite); **tắt** lớp mô hình 3D nhà cửa (`models3d`). * Bật lại: `true` (cả bốn) hoặc `{ models3d: true }`. `false` tắt hết. */ defaultLayers?: DefaultLayersOption; /** Tâm nhìn ban đầu `[lng, lat]`. Mặc định: Việt Nam. */ center?: LngLat; /** Mức zoom ban đầu (0–22). */ zoom?: number; /** Hướng ban đầu (độ). Mặc định 0. */ heading?: number; /** Góc nghiêng ban đầu (độ). Mặc định -35 (nhìn chéo). */ pitch?: number; /** Zoom tối thiểu/tối đa cho tương tác. */ minZoom?: number; maxZoom?: number; /** Dòng attribution bổ sung hiển thị góc bản đồ. */ attribution?: string; } /** Tuỳ chọn chung khi gắn widget. */ interface WidgetOptions { position?: WidgetPosition; } /** Handle của một widget đã gắn. */ interface WidgetHandle { /** Gỡ widget khỏi map. Idempotent. */ remove(): void; /** Đổi góc neo của widget (v2 — D8). */ setPosition(position: WidgetPosition): void; /** Ẩn widget (giữ trạng thái bên trong). */ hide(): void; /** Hiện lại widget đã ẩn. */ show(): void; } /** Tuỳ chọn UploadPanel. */ interface UploadPanelOptions extends WidgetOptions { /** Callback khi một asset được publish thành công từ panel. */ onPublished?: (result: { assetId: string; tilesetUrl: string; layerId: string; }) => void; /** * Callback khi luồng upload/publish trong panel gặp lỗi (v2 — D7). * Panel vẫn tự hiển thị lỗi trong UI; callback này để host app quan sát. */ onError?: (error: MDSMapError) => void; } /** Tuỳ chọn panel upload lên lớp 3DCityDB. */ interface CatalogUploadPanelOptions extends WidgetOptions { layerCode?: string; onUploaded?: (result: { objectId: string; layerCode: string; tilesetUrl: string; }) => void; onError?: (error: MDSMapError) => void; } /** Tuỳ chọn CatalogFeaturePanel. */ interface CatalogFeaturePanelOptions extends WidgetOptions { layerCode?: string; onSaved?: (result: { objectId: string; layerCode: string; }) => void; onDeleted?: (result: { objectId: string; layerCode: string; }) => void; onError?: (error: MDSMapError) => void; } /** Tuỳ chọn panel danh sách công trình 3DCityDB. */ interface CatalogListPanelOptions extends WidgetOptions { layerCode?: string; onSelect?: (feature: CatalogFeature) => void; onError?: (error: MDSMapError) => void; } /** Tuỳ chọn FeaturePanel. */ interface FeaturePanelOptions extends WidgetOptions { /** Callback khi thuộc tính của một công trình được lưu thành công từ panel. */ onSaved?: (result: { assetId: string; buildingId: string; }) => void; /** * Callback khi luồng đọc/ghi thuộc tính trong panel gặp lỗi (v2 — D7). * Panel vẫn tự hiển thị lỗi trong UI; callback này để host app quan sát. */ onError?: (error: MDSMapError) => void; } /** Tuỳ chọn panel đo. */ type MeasurePanelOptions = WidgetOptions; /** * Một kết quả tìm địa danh. * * Nguồn một bước (local / geocode đã có toạ độ) điền `center`. * Nguồn hai bước (GoMaps autocomplete) có thể bỏ `center` — panel gọi * `SearchPanelOptions.resolve` khi người dùng chọn dòng. */ interface SearchHit { /** Nhãn hiển thị (bắt buộc). */ label: string; /** * Toạ độ bay tới. Tuỳ chọn: nguồn autocomplete thường chưa có; * khi thiếu, panel gọi `resolve` trước khi `flyTo`. */ center?: LngLat; /** Dòng phụ (địa chỉ, loại đối tượng…). */ description?: string; /** Id ổn định nếu nguồn có — dùng làm key danh sách / bước detail. */ id?: string; } /** Tuỳ chọn ô tìm kiếm địa danh. */ interface SearchPanelOptions extends WidgetOptions { /** * Nguồn tìm kiếm do app cấp (hoặc `createGoMapsSearch().search`). * SDK không gọi Cesium ion/Bing. Thiếu hàm này thì panel hiện dòng nhắc, không vỡ. */ search?: (query: string) => Promise; /** * Bước 2 cho nguồn hai bước (vd. GoMaps): khi dòng được chọn thiếu `center`, * panel gọi `resolve(hit)` một lần rồi bay tới. Nguồn đã có `center` thì * không bao giờ gọi. Trả `null` → panel báo "Không lấy được vị trí.". */ resolve?: (hit: SearchHit) => Promise; /** Placeholder ô nhập. */ placeholder?: string; } /** API widget UI dựng sẵn. */ interface UiApi { /** Gắn panel upload GLB (kéo-thả, metadata, chọn vị trí, publish). */ addUploadPanel(options?: UploadPanelOptions): WidgetHandle; /** Gắn panel danh sách layer (bật/tắt, zoom tới). */ addLayerPanel(options?: WidgetOptions): WidgetHandle; /** * Gắn panel thuộc tính công trình: click lên mô hình → xem 10 trường → sửa * → lưu. Chỉ sửa được khi feature có cả `assetId` lẫn `buildingId`. */ addFeaturePanel(options?: FeaturePanelOptions): WidgetHandle; /** Gắn panel upload GLB lên lớp Digital Twin (file + vị trí trên bản đồ 3D). */ addCatalogUploadPanel(options?: CatalogUploadPanelOptions): WidgetHandle; /** Gắn panel sửa vị trí đối tượng Digital Twin trên bản đồ. */ addCatalogFeaturePanel(options?: CatalogFeaturePanelOptions): WidgetHandle; /** Gắn panel liệt kê công trình trên lớp 3DCityDB, chọn để bay tới. */ addCatalogListPanel(options?: CatalogListPanelOptions): WidgetHandle; /** Gắn thanh công cụ đo (điểm / chiều dài / diện tích / chênh cao / cao công trình / góc / bán kính / thể tích). */ addMeasurePanel(options?: MeasurePanelOptions): WidgetHandle; /** * Gắn ô tìm kiếm địa danh. Nguồn qua `options.search` (+ `resolve` nếu * hai bước), hoặc `createGoMapsSearch`. Không gọi geocoder Cesium ion/Bing. */ addSearchPanel(options?: SearchPanelOptions): WidgetHandle; /** * Gắn nút hướng dẫn di chuyển bản đồ (nút `?`): bấm mở bảng hướng dẫn * pan / zoom / xoay / nghiêng — thay cho `navigationHelpButton` của Cesium. */ addHelpPanel(options?: WidgetOptions): WidgetHandle; } /** Instance bản đồ 3D MDS. Tạo bằng `createMap()`. */ interface MDSMap { /** Container DOM đang chứa map. */ readonly container: HTMLElement; /** `true` sau khi `destroy()`. */ readonly destroyed: boolean; readonly camera: CameraApi; readonly layers: LayersApi; readonly assets: AssetsApi; readonly catalog: CatalogApi; readonly measure: MeasureApi; readonly ui: UiApi; /** Đăng ký sự kiện. Trả về hàm huỷ đăng ký. */ on(type: T, handler: MapEventHandler): Unsubscribe; /** Đăng ký sự kiện một lần. */ once(type: T, handler: MapEventHandler): Unsubscribe; /** Huỷ đăng ký sự kiện. */ off(type: T, handler: MapEventHandler): void; /** Đổi bản đồ nền. */ setBasemap(basemap: BasemapId): void; /** Bật/tắt địa hình 3D. */ setTerrain(enabled: boolean): Promise; /** Báo container đổi kích thước (SDK cũng tự theo dõi resize). */ resize(): void; /** Chụp khung hình hiện tại thành data URL PNG. */ screenshot(): Promise; /** Vị trí camera hiện tại (tiện — tương đương `camera.getPosition()`). */ getCameraPosition(): CameraPosition; /** * Huỷ map: gỡ mọi layer/widget/listener, giải phóng WebGL context. * Idempotent — gọi nhiều lần an toàn. */ destroy(): void; } export { type FeaturePanelOptions as $, type AssetBuildingRef as A, BUILDING_ATTRIBUTE_FIELDS as B, CATALOG_TERMINAL_JOB_STATUSES as C, type CatalogFeature as D, type CatalogFeatureListParams as E, type CatalogFeatureListResult as F, type GeoJsonObject as G, type CatalogFeaturePanelOptions as H, type CatalogFieldConstraints as I, type CatalogFieldDataType as J, type CatalogFieldPrimitive as K, type CatalogFieldValue as L, type MapOptions as M, type CatalogFieldViewType as N, type CatalogJobStatus as O, type CatalogLayerDescriptor as P, type CatalogLayerInfo as Q, type CatalogListPanelOptions as R, type SearchHit as S, type CatalogPlacement as T, type CatalogPlacementPatch as U, type CatalogUpdateFieldsOptions as V, type CatalogUploadOptions as W, type CatalogUploadPanelOptions as X, type CatalogUploadResult as Y, type DefaultLayersOption as Z, type FeatureClickEvent as _, type MDSMap as a, GLB_FILE_EXTENSION as a0, type GeoJsonFeature as a1, type GeoJsonFeatureCollection as a2, type GeoJsonGeometry as a3, type GeoJsonLayerDescriptor as a4, type GeoJsonLineString as a5, type GeoJsonMultiLineString as a6, type GeoJsonMultiPoint as a7, type GeoJsonMultiPolygon as a8, type GeoJsonPoint as a9, type MeasurePoint as aA, type MeasureResult as aB, type MeasureSession as aC, type ModelLayerDescriptor as aD, type ModelPlacement as aE, type PickedFeature as aF, type PlaceLabelsLayerDescriptor as aG, type PlacementInput as aH, type PlacementOffsetEnu as aI, type PublishResult as aJ, type RasterLayerDescriptor as aK, type RoadsLayerDescriptor as aL, type TilemapModelLayerDescriptor as aM, type Tileset3dLayerDescriptor as aN, type UiApi as aO, type Unsubscribe as aP, type UploadOptions as aQ, type UploadPanelOptions as aR, type WidgetHandle as aS, type WidgetOptions as aT, type WidgetPosition as aU, isMDSMapError as aV, type GeoJsonPolygon as aa, type GeoJsonPosition as ab, type GeoJsonStyle as ac, type LayerCommonOptions as ad, type LayerDescriptor as ae, type LayerErrorEvent as af, type LayerEvent as ag, type LayerHandle as ah, type LayerStatus as ai, type LayerType as aj, type LayersApi as ak, type LngLat as al, type LngLatBounds as am, MAX_UPLOAD_BYTES as an, type MDSErrorCode as ao, MDSMapError as ap, MDS_ERROR_CODES as aq, type MapClickEvent as ar, type MapEventHandler as as, type MapEventMap as at, type MapEventType as au, type MeasureApi as av, type MeasureHeightSource as aw, type MeasureLockedFeature as ax, type MeasureMode as ay, type MeasurePanelOptions as az, type SearchPanelOptions as b, type AssetEventMap as c, type AssetHandle as d, type AssetInfo as e, type AssetLayerDescriptor as f, type AssetListParams as g, type AssetListResult as h, type AssetProgress as i, type AssetStatus as j, type AssetsApi as k, type AuthOptions as l, type BasemapId as m, type BuildingAttributeKey as n, type BuildingAttributeValue as o, type CameraApi as p, type CameraFlyOptions as q, type CameraPosition as r, type CameraTarget as s, type CatalogApi as t, type CatalogBoundingBox as u, type CatalogCreateLayerOptions as v, type CatalogCreateLayerResult as w, type CatalogCustomField as x, type CatalogDeleteOptions as y, type CatalogDeleteResult as z };