GetFeatureInfo query only for visible layers in OpenLayers 6 - javascript

I'm a newby with JS and OL, and I have an Openlayers 6 map with different WMS layers grouped into several ol.layer.Group. I want to request feature information through "getGetFeatureInfoUrl". Visibility of layers can be turned on/off in the layer tree. I'd like to, upon clicking somewhere in the map:
Get Feature Info ONLY for layers that are currently visible
and, if there are more than one layers at the chosen location, get the Feature Info for all of them
This code works well for just one layer (wmsLayer5, in this case)
map.on('singleclick', function (evt) {
if (!wmsLayer5.getVisible()) return;
document.getElementById('info').innerHTML = '';
const viewResolution = /** #type {number} */ (vista.getResolution());
const url = wmsLayer5.getSource().getFeatureInfoUrl(
evt.coordinate,
viewResolution,
'EPSG:25830',
{'INFO_FORMAT': 'text/html'}
);
if (url) {
fetch(url)
.then((response) => response.text())
.then((html) => {
document.getElementById('info').innerHTML = html;
});
}
});
But I need a code to iterate over all layers and only call getFeatureInfo if they are visible. I've tried this one, but doesn't work and doesn't return any message in the console
map.on('singleclick', function (evt1) {
document.getElementById('info').innerHTML = '';
var viewResolution = /** #type {number} */
(vista.getResolution());
var url = '';
document.getElementById('info').innerHTML ='';
layers.forEach(function (layer, i, layers) {
if (layer.getVisible() ) {
url = layer.getSource().getGetFeatureInfoUrl(
evt1.coordinate,
viewResolution,
'EPSG:25830', {
'INFO_FORMAT': 'text/html',
'FEATURE_COUNT': '300'
});
if (url) {
fetch(url)
.then((response) => response.text())
.then((html) => {
document.getElementById('info').innerHTML += html;
});
}
}
});
});
Any suggestion to fix it?

This method has been deprecated since version 6.13 (4 months ago) and won't be changed before next major release. I didn't use suggested replacement layer.getData(). Following code iterates through all the layers and queries only visible ones and of type Image.
map.on("click", onMouseClick);
function onMouseClick(browserEvent) {
let coordinate = browserEvent.coordinate;
let pixel = map.getPixelFromCoordinate(coordinate);
map.forEachLayerAtPixel(pixel, function (layer) {
if (layer instanceof ol.layer.Image) {
if (layer.get("visible")) {
let url = layer.getSource().getFeatureInfoUrl(coordinate, map.getView().getResolution(), "EPSG:3857", {
INFO_FORMAT: "application/json",
});
if (url) {
fetch(url)
.then(function (response) {
return response.text();
})
.then(function (json) {
let data = JSON.parse(json);
if (data.features.length > 0) {
//Do something with data.features
}
});
}
}
}
});
}

Related

Having trouble console.log anything from this API, we're not allowed to use JQuery or Bootstrap, so I have to use fetch and bulma

