Skip to content

Commit adfc8cc

Browse files
committed
Enable query by default, with prioritized default
format selection - Enable query checkbox by default for all queryable services (WMS, WMTS, ESRI MapServer, ESRI ImageServer) - Implement smart query format selection with priority: 1. text/mapml (highest priority) 2. application/json or application/geo+json 3. text/html 4. text/plain 5. first available format (fallback) - Change ESRI identify requests from f=html to f=json for broader compatibility across ArcGIS versions - Update all tests to reflect query-enabled-by-default behavior This improves user experience by making queryable layers immediately interactive without requiring manual checkbox activation, and ensures the best available format is selected automatically.
1 parent 00e5628 commit adfc8cc

File tree

8 files changed

+66
-39
lines changed

8 files changed

+66
-39
lines changed

.github/copilot-instructions.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,11 @@ Each projection has specific basemap configuration with zoom inputs, tile matrix
165165
- Extract from `<ResourceURL resourceType="FeatureInfo">` elements
166166
- Info formats specified in capabilities as MIME types
167167

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
168+
**ESRI Identify** - Uses `identify` endpoint with JSON format:
169+
- **MapServer**: `${baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&...&f=json`
170+
- **ImageServer**: `${baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&...&f=json`
171+
- Uses `f=json` parameter to return ESRI JSON format for broad compatibility across ArcGIS versions
172+
- MapServer uses `returnGeometry=true`, ImageServer uses `returnCatalogItems=true`
172173

173174
## Common Pitfalls
174175

src/capabilities.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Current Conditions, https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&versio
88
Coastal Flood Risk Index, https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&version=1.3.0&request=GetCapabilities&layers=CoastalFloodRiskIndex
99
Fire Weather Hotspots (2020), https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&version=1.3.0&request=GetCapabilities&layers=RAQDPS-FW.CE_HOTSPOTS.2020
1010
Wildfire Hotspots, https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&version=1.3.0&request=GetCapabilities&layers=WildfireHotspots
11+
Service web du Ministère de la Sécurité publique du Québec, https://geoegl.msp.gouv.qc.ca/apis/wss/inondation2020.fcgi?SERVICE=WMS&REQUEST=GetCapabilities
1112
Air Quality - NO2 Monthly Average, https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&version=1.3.0&request=GetCapabilities&layers=RDAQA.CE_NO2-MAvg
1213
Weather Radio Stations, https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&version=1.3.0&request=GetCapabilities&layers=WEATHERADIO
1314
Sea Ice Volume (1km), https://geo.weather.gc.ca/geomet/?lang=en&service=WMS&version=1.3.0&request=GetCapabilities&layers=WCPS_1km_SeaIceVol

src/script/mapmlify-layer.js

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,15 @@ class MapmlifyLayer extends HTMLElement {
9494
this.#selectedProjection = c.projection || 'OSMTILE';
9595
}
9696

97-
// Query format default
97+
// Query format default (smart selection based on priority)
9898
if (st === 'WMS') {
99-
this.#selectedQueryFormat = c.getFeatureInfoFormats?.[0] || 'text/html';
99+
this.#selectedQueryFormat = this.#selectBestQueryFormat(
100+
c.getFeatureInfoFormats || []
101+
);
100102
} else if (st === 'WMTS') {
101-
this.#selectedQueryFormat = layer.infoFormats?.[0] || 'text/html';
103+
this.#selectedQueryFormat = this.#selectBestQueryFormat(
104+
layer.infoFormats || []
105+
);
102106
}
103107

104108
// Dimension defaults
@@ -109,7 +113,8 @@ class MapmlifyLayer extends HTMLElement {
109113
}));
110114

