|
1 | 1 | # MapMLify AI Coding Instructions |
2 | 2 |
|
3 | 3 | ## Project Overview |
4 | | -MapMLify is a client-side web application that converts OGC WMS (Web Map Service) capabilities documents into functional MapML map viewers. It uses the `@maps4html/mapml` web components to create interactive map experiences directly in the browser. |
| 4 | +MapMLify is a client-side web application that converts geospatial service capabilities documents into functional MapML map viewers. The objective of creating the map viewers is to copy the code for use in external web pages. It uses the `@maps4html/mapml` web components to create interactive map experiences directly in the browser, suitable for copying. |
| 5 | + |
| 6 | +**Supported Services:** |
| 7 | +- **OGC WMS** (Web Map Service) - versions 1.1.1 and 1.3.0 |
| 8 | +- **OGC WMTS** (Web Map Tile Service) - version 1.0.0 |
| 9 | +- **ESRI REST API MapServer** - both tiled and dynamic (export) modes |
| 10 | +- **ESRI REST API ImageServer** - raster imagery services |
| 11 | + |
| 12 | +**Not Yet Supported:** |
| 13 | +- ESRI FeatureServer (vector features) |
| 14 | +- OGC WFS (Web Feature Service) |
| 15 | +- OGC API (Application Programming Interface) services |
5 | 16 |
|
6 | 17 | **⚠️ Before coding: Read your available skills/tools to understand what capabilities you have for file editing, searching, running commands, etc.** |
7 | 18 |
|
8 | 19 | ## Architecture & Key Concepts |
9 | 20 |
|
10 | 21 | ### Core Data Flow |
11 | | -1. **Fetch WMS Capabilities** ([main.js](../src/script/main.js#L83-L106)): Attempts direct fetch first, falls back to CORS proxy (`https://corsproxy.io/?`) |
12 | | -2. **Parse XML Capabilities** ([main.js](../src/script/main.js#L112-L269)): Extracts service info, layers, styles, CRS/SRS, bounding boxes, GetFeatureInfo formats |
13 | | -3. **Generate MapML** ([main.js](../src/script/main.js#L620-L770)): Dynamically creates `<mapml-viewer>`, `<map-layer>`, `<map-extent>`, `<map-input>`, `<map-link>` elements |
14 | | -4. **Render Interactive Maps**: MapML web components handle rendering, interaction, and GetFeatureInfo queries |
| 22 | +1. **Fetch Capabilities** ([main.js](../src/script/main.js#L83-L106)): Attempts direct fetch first, then prompts user to save local file if CORS issues arise, presents button to read that file from disk (only if CORS issue detected). |
| 23 | +2. **Detect Service Type** ([main.js](../src/script/main.js#L234-L270)): Identifies WMS (XML with WMS namespace), WMTS (XML with WMTS namespace), or ESRI (JSON with MapServer/ImageServer indicators) |
| 24 | +3. **Parse Capabilities** ([main.js](../src/script/main.js#L112-L269)): Extracts service info, layers, styles, CRS/SRS, bounding boxes, query formats (GetFeatureInfo for WMS/WMTS, identify for ESRI) |
| 25 | +4. **Generate MapML** (service-specific functions): Dynamically creates `<mapml-viewer>`, `<map-layer>`, `<map-extent>`, `<map-input>`, `<map-link>` elements |
| 26 | +5. **Render Interactive Maps**: MapML web components handle rendering, interaction, and query operations |
| 27 | + |
| 28 | +### Service Type Detection |
| 29 | +Service type is detected by examining the response: |
| 30 | +- **WMS**: XML root element `Capabilities` with WMS namespace (`http://www.opengis.net/wms`) |
| 31 | +- **WMTS**: XML root element `Capabilities` with WMTS namespace (`http://www.opengis.net/wmts/1.0`) |
| 32 | +- **ESRI MapServer**: JSON with `layers` array and `tileInfo` (tiled) or `supportedImageFormatTypes` (export) |
| 33 | +- **ESRI ImageServer**: JSON with `pixelType` or `serviceDataType` containing `esriImageService` |
15 | 34 |
|
16 | 35 | ### WMS Version Handling |
17 | 36 | The app supports WMS 1.1.1 and 1.3.0, with critical differences: |
18 | 37 | - **Parameter names**: 1.3.0 uses `CRS`/`I`/`J`, 1.1.1 uses `SRS`/`X`/`Y` |
19 | | -- **BBOX ordering**: WMS 1.3.0 with EPSG:4326 requires lat,lon order (ymin,xmin,ymax,xmax); all other CRS use standard xmin,ymin,xmax,ymax ([main.js](../src/script/main.js#L540-L548)) |
| 38 | +- **BBOX ordering**: WMS 1.3.0 with EPSG:4326 requires lat,lon order (ymin,xmin,ymax,ymax); all other CRS use standard xmin,ymin,xmax,ymax ([main.js](../src/script/main.js#L540-L548)) |
20 | 39 | - Check version with `version.startsWith('1.3')` pattern throughout codebase |
21 | 40 |
|
| 41 | +### WMTS Tile Matrix Sets |
| 42 | +WMTS services define TileMatrixSet elements that specify zoom levels, tile sizes, and CRS: |
| 43 | +- Extract TileMatrixSet identifier and associated TileMatrix elements ([main.js](../src/script/main.js#L393-L450)) |
| 44 | +- Map TileMatrixSet CRS to MapML projections using `mapTileMatrixSetToProjection()` ([main.js](../src/script/main.js#L376-L392)) |
| 45 | +- EPSG:4326 requires validation: must have 2×1 tiles at zoom 0 to qualify as WGS84 projection |
| 46 | +- ResourceURL templates provide tile and FeatureInfo URL patterns with `{TileMatrix}`, `{TileRow}`, `{TileCol}` variables ([main.js](../src/script/main.js#L564-L574)) |
| 47 | + |
| 48 | +### ESRI Service Modes |
| 49 | +ESRI MapServer can operate in two modes: |
| 50 | +- **Tiled Mode** (`ESRI-MapServer-Tile`): Pre-generated tiles, indicated by presence of `tileInfo` in JSON |
| 51 | +- **Export Mode** (`ESRI-MapServer`): Dynamic map generation, uses `export` endpoint with bbox parameters |
| 52 | +- **ImageServer**: Always dynamic, uses `exportImage` endpoint |
| 53 | + |
| 54 | +Detection logic in `detectESRIServiceType()` ([main.js](../src/script/main.js#L256-L270)) |
| 55 | + |
22 | 56 | ### Projection System |
23 | 57 | Four projections are supported, mapped from WMS CRS to MapML units: |
24 | 58 | - `EPSG:3857` → `OSMTILE` (Web Mercator) - default |
@@ -60,10 +94,13 @@ npm run format # Format all JS files |
60 | 94 | npm run format:check # Check formatting without changes |
61 | 95 | ``` |
62 | 96 |
|
63 | | -### Testing WMS Services |
| 97 | +### Testing Services |
64 | 98 | - Preset URLs are loaded from [capabilities.txt](../src/capabilities.txt) with format: `Label,URL` or just `URL` |
65 | 99 | - Test both direct fetch and CORS proxy scenarios |
66 | | -- Verify behavior across WMS versions (1.1.1 vs 1.3.0) |
| 100 | +- **WMS**: Verify behavior across versions (1.1.1 vs 1.3.0) |
| 101 | +- **WMTS**: Test services with multiple TileMatrixSets and dimensions |
| 102 | +- **ESRI**: Test both tiled and export modes for MapServer; verify ImageServer rendering |
| 103 | +- Sample files: `nasa-imagery-wmts.xml` (WMTS), `ducks-MapServer.json` (ESRI MapServer) |
67 | 104 |
|
68 | 105 | ## Project-Specific Conventions |
69 | 106 |
|
@@ -91,27 +128,59 @@ Never attempt partial DOM updates to existing viewers - always rebuild. |
91 | 128 | ## Critical Implementation Details |
92 | 129 |
|
93 | 130 | ### Template URL Construction |
94 | | -Build WMS URLs manually as strings to preserve MapML template variables like `{xmin}`, `{w}`, etc.: |
| 131 | + |
| 132 | +**WMS URLs** - Build manually as strings to preserve MapML template variables: |
95 | 133 | ```javascript |
96 | 134 | let tref = `${currentWmsBaseUrl}?SERVICE=WMS&VERSION=${version}&REQUEST=GetMap&LAYERS=${encodeURIComponent(layer.name)}&WIDTH={w}&HEIGHT={h}...`; |
97 | 135 | // DON'T use URLSearchParams - it will encode the curly braces |
98 | 136 | ``` |
99 | 137 |
|
| 138 | +**WMTS URLs** - Use ResourceURL templates from capabilities, replace template variables: |
| 139 | +```javascript |
| 140 | +function buildWMTSTileUrl(template, layer, tileMatrixSet, style, format, zoom, row, col) { |
| 141 | + let url = template; |
| 142 | + url = url.replace(/{TileMatrixSet}/g, tileMatrixSet); |
| 143 | + url = url.replace(/{TileMatrix}/g, zoom); |
| 144 | + url = url.replace(/{TileRow}/g, row); |
| 145 | + url = url.replace(/{TileCol}/g, col); |
| 146 | + // ... replace {Style}, {Layer}, dimension parameters |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +**ESRI URLs** - Construct based on service type and mode: |
| 151 | +- **MapServer Tile**: `${baseUrl}/tile/{z}/{y}/{x}` |
| 152 | +- **MapServer Export**: `${baseUrl}/export?bbox={xmin},{ymin},{xmax},{ymax}&size={w},{h}&format=...` |
| 153 | +- **ImageServer**: `${baseUrl}/exportImage?bbox={xmin},{ymin},{xmax},{ymax}&size={w},{h}&format=...` |
| 154 | + |
100 | 155 | ### Basemap Layer Configuration |
101 | 156 | Each projection has specific basemap configuration with zoom inputs, tile matrix inputs, and tile URLs ([main.js](../src/script/main.js#L640-L764)). OSMTILE uses dual tile links for geometry and labels. WGS84 has no basemap currently. |
102 | 157 |
|
103 | | -### GetFeatureInfo Coordinate Parameters |
104 | | -Map click coordinates use different parameter names: |
| 158 | +### Query/Feature Info Handling |
| 159 | + |
| 160 | +**WMS GetFeatureInfo** - Click coordinates use version-specific parameters: |
105 | 161 | - WMS 1.3.0: `&I={i}&J={j}` |
106 | 162 | - WMS 1.1.1: `&X={i}&Y={j}` |
107 | 163 |
|
| 164 | +**WMTS GetFeatureInfo** - Uses ResourceURL templates with `{TileRow}`, `{TileCol}`, `{I}`, `{J}` parameters |
| 165 | +- Extract from `<ResourceURL resourceType="FeatureInfo">` elements |
| 166 | +- Info formats specified in capabilities as MIME types |
| 167 | + |
| 168 | +**ESRI Identify** - Uses `identify` endpoint: |
| 169 | +- **MapServer**: `${baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&...` |
| 170 | +- **ImageServer**: `${baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&...` |
| 171 | +- Returns results in JSON format, supports various `returnGeometry` options |
| 172 | + |
108 | 173 | ## Common Pitfalls |
109 | 174 |
|
110 | 175 | 1. **Don't modify existing viewer DOM**: Always remove and recreate viewers when changing configuration |
111 | 176 | 2. **BBOX ordering matters**: WMS 1.3.0 + EPSG:4326 is the ONLY case requiring lat,lon order |
112 | 177 | 3. **Encode layer names**: Use `encodeURIComponent(layer.name)` in URL construction |
113 | | -4. **Root CRS inheritance**: Layers inherit CRS from root `<Capability><Layer>` ([main.js](../src/script/main.js#L148-L153)) |
| 178 | +4. **Root CRS inheritance** (WMS): Layers inherit CRS from root `<Capability><Layer>` ([main.js](../src/script/main.js#L148-L153)) |
114 | 179 | 5. **Map-input attributes**: Location inputs should NOT have min/max attributes ([main.js](../src/script/main.js#L863-L870)) |
| 180 | +6. **WMTS dimension defaults**: When building preview URLs, replace dimension template variables with default values from capabilities |
| 181 | +7. **ESRI coordinate systems**: ESRI services use WKID (e.g., 3857) instead of EPSG codes; extract from `spatialReference.wkid` or `latestWkid` |
| 182 | +8. **TileMatrixSet validation**: Not all EPSG:4326 TileMatrixSets are WGS84-compatible; verify 2×1 tile structure at zoom 0 |
| 183 | +9. **Service type before parsing**: Always detect service type before attempting to parse; JSON vs XML parsers are not interchangeable |
115 | 184 |
|
116 | 185 | ## File Organization |
117 | 186 | - [src/index.html](../src/index.html): Entry point with MapML polyfill import |
|
0 commit comments