so I've been having trouble trying to get anything to console.log from this API, the most I can get is a null or undefined return. I've tried just the base statement from the API company, and the code snippet runs for them but for some reason won't even return a console.log for me. not sure if it's a problem on their end or mine because it seems to run fine on their website. also as I said in the title, I have to use fetch
EDIT: I'm in coding school right now so I'm pretty new to all of this
EDIT: the dashboard shows that the API is being called, so why am I not getting any responses?
EDIT: I figured it out, the API wasn't working
// global variables
var countryInput = document.querySelector("#ipt-country");
var submitButton = document.querySelector("#submit-btn");
var currencyDisplay = document.querySelector("#currency-display");
// country currency array codes
var countryCurrencyArray =[ list off all countries with iso code for currency goes here, not going to list it bc its 270 lines long
];
// begins exchange rate function
function getExchangeRate() {
// grab data attribute
var countrySearch = countryInput.value.toLowerCase().trim();
var currencyUSA = "USD";
var countryCurrency = "AUD";
// var countryCurrency = countryInput.value.countryCurrencyArray[i];
// if else errors
if (countrySearch.length < 1) {
return(null);
} else {
var countryConversion = countryCurrencyArray.find(
(element) => element.name === countrySearch)
}
if (countryConversion === void 0) {
return(null);
} else {
var countryCurrency = countryConversion.code;
}
// fetch API to change currency rate from American Dollar (USD) to selected currency
fetch(
'https://currency-converter5.p.rapidapi.com/currency/convert?' +
'&from=' + currencyUSA +
'&to=' + countryCurrency +
'&amount=1',
{
"method": "GET",
"headers": {
"x-rapidapi-host": "currency-converter5.p.rapidapi.com",
"x-rapidapi-key": "API-KEY"
},
}).then(response => {
console.log(response);
})
.then(function(response) {
response.json().then(function(data){
for (i=0; i < data.response.countryCurrency.length; i++) {
var exchangeMoney = document.createElement("div");
exchangeMoney.classList.add(
"is-flex-mobile",
"column",
"has-text-centered",
"is-justify-content-space-evenly"
);
var exchangeOutput = document.createElement("div");
exchangeRateOutput.classList.add("level-item");
exchangeRateOutput.innerText = data.response.countryCurrency[i].code;
exchangeRateMoney.appendChild(exchangeOutput);
console.log(exchangeOutput);
}
});
}).catch(err => {
console.error('Request Failed', err);
});
}
getExchangeRate();
console.log(getExchangeRate());
submitButton.addEventListener("click", getExchangeRate);

Get all items or data from API where they need to meet a condition to be fetched

I want to display a list of all items or data from an API source where the VirtualOrganization (or some other data) is the one i specify (like ATCclub). I use Axios to get the data.
Baicicly I only want to only fetch the JSON data from the API where the VirtualOrganization is the right one, and then display it.
Here is my code:
let data;
axios.get(URLBASE + '/flights/' + expert + '?apikey=' + APIKEY, {
params: {
virtualOrganization: "ATCclub"
}
})
.then(response => {
console.log(response.data.result);
if (response.data.result.virtualOrganization === "ATCclub") {
for (let i = 0; i < response.data.result.virtualOrganization.array.length; i++) {
document.getElementById("username").innerHTML = response.data.result.username;
document.getElementById("aircraftId").innerHTML = response.data.result.aircraftId;
document.getElementById("heading").innerHTML = response.data.result.heading;
document.getElementById("latitude").innerHTML = response.data.result.latitude;
document.getElementById("longitude").innerHTML = response.data.result.longitude;
document.getElementById("speed").innerHTML = response.data.result.speed;
document.getElementById("altitude").innerHTML = response.data.result.altitude;
}
}
})
.catch(error => console.error(error));
NOTE: I have managed to display one row from the JSON.
I found a solution after someone sent me a answer to "filter it after".
Then I came up with this:
// resF (result of flights)
const resF = response.data.result.filter(function (e){
return e.virtualOrganization === "ATCclub";
});

"weather is not defined" error when working with openwethermap API

I'm somewhat new to working with API's using vanilla JavaScript and I keep running into this error when trying to access the "description" within the "weather object". The console keeps reading "weather is not defined". I'm using the open weather map API. In theory I should be able to retrieve using data.current.weather.description. but that doesn't work, along with the other variations I've tried. Here is my current code.
window.addEventListener("load", () => {
let long;
let lat;
let temperatureDescription = document.querySelector(
".temperature-description"
);
let temperatureDegree = document.querySelector(".temperature-degree");
let locationTimezone = document.querySelector(".location-timezone");
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
long = position.coords.longitude;
lat = position.coords.latitude;
const proxy = "https://cors-anywhere.herokuapp.com/";
const api = `${proxy}https://api.openweathermap.org/data/2.5/onecall?lat=${lat}&lon=${long}&
exclude=hourly,daily&appid=da5463709c92ab1860d3a81037565c6e`;
fetch(api)
.then((response) => {
return response.json();
})
.then((data) => {
console.log(data);
const {
temp,
weather: { description },
} = data.current;
//Set DOM Elements from the API
let kelvinToCelsius = temp - 273.15;
temperatureDegree.textContent = kelvinToCelsius.toFixed(0);
temperatureDescription.textContent = description;
locationTimezone.textContent = data.timezone;
});
});
} else {
}
});
If anyone has ran into this issue and solved, it would be much appreciated if you filled me in.