111115
this.#boundsEnabled = true;
112-
this.#queryEnabled = false;
116+
// Query enabled by default if layer is queryable
117+
this.#queryEnabled = this.#layerIsQueryable();
113118
this.#viewerActive = false;
114119
this.#sourceCodeVisible = false;
115120
this.#selectedExportMode = 'individual';
@@ -1432,7 +1437,7 @@ class MapmlifyLayer extends HTMLElement {
14321437
queryLink.setAttribute('data-query-link', 'true');
14331438
queryLink.setAttribute(
14341439
'tref',
1435-
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&layers=all:${layer.id}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=true&f=html`
1440+
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&layers=all:${layer.id}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=true&f=json`
14361441
);
14371442
mapExtent.appendChild(queryLink);
14381443
}
@@ -1543,7 +1548,7 @@ class MapmlifyLayer extends HTMLElement {
15431548
queryLink.setAttribute('data-query-link', 'true');
15441549
queryLink.setAttribute(
15451550
'tref',
1546-
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=false&returnCatalogItems=true&f=html`
1551+
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=false&returnCatalogItems=true&f=json`
15471552
);
15481553
mapExtent.appendChild(queryLink);
15491554
}
@@ -1691,7 +1696,7 @@ class MapmlifyLayer extends HTMLElement {
16911696
queryLink.setAttribute('data-query-link', 'true');
16921697
queryLink.setAttribute(
16931698
'tref',
1694-
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&layers=all:${layer.id}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=true&f=html`
1699+
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&layers=all:${layer.id}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=true&f=json`
16951700
);
16961701
mapExtent.appendChild(queryLink);
16971702
} else {
@@ -1731,7 +1736,7 @@ class MapmlifyLayer extends HTMLElement {
17311736
queryLink.setAttribute('data-query-link', 'true');
17321737
queryLink.setAttribute(
17331738
'tref',
1734-
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=false&returnCatalogItems=true&f=html`
1739+
`${c.baseUrl}/identify?geometry={i},{j}&geometryType=esriGeometryPoint&sr=${c.wkid}&tolerance=5&mapExtent={xmin},{ymin},{xmax},{ymax}&imageDisplay={w},{h},96&returnGeometry=false&returnCatalogItems=true&f=json`
17351740
);
17361741
mapExtent.appendChild(queryLink);
17371742
} else {
@@ -1743,6 +1748,39 @@ class MapmlifyLayer extends HTMLElement {
17431748

17441749
// ─── SHARED HELPERS ───────────────────────────────────
17451750

1751+
// Select best query format based on priority:
1752+
// 1. text/mapml
1753+
// 2. application/json or application/geo+json
1754+
// 3. text/html
1755+
// 4. text/plain
1756+
// 5. first format in list (fallback)
1757+
#selectBestQueryFormat(formats) {
1758+
if (!formats || formats.length === 0) return 'text/html';
1759+
1760+
// Check for text/mapml (highest priority)
1761+
const mapml = formats.find((f) => f.toLowerCase() === 'text/mapml');
1762+
if (mapml) return mapml;
1763+
1764+
// Check for application/json or application/geo+json
1765+
const json = formats.find(
1766+
(f) =>
1767+
f.toLowerCase() === 'application/json' ||
1768+
f.toLowerCase() === 'application/geo+json'
1769+
);
1770+
if (json) return json;
1771+
1772+
// Check for text/html
1773+
const html = formats.find((f) => f.toLowerCase() === 'text/html');
1774+
if (html) return html;
1775+
1776+
// Check for text/plain
1777+
const plain = formats.find((f) => f.toLowerCase() === 'text/plain');
1778+
if (plain) return plain;
1779+
1780+
// Fallback to first format
1781+
return formats[0];
1782+
}
1783+
17461784
#layerIsQueryable() {
17471785
const c = this.#config;
17481786
const st = c.serviceType;

tests/esri-imageserver.spec.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,17 @@ test.describe('ESRI ImageServer — Query', () => {
9797
await expect(layer.locator('.query-format-selector')).toHaveCount(1);
9898
});
9999

100-
test('enabling query adds identify link', async ({ page }) => {
100+
test('query enabled by default adds identify link', async ({ page }) => {
101101
await loadService(page, SERVICE_URL);
102102
await activateLayer(page, 0);
103-
const layer = page.locator('mapmlify-layer').nth(0);
104-
await layer.locator('.query-format-selector input[type="checkbox"]').check();
105-
// Wait for viewer rebuild
106-
await layer.locator('mapml-viewer').waitFor({ timeout: 15000 });
103+
// Query is enabled by default for queryable services
107104
const mapLayer = viewerLocator(page, 0, 'map-layer[data-esri-layer]');
108105
const queryLink = mapLayer.locator('map-link[rel="query"]');
109106
await expect(queryLink).toHaveCount(1);
110107
const tref = await queryLink.getAttribute('tref');
111108
expect(tref).toContain('/identify?');
112109
expect(tref).toContain('geometry={i},{j}');
113110
expect(tref).toContain('geometryType=esriGeometryPoint');
111+
expect(tref).toContain('f=json');
114112
});
115113
});

tests/esri-mapserver.spec.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,17 @@ test.describe('ESRI MapServer (Dynamic)', () => {
134134
await expect(extent.locator('map-input[name="h"]')).toHaveCount(1);
135135
});
136136

137-
test('enabling query adds identify link', async ({ page }) => {
137+
test('query enabled by default adds identify link', async ({ page }) => {
138138
await loadService(page, DYNAMIC_URL);
139139
await activateLayer(page, 0);
140-
const layer = page.locator('mapmlify-layer').nth(0);
141-
await layer.locator('.query-format-selector input[type="checkbox"]').check();
142-
// Wait for viewer rebuild
143-
await layer.locator('mapml-viewer').waitFor({ timeout: 15000 });
140+
// Query is enabled by default for queryable services
144141
const mapLayer = viewerLocator(page, 0, 'map-layer[data-esri-layer]');
145142
const queryLink = mapLayer.locator('map-link[rel="query"]');
146143
await expect(queryLink).toHaveCount(1);
147144
const tref = await queryLink.getAttribute('tref');
148145
expect(tref).toContain('/identify?');
149146
expect(tref).toContain('geometry={i},{j}');
150147
expect(tref).toContain('geometryType=esriGeometryPoint');
148+
expect(tref).toContain('f=json');
151149
});
152150
});

tests/wms-111.spec.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ test.describe('WMS 1.1.1 — Version-Specific Parameters', () => {
5151
test('query tref uses X/Y instead of I/J', async ({ page }) => {
5252
await loadService(page, SERVICE_URL);
5353
await activateLayer(page, 0);
54-
// Enable query
55-
const layer = page.locator('mapmlify-layer').nth(0);
56-
await layer.locator('.query-format-selector input[type="checkbox"]').check();
54+
// Query is enabled by default
5755
const queryLink = viewerLocator(page, 0, 'map-link[rel="query"]');
5856
await expect(queryLink).toHaveCount(1);
5957
const tref = await queryLink.getAttribute('tref');

tests/wms-130.spec.js

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -123,21 +123,18 @@ test.describe('WMS 1.3.0 — Image Link', () => {
123123
});
124124

125125
test.describe('WMS 1.3.0 — Query Link', () => {
126-
test('queryable layer has no query link by default', async ({ page }) => {
126+
test('queryable layer has query link by default', async ({ page }) => {
127127
await loadService(page, SERVICE_URL);
128128
await activateLayer(page, 0);
129-
// Query is disabled by default
129+
// Query is enabled by default for queryable layers
130130
const queryLinks = viewerLocator(page, 0, 'map-link[rel="query"]');
131-
await expect(queryLinks).toHaveCount(0);
131+
await expect(queryLinks).toHaveCount(1);
132132
});
133133

134-
test('enabling query adds query link with I/J params', async ({ page }) => {
134+
test('query link uses I/J params for WMS 1.3.0', async ({ page }) => {
135135
await loadService(page, SERVICE_URL);
136136
await activateLayer(page, 0);
137-
// Enable query checkbox
138-
const layer = page.locator('mapmlify-layer').nth(0);
139-
await layer.locator('.query-format-selector input[type="checkbox"]').check();
140-
// Wait for query link to appear
137+
// Query is enabled by default
141138
const queryLink = viewerLocator(page, 0, 'map-link[rel="query"]');
142139
await expect(queryLink).toHaveCount(1);
143140
const tref = await queryLink.getAttribute('tref');

tests/wmts.spec.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,10 @@ test.describe('WMTS — Tile Link', () => {
106106
});
107107

108108
test.describe('WMTS — Query Link', () => {
109-
test('queryable layer gets query link when enabled', async ({ page }) => {
109+
test('queryable layer gets query link by default', async ({ page }) => {
110110
await loadService(page, SERVICE_URL);
111111
await activateLayer(page, 0);
112-
// Enable query
113-
const layer = page.locator('mapmlify-layer').nth(0);
114-
await layer.locator('.query-format-selector input[type="checkbox"]').check();
115-
// Wait for viewer rebuild
116-
await layer.locator('mapml-viewer').waitFor({ timeout: 15000 });
112+
// Query is enabled by default for queryable layers
117113
const mapLayer = viewerLocator(page, 0, 'map-layer[data-wmts-layer]');
118114
const queryLink = mapLayer.locator('map-link[rel="query"]');
119115
await expect(queryLink).toHaveCount(1);

0 commit comments

Comments
 (0)