From 8913bf51edc27e0b1686ffbee54e364301d82fb0 Mon Sep 17 00:00:00 2001 From: DafyddLlyr Date: Sun, 21 Nov 2021 21:30:23 +0000 Subject: [PATCH 1/2] Setup WMS branch --- gazetteer.js | 186 ------------------------------------------------ index.html | 18 ----- interactions.js | 32 --------- main.js | 21 +----- popover.js | 65 ----------------- style.css | 66 +---------------- wfs.js | 82 --------------------- 7 files changed, 2 insertions(+), 468 deletions(-) delete mode 100644 gazetteer.js delete mode 100644 interactions.js delete mode 100644 popover.js delete mode 100644 wfs.js diff --git a/gazetteer.js b/gazetteer.js deleted file mode 100644 index 4ec1f82..0000000 --- a/gazetteer.js +++ /dev/null @@ -1,186 +0,0 @@ -// Gazetteer/AddressBase Form Code - -let zoomToFn; - -// Initilaise the Gazetteer form -function initGazetteer(zoomTo) { - // Store the zoom function pointer here for use when a result is clicked - zoomToFn = zoomTo - - // Add a listener to the Gazetteer search form - const form = document.getElementById("gazetteer_search"); - form.addEventListener("submit", (evt) => submitGazetteerForm(evt)); - - // Add a listener to the Gazetteer results list - const selector = document.getElementById("gazetteer_result"); - selector.addEventListener("change", (evt) => selectGazetteerResult(evt)); - - // Add a listener to the AddressBase search form - const form2 = document.getElementById("addressbase_search"); - form2.addEventListener("submit", (evt) => submitAddressBaseForm(evt)); - - // Add a listener to the AddressBase results list - const selector2 = document.getElementById("addressbase_result"); - selector2.addEventListener("change", (evt) => selectAddressBaseResult(evt)); -} - -// Call the Gazetteer API when a search is requested -function submitGazetteerForm(evt) -{ - // Stop the form refreshing the page - evt.preventDefault(); - - // Call the Gazetteer API - callGazetteerApi(evt.target[0].value).then(data => { - // Handle the response - handleGazetteerResponses(data); - }); -} - -// Called when a Gazetteer result is selected -function selectGazetteerResult(evt) -{ - // Zoom the map to the selected result - zoomToFn(evt.target.value); -} - -// Call the AddressBase API when a search is requested -function submitAddressBaseForm(evt) -{ - // Stop the form refreshing the page - evt.preventDefault(); - // Call the AddressBase API - callAddressBaseApi(evt.target[0].value).then(data => { - // Handle the response - handleAddressBaseResponses(data); - }); -} - -// Called when an AddressBase result is selected -function selectAddressBaseResult(evt) -{ - // Zoom the map to the selected result - zoomToFn(evt.target.value); -} - -// API Code - -// Gazetteer API URL -// Sample request: https://api.themapcloud.com/api/v2/gazetteer/search-all/?token= -const gazetteerAPI = "https://api.themapcloud.com/api/v2/gazetteer/search-all/"; - -// AddressBase Postcode API URL -/* Sample request: - https://api.themapcloud.com/address/addressbase/postcode? - token=& - pc=& - addrformat=1& (1,2,3 = one line address, multi-line address, individual fields) - format=json& (json or xml) - datatype=dpa (dpa or lpi = post office vs local govt gazetteer) -*/ -const addressBaseAPI = "https://api.themapcloud.com/address/addressbase/postcode"; - -// Read the token from the .env parameters -const token = import.meta.env.VITE_TMC_TOKEN; - -// Asyncronous call to the Gazetteer API -async function callGazetteerApi(searchFor) { - // construct the url - const url = gazetteerAPI + searchFor + "?token=" + token; - // make the call and await the response - const response = await fetch(url, { - method: "GET", - headers: { - "Accept": "application/json", - } - }).catch((/*error*/) => handleNetworkError()); - // On success, convert the result to json - return response.json(); -} - -// Handle the Gazetteer responses -function handleGazetteerResponses(data) { - // Get the select options list - var dataList = document.getElementById("gazetteer_result"); - // Empty previous results - while (dataList.firstChild) { dataList.removeChild(dataList.firstChild);} - // Create and add a default option - var defaultOption = document.createElement('option'); - defaultOption.value = ""; - defaultOption.text = "select to zoom..."; - defaultOption.selected = true; - dataList.appendChild(defaultOption); - - // Disable the select if there were no results - dataList.disabled = data.matches.length < 1; - - // Add the results to the select options - data.matches.forEach(match => { - // Create an option - var option = document.createElement('option'); - // Set the value to the x,y coordinate string - option.value = match.geometry_x + "," + match.geometry_y; - // Set the text to the location text - option.text = match.location; - // Don't select this option yet - option.selected = false; - // Add to the list - dataList.appendChild(option); - }); -} - -// Error handler -function handleNetworkError() { - console.log("Network Error: Please check that you're connected to VPN"); -} - -// Asyncronous call to the AddressBase API -async function callAddressBaseApi(postcode) { - // construct the url - const url = addressBaseAPI + "?token=" + token + "&pc=" + postcode + "&addrformat=1&format=json&datatype=dpa"; - // make the call and await the response - const response = await fetch(url, { - method: "GET", - headers: { - "Accept": "application/json", - } - }).catch((/*error*/) => handleNetworkError()); - // On success, convert the result to json - return response.json(); -} - -// Handle the AddressBase responses -function handleAddressBaseResponses(data) { - // Get the select options list - var dataList = document.getElementById("addressbase_result"); - - // Empty previous results - while (dataList.firstChild) { dataList.removeChild(dataList.firstChild);} - - // Create and add a default option - var defaultOption = document.createElement('option'); - defaultOption.value = ""; - defaultOption.text = "select to zoom..."; - defaultOption.selected = true; - dataList.appendChild(defaultOption); - - // Disable the select if there were no results - dataList.disabled = data.results.length < 1; - - // Add the results to the select options - data.results.forEach(result => { - // Create an option - var option = document.createElement('option'); - // Set the value to the x,y coordinate string - option.value = result.x_coord + "," + result.y_coord; - // Set the text to the address text - option.text = result.address; - // Don't select this option yet - option.selected = false; - // Add to the list - dataList.appendChild(option); - }); -} - -// Export the init function for the main script to pick up -export default initGazetteer diff --git a/index.html b/index.html index 99ab2d9..e1f32d1 100644 --- a/index.html +++ b/index.html @@ -8,24 +8,6 @@
- -
- - -
diff --git a/interactions.js b/interactions.js deleted file mode 100644 index 6b0586b..0000000 --- a/interactions.js +++ /dev/null @@ -1,32 +0,0 @@ -import { Select, Translate, Modify } from 'ol/interaction'; - -// Simple function to log out the area of a feature -const logFeatureArea = (feature) => { - const selectedGeom = feature.getGeometry(); - const area = selectedGeom.getArea().toFixed(2); - console.log(`Area: ${area}m²`); -} - -// Create a new "Select" interaction -// https://openlayers.org/en/latest/apidoc/module-ol_interaction_Select-Select.html -const select = new Select(); - -// Attach the logFeatureArea to an event on the select interaction -select.on("select", evt => logFeatureArea(evt.selected[0])) - -// Create a new "Translate" interaction -// https://openlayers.org/en/latest/apidoc/module-ol_interaction_Translate-Translate.html -const translate = new Translate({ - features: select.getFeatures(), -}); - -// Create a new "Modify" interaction -// https://openlayers.org/en/latest/apidoc/module-ol_interaction_Modify-Modify.html -const modify = new Modify({ - features: select.getFeatures(), -}); - -// Iterate over the interactions created above, and add them to the map -const initInteractions = (map) => [select, translate, modify].forEach(interaction => map.addInteraction(interaction)) - -export default initInteractions; \ No newline at end of file diff --git a/main.js b/main.js index e4c1fee..5ab8d0c 100644 --- a/main.js +++ b/main.js @@ -5,15 +5,10 @@ import getWMTSLayer from "./wmts"; import projectionBNG from "./projection"; import TileLayer from "ol/layer/Tile"; import getWMSLayer from "./wms"; -import initPopover from "./popover"; -import getWFSLayer from "./wfs"; -import initInteractions from "./interactions"; -import initGazetteer from "./gazetteer"; // Create layer from imported functions const mastermapWMTS = await getWMTSLayer("os_licensed_background_colour"); const woodlandWMS = getWMSLayer("sf_nwss"); -const scenicAreasWFS = getWFSLayer("osmm:osmm_topographicarea") // Set up a new Tile Layer const openStreetMap = new TileLayer({ @@ -29,7 +24,6 @@ const map = new Map({ // openStreetMap, mastermapWMTS, woodlandWMS, - // scenicAreasWFS, ], // A View object represents a simple 2D view of the map. // This is the object to act upon to change the center, resolution, and rotation of the map @@ -39,17 +33,4 @@ const map = new Map({ center: [279731, 693249], zoom: 6, }), -}); - -// Zoom to -function zoomTo(coord_string) { - var split = coord_string.split(","); - if(split.length == 2) { - map.getView().setResolution(0.5); - map.getView().setCenter([parseInt(split[0]), parseInt(split[1])]); - } -} - -initPopover(map, woodlandWMS); -// initInteractions(map); -// initGazetteer(zoomTo); +}); \ No newline at end of file diff --git a/popover.js b/popover.js deleted file mode 100644 index e3754f9..0000000 --- a/popover.js +++ /dev/null @@ -1,65 +0,0 @@ -import Overlay from "ol/Overlay"; - -// References to HTML elements we will target to create our popover -const container = document.getElementById("popup"); -const content = document.getElementById("popup-content"); -const closer = document.getElementById("popup-closer"); - -// Instantiate a new Overlay -// An Overlay is an element to be displayed over the map and attached to a single map location -// https://openlayers.org/en/latest/apidoc/module-ol_Overlay-Overlay.html -const popup = new Overlay({ - element: container, - autoPan: true, - autoPanAnimation: { - duration: 250, - }, -}); - -// Close the popop on click of the closer element -closer.onclick = () => { - popup.setPosition(undefined); - closer.blur(); - return false; -}; - -// Setup the popup position and content -const setupPopup = (coord, attributes) => { - // Clear previous attributes - content.innerHTML = ""; - // Set the position of the popop - popup.setPosition(coord); - // Iterate over the attributes, appending a simple HTML snipped for each one - Object.entries(attributes).forEach( - ([key, value]) => (content.innerHTML += `

