@aapicoits/powermap-web-sdk 1.0.1 → 1.1.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 CHANGED
@@ -695,22 +695,60 @@ const map = new PowerMap({
695
695
 
696
696
  ## 12. 🔍 Search & Geocoding
697
697
 
698
- The Web SDK provides built-in search capabilities using the PowerMap Search API.
698
+ The Web SDK provides built-in search capabilities using the PowerMap Search API with automatic script detection, smart field fallbacks, and cross-endpoint query handling.
699
699
 
700
700
  ### `search(query, options)`
701
701
 
702
702
  Available options:
703
703
 
704
- - `lang`: `'th'` (default) or `'en'`.
705
- - `location`: `[latitude, longitude]` to prioritize nearby results.
704
+ | Option | Type | Default | Description |
705
+ | :--- | :--- | :--- | :--- |
706
+ | `lang` | `string` | `'auto'` | Language mode: `'auto'`, `'th'`, or `'en'`. In `'auto'` mode, script type is detected automatically from Unicode ranges. |
707
+ | `location` | `[lat, lng]` | `-` | `[latitude, longitude]` coordinate pair to prioritize nearby search results. |
708
+
709
+ #### Automatic Script Detection & Fallbacks
710
+ - **`lang: 'auto'`**: Automatically inspects query characters. Thai queries (`[\u0E00-\u0E7F]`) select Thai search services, while English/Latin queries (`[a-zA-Z]`) select English search services.
711
+ - **Mixed Script Handling**: For mixed search terms (e.g. `"Central บางนา"` or `"BTS อโศก"`), if primary search yields no results or contains mixed scripts, the SDK automatically executes a cross-endpoint fallback search and merges unique results.
712
+ - **Smart Field Mapping**: `name` and `address` automatically default to the preferred query language with automatic fallback (`nameEn` -> `nameTh` -> `name` or `nameTh` -> `nameEn` -> `name`), ensuring titles and addresses are never returned as empty strings.
713
+
714
+ #### Returned `SearchResult` Properties
715
+
716
+ Each item in the returned array contains:
717
+
718
+ | Field | Type | Description |
719
+ | :--- | :--- | :--- |
720
+ | `id` / `gid` | `string` | Unique identifier for the POI. |
721
+ | `name` | `string` | Display name in the preferred language with automatic fallback. |
722
+ | `nameEn` | `string` | English name of the place (with Thai fallback). |
723
+ | `nameTh` | `string` | Thai name of the place (with English fallback). |
724
+ | `address` | `string` | Formatted address in the preferred language with fallback. |
725
+ | `addressEn` | `string` | Formatted English address string. |
726
+ | `addressTh` | `string` | Formatted Thai address string. |
727
+ | `position` | `[lat, lng]` | Coordinate pair `[latitude, longitude]` (compatible with Mobile SDK). |
728
+ | `positionLngLat` | `[lng, lat]` | Coordinate pair `[longitude, latitude]` for Web map view manipulation. |
729
+ | `province` / `amphoe` / `tambon` | `string` | Administrative boundary details. |
730
+ | `postCode` | `string` | Postal code if available. |
731
+ | `rawData` | `Object` | Raw Elasticsearch GeoJSON source payload. |
732
+
733
+ ### Search Examples
706
734
 
707
735
  ```javascript
708
- const results = await map.search("Central World", { lang: 'en' });
736
+ // 1. Auto language detection (Recommended)
737
+ const results = await map.search("Central World");
709
738
 
710
739
  results.forEach(item => {
711
- console.log(`${item.name}: ${item.address}`);
712
- console.log(`Position: ${item.position}`); // [lat, lng]
740
+ console.log(`${item.name} (${item.nameTh}): ${item.address}`);
741
+ console.log(`Position [lat, lng]:`, item.position);
713
742
  });
743
+
744
+ // 2. Explicit English search with location prioritization
745
+ const enResults = await map.search("Siam Paragon", {
746
+ lang: 'en',
747
+ location: [13.746, 100.534] // [lat, lng]
748
+ });
749
+
750
+ // 3. Mixed query (Thai + English)
751
+ const mixedResults = await map.search("BTS อโศก", { lang: 'auto' });
714
752
  ```
715
753
 
716
754
  ---
@@ -945,16 +983,42 @@ map.on('geometrySelectionChanged', ({ features }) => {
945
983
 
946
984
  ## 16. 🏠 Indoor Mapping
947
985
 
948
- The PowerMap SDK provides a robust API for managing indoor environments, including floor switching, category filtering, and specialized geometry handling.
986
+ The PowerMap SDK provides a robust API for managing indoor environments with **OGC IMDF 1.0.0 Full Compliance** — supporting all 16 standard feature types, ZIP archive import/export, and schema validation.
949
987
 
950
- ### 16.1 Enabling Indoor Mode
988
+ > [!TIP]
989
+ > For the complete IMDF reference including all feature types, properties, archive format, and validation — see [GEOMETRY.md](./GEOMETRY.md#ogc-imdf-100-compliance)
951
990
 
952
- Switch to indoor mode to enable building-specific logic and specialized drawing tools (e.g., Beacons, Walkways).
991
+ ### 16.1 Indoor Venue Selection (NEW)
992
+
993
+ The new `loadIndoorMap()` API lets you select and activate a venue from pre-loaded data. It handles mode switching, floor detection, and camera fitting automatically.
953
994
 
954
995
  ```javascript
955
- map.setMode('indoor');
996
+ // 1. Load data from your API
997
+ const data = await fetch('/api/venues/siam-paragon/features').then(r => r.json());
998
+ map.geometry.import(data);
999
+
1000
+ // 2. Select venue → auto enters indoor mode
1001
+ const result = map.loadIndoorMap('siam_paragon');
1002
+ console.log(result.floors); // [0, 1, 2, 3, 4]
1003
+ console.log(result.currentFloor); // 0
1004
+
1005
+ // 3. Switch floors
1006
+ map.setFloor(2); // Convenience alias for map.indoor.setFloor()
1007
+
1008
+ // 4. Query venue metadata
1009
+ map.indoor.getVenueInfo(); // { id, name, floors, bounds, buildingCount }
1010
+ map.indoor.getFloorInfo(2); // { name, unitCount, poiCount, beaconCount }
1011
+
1012
+ // 5. Exit
1013
+ map.unloadIndoorMap();
956
1014
  ```
957
1015
 
1016
+ | Method | Returns | Description |
1017
+ | :--- | :--- | :--- |
1018
+ | `loadIndoorMap(venueId, opts)` | `{ venue, floors, currentFloor }` | Select venue, enter indoor mode, fit bounds |
1019
+ | `setFloor(level, opts)` | `PowerMap` | Convenience alias for `map.indoor.setFloor()` |
1020
+ | `unloadIndoorMap()` | `PowerMap` | Exit indoor mode, clear selection |
1021
+
958
1022
  ### 16.2 Floor Management (`map.indoor`)
959
1023
 
960
1024
  When in indoor mode, use the `map.indoor` facade to control the vertical context of the map.
@@ -964,6 +1028,11 @@ When in indoor mode, use the `map.indoor` facade to control the vertical context
964
1028
  | `setFloor(ordinal, opts)` | `number, Object` | Switch to a specific floor level (e.g., 1, 2, -1). |
965
1029
  | `getAvailableFloors()` | - | Returns a sorted array of all unique floor ordinals found in the map data. |
966
1030
  | `getCurrentFloor()` | - | Returns the ordinal of the currently active floor. |
1031
+ | `getActiveVenue()` | - | Returns the currently selected venue feature or `null`. |
1032
+ | `getVenues()` | - | Lists all venue features in loaded data. |
1033
+ | `getVenueInfo()` | - | Summary of active venue (name, floors, bounds, building count). |
1034
+ | `getFloorInfo(ordinal)` | `number` | Floor details (unit count, POI count, beacon count). |
1035
+ | `getBuildings()` | - | Lists all building features in loaded data. |
967
1036
 
968
1037
  #### Switching Floors with Animation
969
1038
 
@@ -992,19 +1061,58 @@ map.indoor.setCategoryVisible('walkway', true); // Navigation Paths
992
1061
  map.indoor.setCategoryVisible('obstacle', true); // 3D Obstacles/Buildings
993
1062
  ```
994
1063
 
995
- ### 16.4 Indoor Data Kinds
1064
+ ### 16.4 Indoor Data Kinds (IMDF Compliant)
996
1065
 
997
- The SDK categorizes indoor features using the `user_kind` (or `kind`) property:
1066
+ The SDK categorizes indoor features using `user_kind` (or `kind`) mapped to OGC IMDF `feature_type`:
1067
+
1068
+ | SDK Kind | IMDF Feature Type | Geometry | Description |
1069
+ | :--- | :--- | :--- | :--- |
1070
+ | `venue` | venue | Polygon | Main venue (mall, airport) |
1071
+ | `building` | building | Polygon | Building within venue |
1072
+ | `floor` | level | Polygon | Floor plan surface |
1073
+ | `unit` | unit | Polygon | Room, corridor, area |
1074
+ | `opening` | opening | LineString | Door, gate, passage |
1075
+ | `amenity` | amenity | Point | ATM, restroom, etc. |
1076
+ | `anchor` | anchor | Point | Reference point |
1077
+ | `footprint` | footprint | Polygon | Building shadow |
1078
+ | `fixture` | fixture | Polygon | Furniture, permanent |
1079
+ | `section` | section | Polygon | Zone, terminal |
1080
+ | `geofence` | geofence | Polygon | Virtual fence |
1081
+ | `kiosk` | kiosk | Polygon | Service booth |
1082
+ | `detail` | detail | LineString | Crosswalk, railing |
1083
+ | `beacon` | anchor (beacon) | Point | BLE beacon device |
1084
+ | `poi` | anchor (poi) | Point | Point of interest |
1085
+ | `walkway` | pathway | LineString | Indoor navigation path |
1086
+ | `obstacle` | unit (restricted) | Polygon | Non-walkable area |
1087
+
1088
+ ### 16.5 IMDF Archive & Validation
1089
+
1090
+ ```javascript
1091
+ import { IMDFArchive, IMDFValidator } from '@powermap/web-sdk';
998
1092
 
999
- - **floor**: The walkable surface area of a floor (Polygon).
1000
- - **obstacle**: Non-walkable areas. Can be extruded into 3D.
1001
- - **walkway**: Navigable path lines for indoor routing.
1002
- - **poi**: Indoor points of interest with custom icons.
1003
- - **beacon**: Positioning hardware or logical points.
1093
+ // Export as IMDF ZIP archive
1094
+ const blob = await IMDFArchive.toArchive(map.geometry.export());
1004
1095
 
1005
- ### 16.5 Event Synchronization
1096
+ // Import IMDF ZIP archive
1097
+ const fc = await IMDFArchive.fromArchive(zipFile);
1098
+ map.geometry.import(fc);
1099
+
1100
+ // Validate IMDF data
1101
+ const result = IMDFValidator.validate(map.geometry.export());
1102
+ if (!result.valid) console.error(result.errors);
1103
+ ```
1104
+
1105
+ > [!NOTE]
1106
+ > IMDF Archive requires [JSZip](https://stuk.github.io/jszip/) as an optional dependency.
1107
+
1108
+ ### 16.6 Event Synchronization
1006
1109
 
1007
1110
  ```javascript
1111
+ // Listen for venue selection
1112
+ map.on('indoorMapLoaded', ({ venue, floors, currentFloor }) => {
1113
+ console.log(`Entered: ${venue.properties?.name?.en}`);
1114
+ });
1115
+
1008
1116
  // Listen for mode changes
1009
1117
  map.on('onModeChanged', ({ mode }) => {
1010
1118
  console.log(`Mode switched to: ${mode}`); // 'standard' or 'indoor'
@@ -1114,6 +1222,9 @@ The SDK emits the following events through its central `EventBus`. You can subsc
1114
1222
  | Event | Payload | Description |
1115
1223
  |---|---|---|
1116
1224
  | `floorChanged` | `ordinal (number)` | Fired when the active indoor floor changes. |
1225
+ | `venueChanged` | `VenueInfo` | Fired when the active venue selection changes. |
1226
+ | `indoorMapLoaded` | `{ venue, floors, currentFloor }` | Fired when a venue is successfully selected via `loadIndoorMap()`. |
1227
+ | `indoorMapUnloaded` | `-` | Fired when indoor mode is exited via `unloadIndoorMap()`. |
1117
1228
 
1118
1229
  ### 🗺️ Routing & Navigation
1119
1230
  | Event | Payload | Description |