Fullstack Portal Created by the HCMR for the Marine Strategy Framework Directive Program in order to cover demands and aspects considering extendability and maintainability
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

560 lines
14 KiB

var requestsGrid;
var wfd;
var legends = {};
var selectedEntityGroup = null;
var selectedEntityId = null;
var selectedMru = null;
async function get_layer_list() {
let response = await fetch(BASE_URL + '/src/geoserver/get_layers.php');
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
let json = await response.json();
return json
} else {
alert("HTTP-Error: " + response.status);
}
}
async function fetchGeoJson(layerCode) {
console.debug('fetching geojson...');
const url = BASE_URL + "/interface/geojson/" + layerCode;
try {
const response = await fetch(url);
const data = await response.json();
console.debug(data);
return data;
} catch (error) {
console.error(error);
}
}
function highlightFeature(e) {
let overLayer = e.target;
e.target.tempStyle = {
weight: overLayer.options.weight,
color: overLayer.options.color,
dashArray: overLayer.options.dashArray,
fillOpacity: overLayer.options.fillOpacity
};
console.debug("highlighted: ", e.target);
try {
overLayer.setStyle({
weight: 5,
color: '#666',
dashArray: '',
fillOpacity: 0.7
});
} catch (err) {
console.log('could not change style');
}
}
function resetHighlight(e) {
try {
e.target.setStyle(e.target.tempStyle);
delete e.target.tempStyle;
} catch {
console.debug('eee');
}
}
function onEachFeature(feature, layer) {
layer.on({
mouseover: highlightFeature,
mouseout: resetHighlight,
click: zoomToFeature
});
}
function styleLine(feature, layer) {
return {
fillColor: getColor(), //feature.properties.name
weight: 2,
radius: 8,
opacity: 1,
color: '#000',
dashArray: '3',
fillOpacity: 0.8
};
}
function stylePoint(feature, latlng) {
console.debug(feature);
return L.circleMarker(latlng, styleRules);
};
function getColor(d=null) {
if (d != null)
return intToRGB(hashCode(d));
else
return "#ff7800";
}
function intToRGB(i){
var c = (i & 0x00FFFFFF)
.toString(16)
.toUpperCase();
return "00000".substring(0, 6 - c.length) + c;
}
function hashCode(str) { // java String#hashCode
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
return hash;
}
// zoom to feature (for data sources)
function zoomToFeature(e) {
let featureId = e.target.feature.properties.id;
try {
selectedEntityGroup = e.target.feature.id.split('.')[0];
selectedEntityId = e.target.feature.properties.id;
} catch (error) {
selectedEntityId = e.target.feature.properties.id;
}
lonlat = {lon: e.latlng.lng, lat: e.latlng.lat};
moreInfoPopup(e.target.feature.properties);
try {
mapL.fitBounds(e.target.getBounds());
} catch (err) {
console.log('cannot zoom ', err);
}
}
function boundsToExtent(northEast, southWest, my_crs) {
let my_proj = my_crs.projection;
let rt = my_proj.project(northEast);
let lb = my_proj.project(southWest);
return {
left: lb.x,
bottom: lb.y,
right: rt.x,
top: rt.y
}
}
function getBathymetry() {
// load contours in JSON
const url = "https://ows.emodnet-bathymetry.eu/wfs?service=WFS&version=1.1.0&request=GetFeature&typeName=emodnet:contours&outputFormat=application/json";
const rainbow_url = "https://ows.emodnet-bathymetry.eu/wms";
let remoteLayer;
// add rainbow colored bathymetry map
const rnb = L.tileLayer.wms(rainbow_url, { transparent: true, layers: 'emodnet:mean_rainbowcolour', format: 'image/png'});
const cnt = L.tileLayer.wms(rainbow_url, { transparent: true, layers: 'emodnet:contours', format: 'image/png'});
legends['DPTH'] = L.control.Legend({
position: "bottomright",
symbolWidth: 150,
symbolHeight: 208,
collapsed: true,
legends: [{
type: "image",
label: ' ',
url: "https://tiles.emodnet-bathymetry.eu/legends/legend_rainbow.png"
}]
}).addTo(mapL);
remoteLayer = L.layerGroup([rnb, cnt]);
return remoteLayer;
}
async function getDepthOnPoint(latlng) {
await fetch(`https://rest.emodnet-bathymetry.eu/depth_sample?geom=POINT(${latlng.lng}%20${latlng.lat})`, {
"credentials": "omit",
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language": "en-US,en;q=0.5",
"Upgrade-Insecure-Requests": "1",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-site",
"Sec-GPC": "1"
},
"method": "GET",
"mode": "cors"
}).then(res => {
return res.json();
}).then(depthInfo => {
const depth = depthInfo.avg.toString();
L.popup()
.setLatLng(latlng)
.setContent(`<table class="table"><tr><th>Topography (m)</th></tr><tr><td>${depth}</td></tr></table>`)
.openOn(mapL);
});
}
// function downloadStationData(stationid) {
// console.debug('stationid: ', stationid);
// if (stationid.length === 0) {
// return;
// }
// fetch(`${BASE_URL}/src/data/get_station_data.php?id=${stationid}`, {
// "credentials": "include",
// "headers": {
// "Accept": "application/zip",
// "Accept-Language": "en-US,en;q=0.5",
// "Sec-Fetch-Dest": "empty",
// "Sec-Fetch-Mode": "cors",
// "Sec-Fetch-Site": "same-origin",
// "Pragma": "no-cache",
// "Cache-Control": "no-cache"
// },
// "method": "GET",
// "mode": "cors"
// }).then(res => { return res.blob(); })
// .then((data) => {
// var a = document.createElement("a");
// a.href = window.URL.createObjectURL(data);
// a.download = "request";
// a.click();
// });
// }
// function downloadCruiseData(cruiseId) {
// if (cruiseId.length === 0) {
// return;
// }
// console.debug("CRUISE ID: ", cruiseId);
//
// fetch(`${BASE_URL}/src/data/get_cruise_data.php?id=${cruiseId}`, {
// "credentials": "include",
// "headers": {
// "Accept": "application/zip",
// "Accept-Language": "en-US,en;q=0.5",
// "Sec-Fetch-Dest": "empty",
// "Sec-Fetch-Mode": "cors",
// "Sec-Fetch-Site": "same-origin",
// "Pragma": "no-cache",
// "Cache-Control": "no-cache"
// },
// "method": "GET",
// "mode": "cors"
// }).then(res => { return res.blob(); })
// .then((data) => {
// var a = document.createElement("a");
// a.href = window.URL.createObjectURL(data);
// a.download = "request";
// a.click();
// });
// }
function getHabitat(layerCode) {
// load contours in JSON
const url = "https://ows.emodnet-seabedhabitats.eu/geoserver/emodnet_view/wms";
const lgndUrl = "https://ows.emodnet-seabedhabitats.eu/geoserver/emodnet_view/ows?service=WMS&request=GetLegendGraphic&format=image%2Fpng&width=20&height=20&layer=eusm2021_bio_200&style=eusm2019_msfd_200"
// add rainbow colored bathymetry map
let habitats = new L.layerGroup();
const lrs = ['eusm2021_msfd_800', 'eusm2021_msfd_400', 'eusm2021_msfd_200'];
let l;
lrs.forEach(layer => {
l = L.tileLayer.betterWms(url, { transparent: true, layers: layer, format: 'image/png'});
habitats.addLayer(l)
});
legends[layerCode] = L.control.Legend({
position: "bottomright",
symbolWidth: 400,
symbolHeight: 600,
collapsed: true,
title: 'Habitat Type',
legends: [{
type: "image",
label: ' ',
url: lgndUrl
}]
}).addTo(mapL);
return habitats;
}
function moreInfoPopup(props) {
Alpine.store('entity', props);
let title;
if (props.hasOwnProperty('code')) {
title = `${props.code} &mdash; ${props.name}`;
} else {
title = `Grid &mdash; ${props.cellcode}`;
}
console.debug(props);
// if (typeof props.code == 'undefined' && typeof props.name == 'undefined')
if (typeof props.tspr !== 'undefined')
title = `POSEIDON &mdash; ${props.pid}`;
if (typeof props.ctStationCode !== 'undefined')
title = `WFD &mdash; ${props.ctStationCode}`;
getPagePartial('more-info').then(content => {
new L.control.window(mapL, {
title: title,
content: `${content}`,
visible: true,
position: 'left'
});
});
}
function mruPopup(props) {
if (props.hasOwnProperty('nssg')) {
L.popup()
.setLatLng([props.y_coord, props.x_coord])
.setContent(`<table class="table"><tr><th>NSSG Label</th></tr><tr><td>${props.nssg_label}</td></tr></table>`)
.openOn(mapL);
return;
}
let title;
Alpine.store('mru', props);
title = `MRU: ${props.mr_ms_aa}`;
getPagePartial('mru-info').then(content => {
content.props = props;
new L.control.window(mapL, {
title: title,
content: `${content}`,
visible: true,
position: 'left'
});
});
}
// Fetches html from elements folder
async function getPagePartial(partialName, target=null) {
// const url = BASE_URL + `/src/Views/${partialName}.php`;
const url = BASE_URL + `/interface/partial/${partialName}`;
const res = await fetch(url)
.then((response) => {return response.text();})
.then((content) => {
return content
})
.catch((err) => {return err;});
try {
// fill target element with html
document.querySelector(target).innerHTML = res;
} catch(err) {
return res;
}
}
function getProduct(layer) {
let url = layer.endpoint;
let legendUrl = layer.legend;
let l;
l = L.tileLayer.betterWms(url, { transparent: true, layers: layer.code, format: 'image/png'});
legends[layer.code] = L.control.Legend({
position: "bottomright",
symbolWidth: 100,
symbolHeight: 200,
collapsed: true,
title: 'Probability of habitat presence',
legends: [{
type: "image",
label: ' ',
url: legendUrl
}]
}).addTo(mapL);
mapL.on('click', e => {
let location = e.latlng;
});
return l;
}
/**
* Submit a request to the server and returns the entry inserted
* @param {number} desc
* @param {number} crit
* @return {json}
*/
function request_data(desc, crit, from, to, bodyId=null) {
console.debug('requesting data');
let url = BASE_URL + `/src/data/search_request_data.php?bodyid=${bodyId}&dateFrom=${from}&dateTo=${to}&criteria=${crit}`;
fetch(url)
.then(res => {
return res.json();
}).then(data => {
db.requests.add({
uuid: data.uuid,
filename: data.filename
}).then(d => {
requestsGrid.updateConfig({
data: data
}).forceRender();
});
});
}
function initializeLayerTree() {
pTree = new PickleTree({
c_target: 'layertree', //'maptab_treeview',
c_config: {
// options here
switchMode: true,
hasLink: true,
drag: false,
contextPos: 'before',
foldedStatus: true
},
switchCallback: layerTreeSwitch,
c_data: myData
});
}
function getWFD(layerName) {
const legendName = layerName.split('_').slice(1,3).join('_');
const lgndUrl = BASE_URL + "/images/legends/" + legendName + ".png";
console.debug(lgndUrl);
let l;
l = L.tileLayer.wms(BASE_URL + '/geoserver/wms', { transparent: true, layers: layerName, format: 'image/png'});
legends[layerName] = L.control.Legend({
position: "bottomright",
symbolWidth: 90,
symbolHeight: 130,
collapsed: true,
legends: [{
type: "image",
label: ' ',
url: lgndUrl
}]
}).addTo(mapL);
return l;
}
async function searchForRequests() {
let response = await fetch(BASE_URL + '/actions/requests');
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
let json = await response.json();
return json;
} else {
alert("HTTP-Error: " + response.status);
}
}
function flattenJson(data, depth = 1) {
var result = {};
function recurse(cur, prop) {
if (Object(cur) !== cur || depth === 0) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for(var i=0, l=cur.length; i<l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop + "." + p : p, depth - 1);
}
if (isEmpty && prop)
result[prop] = {};
}
}
recurse(data, "", depth);
return result;
}
async function downloadShapefile(layerName, srs) {
let response = await fetch(BASE_URL + '/geoserver/shapefile/' + layerName + '/' + srs, {
"credentials": "include",
"headers": {
"Accept": "application/zip",
"Accept-Language": "en-US,en;q=0.5",
"Sec-Fetch-Dest": "empty",
"Sec-Fetch-Mode": "cors",
"Sec-Fetch-Site": "same-origin",
"Pragma": "no-cache",
"Cache-Control": "no-cache"
},
"method": "GET",
"mode": "cors"
});
if (response.ok) { // if HTTP-status is 200-299
// get the response body (the method explained below)
let zip = await response.blob();
var a = document.createElement("a");
let data = await zip;
a.href = window.URL.createObjectURL(data);
a.download = layerName + "_shapefiles";
a.click();
} else {
alert("HTTP-Error: " + response.status);
}
}
async function getFisheriesProduct() {
// Create timeline slider control
const group = L.layerGroup();
// load contours in JSON
const bgLayer = L.tileLayer.betterWms(BASE_URL + '/geoserver/wms', { layers: 'nssg_areas', transparent: true, format: "image/png"});
const url = BASE_URL + "/interface/charts/afppy";
try {
const response = await fetch(url);
const data = await response.json();
let pies;
// Add the custom control to the map
pies = createPie(data, 1990).addTo(group);
layerControls['AFPPY'] = L.control.slider(value => {
pies.remove();
pies = createPie(data, value);
group.addLayer(pies);
},{
min: 1990,
max: 2019,
step: 1,
value: 1990,
logo: 'Year Selector',
}).addTo(mapL);
} catch (error) {
console.error(error);
}
bgLayer.addTo(group);
return group;
}