${key}: ${value}

`) - ); -}; - -// Initialise the popover -const initPopover = (map, layer) => { - // Define the function which trigger on click of the map - map.on("singleclick", (evt) => { - // Get the previously assigned map layer - const layerName = layer.getProperties().layerName; - const viewResolution = map.getView().getResolution(); - // Get the URL for the GetFeatureInfo request - const url = layer - .getSource() - .getFeatureInfoUrl(evt.coordinate, viewResolution, "EPSG:27700", { - INFO_FORMAT: "application/json", - QUERY_LAYERS: layerName, - }); - if (url) { - fetch(url) - .then((response) => response.json()) - .then((geojson) => { - // GetFeatureInfo returns a GeoJSON objevt from which we can extract the attributes to view in our popup - setupPopup(evt.coordinate, geojson.features[0].properties); - // Finally, add the overlay to our map - map.addOverlay(popup); - }); - } - }); -}; - -export default initPopover; \ No newline at end of file diff --git a/style.css b/style.css index da17887..e5eba2f 100644 --- a/style.css +++ b/style.css @@ -11,68 +11,4 @@ html, body { top: 0; bottom: 0; width: 100%; -} - -/* CSS for Popup */ - -.ol-popup { - position: absolute; - background-color: white; - box-shadow: 0 1px 4px rgba(0,0,0,0.2); - padding: 15px; - border-radius: 10px; - border: 1px solid #cccccc; - bottom: 12px; - left: -50px; - min-width: 280px; -} - -#popup-content > p { - margin: 5px; -} - -.ol-popup:after, .ol-popup:before { - top: 100%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; -} - -.ol-popup:after { - border-top-color: white; - border-width: 10px; - left: 48px; - margin-left: -10px; -} - -.ol-popup:before { - border-top-color: #cccccc; - border-width: 11px; - left: 48px; - margin-left: -11px; -} - -.ol-popup-closer { - text-decoration: none; - position: absolute; - top: 2px; - right: 8px; -} - -.ol-popup-closer:after { - content: "✖"; - color: black; -} - -/* CSS for Gazetteer */ - -.gazetteer { - z-index: 1000; - position: absolute; - left: 5vw; - bottom: 10vh; - } - \ No newline at end of file +} \ No newline at end of file diff --git a/wfs.js b/wfs.js deleted file mode 100644 index b6affb8..0000000 --- a/wfs.js +++ /dev/null @@ -1,82 +0,0 @@ -import { bbox as bboxStrategy } from "ol/loadingstrategy"; -import { WFS } from "ol/format"; -import { Fill, Stroke, Style } from 'ol/style'; -import VectorLayer from "ol/layer/Vector"; -import VectorSource from "ol/source/Vector"; - -// Helper function get a WFS layer from the MapCloud -// Note: The details required to make this request are returned by the CustomerService API -// https://api.themapcloud.com/api/v2/customer-services/details/{mapservice_id} -const getWFSLayer = (layerName) => { - // Extract the featurePrefix and featureType from the full layer name - const [featurePrefix, featureType] = layerName.split(":") - // Create a new instance of the WFS class - // This is a feature format for reading and writing data in the WFS format - const formatWFS = new WFS(); - // Set up our Vector Source for the WFS layer - const sourceWFS = new VectorSource({ - // Define our loader function which will fetch features from our service - loader: (extent) => { - // Create an encoded WFS GetFeature request - const featureRequest = formatWFS.writeGetFeature({ - srsName: "EPSG:27700", - featureNS: `http://thinkwhere.com/${featurePrefix}`, - featurePrefix: featurePrefix, - featureTypes: [featureType], - bbox: extent, - // Geometry name can be variable, but hardcoded for this function - // See note above on how to get these details from tMC API - geometryName: "polygon", - maxFeatures: 1000, - }); - // Make a POST request to the WFS API endpoint - fetch( - `https://api.themapcloud.com/maps/wfs?token=${ - import.meta.env.VITE_TMC_TOKEN - }`, - { - method: "POST", - // Serialise our GetFeature request as a string - body: new XMLSerializer().serializeToString(featureRequest), - } - ) - .then((response) => response.text()) - .then((xml) => { - // Parse response and convert XML (GML) to OpenLayers features - // This is the step that requires the projectionGML object from earlier - let features = formatWFS.readFeatures(xml, { - dataProjection: "EPSG:27700", - featureProjection: "EPSG:27700", - }); - // Add our OL features to the source - sourceWFS.addFeatures(features); - }); - }, - // Define a loading stategy to use for fetching features - // OL has a few built in, or a custom strategy can be created - strategy: bboxStrategy, - }); - - // Define a style to apply to our layer - const wfsStyle = new Style({ - stroke: new Stroke({ - color: 'rgba(0, 0, 255, 1.0)', - width: 2, - }), - fill: new Fill({ - color: 'rgba(0, 0, 255, 0.3)' - }) - }); - - // Create a vector layer using our source and style - const vectorLayer = new VectorLayer({ - source: sourceWFS, - style: wfsStyle, - // A scale threshold is set to limit the number of features returned in one go - minZoom: 14, - }); - - return vectorLayer; -}; - -export default getWFSLayer; From 79bf30ca7f6872dab24c8f057dd5dd6991af9c9e Mon Sep 17 00:00:00 2001 From: DafyddLlyr Date: Sun, 21 Nov 2021 21:48:33 +0000 Subject: [PATCH 2/2] Fix imports --- main.js | 1 + wmts.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/main.js b/main.js index fc47364..0b8011a 100644 --- a/main.js +++ b/main.js @@ -3,6 +3,7 @@ import { Map, View } from "ol"; import OSM from "ol/source/OSM.js"; import projectionBNG from "./projection"; import TileLayer from "ol/layer/Tile"; +import getWMTSLayer from "./wmts"; import getWMSLayer from "./wms"; // Create layer from imported functions diff --git a/wmts.js b/wmts.js index 27d245f..9534d62 100644 --- a/wmts.js +++ b/wmts.js @@ -26,4 +26,4 @@ const getWMTSLayer = async (layerName) => { return wmtsLayer; }; -export default getWMTSLayer; +export default getWMTSLayer; \ No newline at end of file