var zoomBtn = document.getElementById("zoom-"); if (zoomBtn) { zoomBtn.onclick = async function() { var layerName = Layer.get("name"); var proxyUrl = ""; var url = proxyUrl + "?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities&LAYERS=" + layerName; try { const response = await fetch(url); const text = await response.text(); const parser = new DOMParser(); const xmlDoc = parser.parseFromString(text, "text/xml"); const layerInfo = xmlDoc.getElementsByTagName("Layer"); for (let i = 0; i < layerInfo.length; i++) { const name = layerInfo[i].getElementsByTagName("Name")[0]; if (name && name.textContent === layerName) { const bboxes = layerInfo[i].getElementsByTagName("BoundingBox"); let bbox = null; let sourceSRS = null; // First try to find EPSG:4326 bbox for (let j = 0; j < bboxes.length; j++) { if (bboxes[j].getAttribute("SRS") === "EPSG:4326") { bbox = bboxes[j]; sourceSRS = "EPSG:4326"; break; } } // If no EPSG:4326 found, use the first available bbox if (!bbox && bboxes.length > 0) { bbox = bboxes[0]; sourceSRS = bbox.getAttribute("SRS"); // Ensure the projection is registered try { await ensureProjectionRegistered(sourceSRS); } catch (error) { console.error("Error registering projection:", error); return; } } if (bbox) { const extent = [ parseFloat(bbox.getAttribute("minx")), parseFloat(bbox.getAttribute("miny")), parseFloat(bbox.getAttribute("maxx")), parseFloat(bbox.getAttribute("maxy")) ]; // Add padding to the extent const width = extent[2] - extent[0]; const height = extent[3] - extent[1]; extent[0] -= width * 0.1; extent[1] -= height * 0.1; extent[2] += width * 0.1; extent[3] += height * 0.1; try { let transformedExtent; if (sourceSRS === "EPSG:4326") { transformedExtent = ol.proj.transformExtent(extent, "EPSG:4326", "EPSG:3857"); } else { const wgs84Extent = ol.proj.transformExtent(extent, sourceSRS, "EPSG:4326"); transformedExtent = ol.proj.transformExtent(wgs84Extent, "EPSG:4326", "EPSG:3857"); } if (isNaN(transformedExtent[0]) || isNaN(transformedExtent[1]) || isNaN(transformedExtent[2]) || isNaN(transformedExtent[3])) { throw new Error("Invalid transformed extent"); } map.getView().fit(transformedExtent, { padding: [50, 50, 50, 50], duration: 1000, maxZoom: 15 }); } catch (error) { console.error("Error transforming extent:", error); const defaultExtent = [-20037508.34, -20037508.34, 20037508.34, 20037508.34]; map.getView().fit(defaultExtent, { padding: [50, 50, 50, 50], duration: 1000, maxZoom: 15 }); } } else { console.error("No bounding box found for layer"); } break; } } } catch (error) { console.error("Error fetching layer extent:", error); } }; } Custom Map
0) { var currentFeatureIndex = 0; var totalFeatures = data.features.length; function generatePopupHTML(featureIndex) { var feature = data.features[featureIndex]; var props = feature.properties; // Derive correct layer name from feature.id var layerName = "Unknown Layer"; if (feature && feature.id) { // GeoServer usually returns "workspace:layername.123" var idStr = String(feature.id); if (idStr.indexOf(".") > -1) idStr = idStr.split(".")[0]; if (idStr.indexOf(":") > -1) idStr = idStr.split(":").pop(); layerName = idStr; } else if (props && (props._layer || props.layer || props.layer_name)) { layerName = props._layer || props.layer || props.layer_name; } else if (urlLayers.length > 0) { layerName = urlLayers[0]; } var html = "
"; html += "
"; html += ""; html += "" + (featureIndex + 1) + " of " + totalFeatures + ""; html += ""; html += "
"; html += ""; html += "
"; html += "
"; // Layer information html += "
"; html += "Layer: "; html += "" + layerName + ""; html += "
"; // Action buttons html += "
"; html += ""; html += ""; html += "
"; // Feature attributes - show all properties var propKeys = Object.keys(props); propKeys.forEach(function(key, index) { // Highlight important attributes like Name, Address, etc. var importantKeys = ["name", "address", "title", "description", "type", "category"]; var isHighlighted = importantKeys.some(function(importantKey) { return key.toLowerCase().includes(importantKey); }); html += "
"; html += "" + key + ": "; html += "" + (props[key] || "N/A") + ""; html += "
"; }); html += "
"; return html; } // Generate initial popup popup.innerHTML = generatePopupHTML(currentFeatureIndex); popup.style.display = "block"; overlay.setPosition(coordinate); // Add navigation functions to window scope window.navigateFeature = function(newIndex) { if (newIndex >= 0 && newIndex < totalFeatures) { currentFeatureIndex = newIndex; popup.innerHTML = generatePopupHTML(currentFeatureIndex); } }; window.closePopup = function() { popup.style.display = "none"; overlay.setPosition(undefined); }; window.showTable = function() { var f = data.features[currentFeatureIndex] || {}; var props = (f && f.properties) ? f.properties : {}; // ---- Resolve correct layer name from this feature ---- var layerName = "Unknown"; if (f && f.id) { var idStr = String(f.id); if (idStr.indexOf(".") > -1) idStr = idStr.split(".")[0]; // strip ".123" if (idStr.indexOf(":") > -1) idStr = idStr.split(":").pop(); // strip "workspace:" layerName = idStr || layerName; } else if (props && (props._layer || props.layer || props.layer_name)) { layerName = props._layer || props.layer || props.layer_name; } else if (urlLayers && urlLayers.length > 0) { layerName = urlLayers[0]; } // ---- Try to detect a primary key candidate on the clicked feature ---- var pkCandidates = ["id","fid","gid","objectid","feature_id","pk","ogc_fid"]; var pkcol = null; for (var i = 0; i < pkCandidates.length; i++) { var k = pkCandidates[i]; if (Object.prototype.hasOwnProperty.call(props, k)) { pkcol = k; break; } } // Fallback: first property that ends with "_id" if (!pkcol) { Object.keys(props || {}).some(function(k){ if (/_id$/i.test(k)) { pkcol = k; return true; } return false; }); } var pkval = pkcol ? props[pkcol] : null; var q = "layer=" + encodeURIComponent(layerName); if (pkcol && pkval !== undefined && pkval !== null) { q += "&pkcol=" + encodeURIComponent(pkcol) + "&pk=" + encodeURIComponent(pkval); } var tableUrl = "view_table.php?" + q; // Open modal and load content var modal = new bootstrap.Modal(document.getElementById(\'tableModal\')); var modalContent = document.getElementById(\'tableViewContent\'); // Update modal title if present try { var titleEl = document.querySelector(\'#tableModal .modal-title, #tableModalLabel\'); if (titleEl) { titleEl.textContent = \'Layer Table — \' + layerName; } } catch(e) {} // Show loading spinner modalContent.innerHTML = \'
Loading...
\'; modal.show(); // Load table content via fetch fetch(tableUrl) .then(function(response) { return response.text(); }) .then(function(html) { // Extract just the body content from the response var parser = new DOMParser(); var doc = parser.parseFromString(html, \'text/html\'); var bodyContent = doc.body.innerHTML; modalContent.innerHTML = bodyContent; }) .catch(function(error) { modalContent.innerHTML = \'
Error loading table: \' + error.message + \'
\'; }); }; window.zoomToFeature = function() { var f = data.features[currentFeatureIndex]; if (!f || !f.geometry) { console.warn("No geometry found for feature.", f); return; } try { // Use ol/format/GeoJSON to convert to ol.Feature var geojsonFormat = new ol.format.GeoJSON(); var olFeature = geojsonFormat.readFeature(f, { dataProjection: "EPSG:4326", // Default from GeoServer JSON featureProjection: map.getView().getProjection() }); var geom = olFeature.getGeometry(); if (!geom) { console.warn("No geometry parsed from feature.", f); return; } var extent = geom.getExtent(); // Validate extent; handle cases where geometry extent is empty/invalid var invalid = ( !extent || extent.length !== 4 || !isFinite(extent[0]) || !isFinite(extent[1]) || !isFinite(extent[2]) || !isFinite(extent[3]) || extent[0] === Infinity || extent[2] === -Infinity ); if (invalid) { // Try to derive an extent from the raw GeoJSON point or the click coordinate var buffer = 5000; if (f && f.geometry && f.geometry.type === "Point" && Array.isArray(f.geometry.coordinates)) { var p = ol.proj.transform(f.geometry.coordinates, "EPSG:4326", map.getView().getProjection()); extent = [p[0] - buffer, p[1] - buffer, p[0] + buffer, p[1] + buffer]; } else if (typeof coordinate !== "undefined" && coordinate && coordinate.length === 2) { extent = [coordinate[0] - buffer, coordinate[1] - buffer, coordinate[0] + buffer, coordinate[1] + buffer]; } else { console.warn("Empty extent and no fallback available for zoom.", f); return; } } // For Points, pad extent a bit so it is not zoomed too far in var isPoint = geom.getType() === "Point"; if (isPoint) { var buffer = 5000; // meters; adjust for your data context extent = [ extent[0] - buffer, extent[1] - buffer, extent[2] + buffer, extent[3] + buffer ]; } map.getView().fit(extent, { duration: 1000, padding: [50, 50, 50, 50], maxZoom: 15 }); } catch (err) { console.error("Could not zoom to feature:", err, f); } }; } }) .catch(function(error) { console.error("Error fetching feature info:", error); }); }); }'; } ?>