|
| 1 | +# MapMLify AI Coding Instructions |
| 2 | + |
| 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. |
| 5 | + |
| 6 | +**⚠️ Before coding: Read your available skills/tools to understand what capabilities you have for file editing, searching, running commands, etc.** |
| 7 | + |
| 8 | +## Architecture & Key Concepts |
| 9 | + |
| 10 | +### 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 |
| 15 | + |
| 16 | +### WMS Version Handling |
| 17 | +The app supports WMS 1.1.1 and 1.3.0, with critical differences: |
| 18 | +- **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)) |
| 20 | +- Check version with `version.startsWith('1.3')` pattern throughout codebase |
| 21 | + |
| 22 | +### Projection System |
| 23 | +Four projections are supported, mapped from WMS CRS to MapML units: |
| 24 | +- `EPSG:3857` → `OSMTILE` (Web Mercator) - default |
| 25 | +- `EPSG:3978` → `CBMTILE` (Canada Lambert Conformal Conic) |
| 26 | +- `EPSG:4326` / `CRS:84` → `WGS84` (Geographic) |
| 27 | +- `EPSG:5936` → `APSTILE` (Arctic Polar Stereographic) |
| 28 | + |
| 29 | +Coordinate transformation uses `wgs84ToWebMercator()` for OSMTILE ([main.js](../src/script/main.js#L6-L11)). |
| 30 | + |
| 31 | +### MapML Structure Pattern |
| 32 | +Every layer creates this DOM structure: |
| 33 | +```html |
| 34 | +<mapml-viewer projection="OSMTILE" controls> |
| 35 | + <map-layer label="Layer Title" checked> |
| 36 | + <map-link rel="license" href="..." /> |
| 37 | + <map-link rel="legend" href="..." /> |
| 38 | + <map-extent units="OSMTILE"> |
| 39 | + <map-input name="xmin" type="location" units="pcrs" axis="easting" position="top-left" /> |
| 40 | + <!-- ... more inputs for ymin, xmax, ymax, w, h, i, j ... --> |
| 41 | + <map-select name="style"><!-- if styles exist --></map-select> |
| 42 | + <map-link rel="image" tref="...{xmin},{ymin},{xmax},{ymax}..." /> |
| 43 | + <map-link rel="query" tref="..." data-query-link="true" /><!-- if queryable --> |
| 44 | + </map-extent> |
| 45 | + </map-layer> |
| 46 | +</mapml-viewer> |
| 47 | +``` |
| 48 | + |
| 49 | +## Development Workflows |
| 50 | + |
| 51 | +### Running the App |
| 52 | +```bash |
| 53 | +npm run serve # Starts http-server on port 8000 |
| 54 | +# Navigate to http://localhost:8000/src/index.html |
| 55 | +``` |
| 56 | + |
| 57 | +### Code Formatting |
| 58 | +```bash |
| 59 | +npm run format # Format all JS files |
| 60 | +npm run format:check # Check formatting without changes |
| 61 | +``` |
| 62 | + |
| 63 | +### Testing WMS Services |
| 64 | +- Preset URLs are loaded from [capabilities.txt](../src/capabilities.txt) with format: `Label,URL` or just `URL` |
| 65 | +- Test both direct fetch and CORS proxy scenarios |
| 66 | +- Verify behavior across WMS versions (1.1.1 vs 1.3.0) |
| 67 | + |
| 68 | +## Project-Specific Conventions |
| 69 | + |
| 70 | +### State Management |
| 71 | +- `currentWmsBaseUrl`: Stores base URL (without query params) for building GetMap/GetFeatureInfo requests |
| 72 | +- `currentUsedProxy`: Boolean flag indicating if CORS proxy was needed |
| 73 | +- Layer index (`data-layer-index`) links checkboxes to viewer containers |
| 74 | + |
| 75 | +### Dynamic UI Updates |
| 76 | +When users change dropdowns (style, format, projection), the app: |
| 77 | +1. Updates preview thumbnails immediately ([main.js](../src/script/main.js#L408-L414)) |
| 78 | +2. If viewer is active, calls `removeViewerForLayer()` then `createViewerForLayer()` to rebuild ([main.js](../src/script/main.js#L421-L432)) |
| 79 | + |
| 80 | +Never attempt partial DOM updates to existing viewers - always rebuild. |
| 81 | + |
| 82 | +### Query Support Pattern |
| 83 | +- GetFeatureInfo links use `data-query-link="true"` attribute for identification |
| 84 | +- Toggle queries by adding/removing `<map-link rel="query">` elements ([main.js](../src/script/main.js#L566-L610)) |
| 85 | +- Format selection affects `INFO_FORMAT` parameter in query template URL |
| 86 | + |
| 87 | +### License & Legend Links |
| 88 | +- License links extracted from WMS `<Attribution>` elements, with service-level fallback ([main.js](../src/script/main.js#L124-L135)) |
| 89 | +- Legend links added before `<map-extent>` per MapML spec; only first legend per style used ([main.js](../src/script/main.js#L960-L978)) |
| 90 | + |
| 91 | +## Critical Implementation Details |
| 92 | + |
| 93 | +### Template URL Construction |
| 94 | +Build WMS URLs manually as strings to preserve MapML template variables like `{xmin}`, `{w}`, etc.: |
| 95 | +```javascript |
| 96 | +let tref = `${currentWmsBaseUrl}?SERVICE=WMS&VERSION=${version}&REQUEST=GetMap&LAYERS=${encodeURIComponent(layer.name)}&WIDTH={w}&HEIGHT={h}...`; |
| 97 | +// DON'T use URLSearchParams - it will encode the curly braces |
| 98 | +``` |
| 99 | + |
| 100 | +### Basemap Layer Configuration |
| 101 | +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 | + |
| 103 | +### GetFeatureInfo Coordinate Parameters |
| 104 | +Map click coordinates use different parameter names: |
| 105 | +- WMS 1.3.0: `&I={i}&J={j}` |
| 106 | +- WMS 1.1.1: `&X={i}&Y={j}` |
| 107 | + |
| 108 | +## Common Pitfalls |
| 109 | + |
| 110 | +1. **Don't modify existing viewer DOM**: Always remove and recreate viewers when changing configuration |
| 111 | +2. **BBOX ordering matters**: WMS 1.3.0 + EPSG:4326 is the ONLY case requiring lat,lon order |
| 112 | +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)) |
| 114 | +5. **Map-input attributes**: Location inputs should NOT have min/max attributes ([main.js](../src/script/main.js#L863-L870)) |
| 115 | + |
| 116 | +## File Organization |
| 117 | +- [src/index.html](../src/index.html): Entry point with MapML polyfill import |
| 118 | +- [src/script/main.js](../src/script/main.js): All application logic (1027 lines) |
| 119 | +- [src/style/main.css](../src/style/main.css): Styling for UI controls and map viewers |
| 120 | +- [src/capabilities.txt](../src/capabilities.txt): Preset WMS URLs for testing |
0 commit comments