How do you access the list of tags in a container via 3rd party javascript?

Trying to find a way to list all of the tags in a GTM container via JavaScript. We are looking to export all of the tags for a customer into a Google Sheets so that we can better get a handle on cleaning up their container (currently have 500+ tags).
I've successfully grabbed the container from GTM into Sheets, but according to several google searches, the container does not have a property for the tags underneath it.
var gtmID;
var webPropertyID;
var name;
var triggerType;
var firingTrigger;
var lastEdited;
var clientID = 'CLIENT_ID';
var containerName = 'Customer - WEBSITES';
var workspaceName = 'Default Workspace';
var container;
var scopes=['https://www.googleapis.com/auth/tagmanager.manage.accounts',
'https://www.googleapis.com/auth/tagmanager.edit.containers',
'https://www.googleapis.com/auth/tagmanager.delete.containers',
'https://www.googleapis.com/auth/tagmanager.edit.containerversions',
'https://www.googleapis.com/auth/tagmanager.manage.users',
'https://www.googleapis.com/auth/tagmanager.publish'];
var jsonObjectGTM=[];
var jsonObjectTags=[];
function controller() {
gtmID = 'GTM_ID';
listContainer(gtmID);
listTags(jsonObjectGTM);
recordTags(jsonObjectTags);
}
function checkAuth(immediate) {
var authorizeCheckPromise = new Promise((resolve) => {
gapi.auth.authorize(
{ client_id: clientID, scope: scopes.join(' '), immediate: immediate}, resolve);
});
authorizeCheckPromise
.then(handleAuthResult)
.then(loadTagManagerApi)
.then(runTagManagerTask)
.catch(() => {
console.log('you must authorize any access to the api.');
}
//Check if the user has authoriation
function checkAuth() {
checkAuth(true);
}
//Initiate auth flow in response to user clicking authorize button
function handleAuthclick(event) {
checkAuth();
return false;
}
//Handle response from authorization server
function handleAuthResult(authResult) {
return new Promise((resolce, reject) => {
var authorizeDiv = document.getElementById('authorize-div');
if(authResult && !authResult.error) {
//Hide auth UI, then load client library
authorizeDiv.style.display = 'none';
resolve();
} else {
//Show auth UI, allowing the user to initiate authorization by clicking authorize button
authorizeDiv.style.display = 'inline';
reject();
}
});
}
//load Tag Manager API client library
function loadTagManagerApi() {
return new Promise((resolve, reject) => {
console.log('Load Tag Manager api');
gapi.client.load('tagmanager', 'v2', resolve);
});
}
//Interacts with the tagmanager api v2 to grab the tags
function runTagManagerTask() {
return new Promise((resolve, reject) => {
console.log('Grabbing list of tags');
container = findContainer(gtmID, containerName)
.catch(handleError);
resolve();
}
}
//handles error
function handleError(error) {
console.log('Error when interacting with GTM API');
console.log(error);
}
//Wraps an API request in a promise
function reqestPromise(request) {
return new Promise((resolve, reject) => {
request.execute((response) => {
if (response.code) {
reject(response);
}
resolve(response);
}
}
}
//Returns the specified container
function findContainer(accountPath, containerName) {
consle.log('Finding container in account:' + accountPath);
var request = gapi.client.tagmanager.accounts.containers.list({'parent' : accountPath});
return requestPromise(request)
.then((response) => {
var containers = response.container || [];
var container = containers.find((container) => container.name === containerName);
return container ||
Promise.reject('Unable to find ' + containerName + ' container.');
});
}
Just need to find a way to grab the array/list of tags from the container once I've grabbed it
Thanks to #Eike Pierstorff for the recommendation for Simo Ahava's tool, it helped the process quite a bit, much more accurate and likely faster than any script.
However as far as scripting went, this was my solution:
var name;
var tagType;
var firingTrigger;
var sheet;
var tagList = [];
function controller() {
tagList = TagManager.Accounts.Containers.Workspaces.Tags.list('accounts/{accountID}/containers/{containerID}/workspaces/{workspaceID}');
sheet = SpreadsheetApp.getActiveSpreadsheet();
for (var i = 0; i < tagList.tag.length; i++) {
name = tagList.tag[i].name;
firingTrigger = tagList.tag[i].firingTriggerId;
tagType = tagList.tag[i].type;
sheet.appendRow([name, tagType, firingTrigger]);
}
}

routingParams.departure has no effect for calculateIsoline

I'm using the H.platform.routingService().calculateIsoline method and had expected that the routeParams.departure property would have an effect on the result.
However, changing the date and/or time of day has no effect on the calculated isoline.
In the code below, startLocs is an array of geocode objects with lat and lng
let queryDateString = queryDate.format('YYYY-MM-DDTHH:mm:ss');
startLocs.forEach(loc => {
var routingParams = {
mode: 'fastest;car;',
start: `geo!${loc.geocode.lat},${loc.geocode.lng}`,
range: 600,
rangetype: 'time',
departure: queryDateString
};
// Define a callback function to process the isoline response.
var onResult = result => {
var center = new H.geo.Point(
result.response.center.latitude,
result.response.center.longitude
),
isolineCoords = result.response.isoline[0].component[0].shape,
linestring = new H.geo.LineString(),
isolinePolygon,
isolineCenter;
// Add the returned isoline coordinates to a linestring:
isolineCoords.forEach(function(coords) {
linestring.pushLatLngAlt.apply(linestring, coords.split(','));
});
// Create a polygon and a marker representing the isoline:
isolinePolygon = new H.map.Polygon(linestring);
isolineCenter = new H.map.Marker(center);
// Add the polygon and marker to the map:
this.markerGroup.addObject(isolineCenter);
this.polylineGroup.addObject(isolinePolygon);
};
// Get an instance of the routing service:
var router = this.platform.getRoutingService();
// Call the Routing API to calculate an isoline:
router.calculateIsoline(routingParams, onResult, function(error) {
console.log(error)
});
});
this.isLoading = false;
} catch (err) {
console.log('failed processing isochrones', err);
}
Regardless of the value of queryDateString in this example, the results are identical.
The documentation states that the ReST APIs query params map to properties in the routeParams so I expected that the departure property should have an effect. Does anyone know if that's not the case?
EDIT:
Updated to include working example in case anyone stumbles across this:
let queryDateString = queryDate.format('YYYY-MM-DDTHH:mm:ss');
let onResult = result => {
let center = new H.geo.Point(
result.response.center.latitude,
result.response.center.longitude
)
let isolineCoords = result.response.isoline[0].component[0].shape;
let linestring = new H.geo.LineString();
let isolinePolygon;
let isolineCenter;
// Add the returned isoline coordinates to a linestring:
isolineCoords.forEach(function(coords) {
linestring.pushLatLngAlt.apply(linestring, coords.split(','));
});
// Create a polygon and a marker representing the isoline:
isolinePolygon = new H.map.Polygon(linestring);
isolineCenter = new H.map.Marker(center);
//let isolineObj = [isolineCenter, isolinePolygon];
// Add the polygon and marker to the map:
this.markerGroup.addObject(isolineCenter);
this.polylineGroup.addObject(isolinePolygon);
};
let router = this.platform.getRoutingService();
startLocs.forEach(loc => {
let routingParams = {
mode: 'fastest;car;traffic:enabled',
start: `geo!${loc.geocode.lat},${loc.geocode.lng}`,
range: this.maxTime * 60,
rangetype: 'time',
departure: queryDateString
};
// Call the Routing API to calculate an isoline:
router.calculateIsoline(routingParams, onResult, function(error) {
alert(error.message);
});
});
}
catch (err) {
console.log('failed processing isochrones', err);
}
finally{
this.isLoading = false;
}
The mode is missing the traffic part. Please try to add this '&mode=fastest;car;traffic:enabled'. Then you will also get for example you sent a different shape for e.g. 10:00 am.
Here we have some extended example for visualizing isolines:
https://tcs.ext.here.com/examples/v3/isoline_routing
This might be interesting for you too.

Categories

Resources