Skip to content
Snippets Groups Projects
Commit 61c62d6e authored by Tor-Einar Skog's avatar Tor-Einar Skog
Browse files

Robust datasource map

parent 5ca17b04
Branches
No related tags found
2 merge requests!13Saddlegallmidge form idec 372,!12feat: Add test page (spatial) with mapserver layer in openlayers map
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
*/ */
const ipmdDSSApiURL = "https://platform.ipmdecisions.net/api/dss/"; const ipmdDSSApiURL = "https://platform.ipmdecisions.net/api/dss/";
const ipmdWeatherApiURL = "https://platform.ipmdecisions.net/api/wx/"; //const ipmdWeatherApiURL = "https://platform.ipmdecisions.net/api/wx/";
const ipmdWeatherApiURL = "http://ipmdlocal/api/wx/";
async function getModelMetadata(dssId,modelId) { async function getModelMetadata(dssId,modelId) {
...@@ -281,10 +282,10 @@ function mergeWeatherData(primaryData, secondaryData) ...@@ -281,10 +282,10 @@ function mergeWeatherData(primaryData, secondaryData)
}); });
// Calculate dimensions of the merged data set // Calculate dimensions of the merged data set
console.info("timeStart=" + mergedData.timeStart.format("YYYY-MM-DD") + ", timeEnd=" + mergedData.timeEnd.format("YYYY-MM-DD")); //console.info("timeStart=" + mergedData.timeStart.format("YYYY-MM-DD") + ", timeEnd=" + mergedData.timeEnd.format("YYYY-MM-DD"));
let length = (getUnix(mergedData.timeEnd) - getUnix(mergedData.timeStart)) / mergedData.interval; let length = (getUnix(mergedData.timeEnd) - getUnix(mergedData.timeStart)) / mergedData.interval;
let width = mergedData.weatherParameters.length; let width = mergedData.weatherParameters.length;
console.info(length + "*" + width); //console.info(length + "*" + width);
let dataSet = Array.from(Array(length), () => new Array(width)); let dataSet = Array.from(Array(length), () => new Array(width));
//console.info(dataSet); //console.info(dataSet);
// Keeping track of offsets (if dataset does not cover the entire combined period of the merging datasets) // Keeping track of offsets (if dataset does not cover the entire combined period of the merging datasets)
...@@ -293,8 +294,8 @@ function mergeWeatherData(primaryData, secondaryData) ...@@ -293,8 +294,8 @@ function mergeWeatherData(primaryData, secondaryData)
let primaryDataSet = primaryData.locationWeatherData[0].data; let primaryDataSet = primaryData.locationWeatherData[0].data;
let secondaryDataSet = secondaryData.locationWeatherData[0].data; let secondaryDataSet = secondaryData.locationWeatherData[0].data;
console.info("primaryOffset=" + primaryOffset); //console.info("primaryOffset=" + primaryOffset);
console.info(primaryDataSet); //console.info(primaryDataSet);
// Finally: Merge the data! // Finally: Merge the data!
for(let i=0;i<dataSet.length;i++) for(let i=0;i<dataSet.length;i++)
...@@ -312,7 +313,7 @@ function mergeWeatherData(primaryData, secondaryData) ...@@ -312,7 +313,7 @@ function mergeWeatherData(primaryData, secondaryData)
} }
if(primaryOffset <= i && i-primaryOffset < primaryDataSet.length ) if(primaryOffset <= i && i-primaryOffset < primaryDataSet.length )
{ {
console.info(i-primaryOffset); //console.info(i-primaryOffset);
for(let j=0; j<primaryData.weatherParameters.length;j++) for(let j=0; j<primaryData.weatherParameters.length;j++)
{ {
if(!isEmpty(primaryDataSet[i-primaryOffset][j])) if(!isEmpty(primaryDataSet[i-primaryOffset][j]))
...@@ -331,7 +332,7 @@ function mergeWeatherData(primaryData, secondaryData) ...@@ -331,7 +332,7 @@ function mergeWeatherData(primaryData, secondaryData)
function getUnix(aDate) function getUnix(aDate)
{ {
console.info(typeof aDate); //console.info(typeof aDate);
if(typeof aDate == "string") if(typeof aDate == "string")
{ {
aDate = moment(aDate); aDate = moment(aDate);
...@@ -345,6 +346,111 @@ function isEmpty(val) ...@@ -345,6 +346,111 @@ function isEmpty(val)
return val === undefined || val === null; return val === undefined || val === null;
} }
// Keeping track of maps
var maps = {};
/**
* Requires OpenLayers v. 4
* @param {String} containerId
* @param {JSON} geoJson
*/
async function initDataSourceMap(containerId, geoJson, countryCodeList)
{
let map = maps[containerId];
// Delete whatever was there
if(map != undefined)
{
map.setTarget(undefined);
map = null;
}
//console.info(countryCodeList);
//console.info(geoJson);
// If no data, no map
if((geoJson == undefined || geoJson == null || geoJson.features.length == 0) && (countryCodeList == null || countryCodeList.length == 0))
{
document.getElementById(containerId).innerHTML = "NO GEODATA PROVIDED BY WEATHER DATA SOURCE";
return;
}
else{
document.getElementById(containerId).innerHTML = "";
}
var backgroundLayer = new ol.layer.Tile({
source: new ol.source.OSM({
attributions: [
new ol.Attribution({
html: "TEST"
})
]
})
});
// Creating the map
map = new ol.Map({
target: containerId,
layers: [backgroundLayer],
renderer: 'canvas'
});
maps[containerId] = map;
// Setting zoom and center for the map (need to do this after creating map. so that we can transform our
// center to correct map projection)
var view = new ol.View({
center: ol.proj.transform([10,65], 'EPSG:4326', map.getView().getProjection().getCode()),
zoom: 7,
maxZoom: 7
});
map.setView(view);
let features = new ol.Collection();
let format = new ol.format.GeoJSON();
let drawnFeatures = undefined;
// If we have geoJson available, we display that
if (geoJson != null && geoJson.features.length > 0) {
drawnFeatures = format.readFeatures(geoJson, {
dataProjection: 'EPSG:4326',
featureProjection: map.getView().getProjection().getCode()
});
}
// If not, we have to get geoJson mapped to the countries
else if (countryCodeList != undefined && countryCodeList != null && countryCodeList.length > 0) {
let countryBoundaries = await getCountryBoundaries(countryCodeList);
//console.info(countryBoundaries);
drawnFeatures = await format.readFeatures(countryBoundaries, {
dataProjection: 'EPSG:4326',
featureProjection: map.getView().getProjection().getCode()
});
}
if(drawnFeatures != undefined)
{
//console.info(drawnFeatures);
var featureOverlay = new ol.layer.Vector({
source: new ol.source.Vector({
features: features
})
});
featureOverlay.getSource().addFeatures(drawnFeatures);
featureOverlay.setMap(map);
extent = featureOverlay.getSource().getExtent();
map.getView().fit(extent, map.getSize());
}
}
async function getCountryBoundaries(countryCodeList)
{
const response = await fetch(ipmdWeatherApiURL + "rest/country/" + countryCodeList.join(","));
return await response.json();
}
const fallbackParams = { const fallbackParams = {
1001: [1002], 1001: [1002],
1002: [1001], 1002: [1001],
...@@ -357,6 +463,7 @@ const fallbackParams = { ...@@ -357,6 +463,7 @@ const fallbackParams = {
} }
const weatherParameterList = [ const weatherParameterList = [
{ {
"id": 1001, "id": 1001,
......
...@@ -29,30 +29,48 @@ ...@@ -29,30 +29,48 @@
<div id="inputForm"></div> <div id="inputForm"></div>
<div id="weatherDataForm" style="display: none;"> <div id="weatherDataForm" style="display: none;">
<h2>Weather data</h2> <h2>Weather data</h2>
<fieldset id="historicDatasourceFields"> <div class="row">
<legend>Weather datasource (historic)</legend> <div class="col-md-8">
<select class="form-control" name="weatherDatasourceId" id="weatherDatasourceList" onchange="handleWeatherDatasourceSelected(this);"></select> <fieldset id="historicDatasourceFields">
<div id="historicSourceInfo" style="display: none;"></div> <legend>Weather datasource (historic)</legend>
</fieldset> <select class="form-control" name="weatherDatasourceId" id="weatherDatasourceList" onchange="handleWeatherDatasourceSelected(this);"></select>
<fieldset id="stationFields" style="display: none;"> <div id="historicSourceInfoPanel" class="panel panel-default" style="display: none;">
<select class="form-control" name="weatherStationId" id="weatherStationId" onchange="handleWeatherStationSelected(this);" ></select> <div class="panel-body" id="historicSourceInfo"></div>
</fieldset> </div>
<fieldset id="locationFields"> </fieldset>
<legend>Location (decimal degrees)</legend> <fieldset id="stationFields" style="display: none;">
<div class="form-group"> <select class="form-control" name="weatherStationId" id="weatherStationId" onchange="handleWeatherStationSelected(this);" ></select>
<label for="latitude">Latitude</label> </fieldset>
<input type="number" class="form-control" id="latitude" name="latitude" placeholder="Latitude"> <fieldset id="locationFields">
<legend>Location (decimal degrees)</legend>
<div class="form-group">
<label for="latitude">Latitude</label>
<input type="number" class="form-control" id="latitude" name="latitude" placeholder="Latitude">
</div>
<div class="form-group">
<label for="longitude">Longitude</label>
<input type="number" class="form-control" id="longitude" name="longitude" placeholder="Longitude">
</div>
</fieldset>
</div> </div>
<div class="form-group"> <div class="col-md-4">
<label for="longitude">Longitude</label> <div id="historicDatasourceMap"></div>
<input type="number" class="form-control" id="longitude" name="longitude" placeholder="Longitude">
</div> </div>
</fieldset> </div>
<fieldset id="forecastDatasourceFields"> <div class="row">
<legend>Weather forecasts datasource</legend> <div class="col-md-8">
<select class="form-control" name="forecastWeatherDatasourceId" id="forecastWeatherDatasourceList" onchange="handleForecastSourceSelected(this);"></select> <fieldset id="forecastDatasourceFields">
<div id="forecastSourceInfo" style="display: none;"></div> <legend>Weather forecasts datasource</legend>
</fieldset> <select class="form-control" name="forecastWeatherDatasourceId" id="forecastWeatherDatasourceList" onchange="handleForecastSourceSelected(this);"></select>
<div id="forecastSourceInfoPanel" class="panel panel-default" style="display: none;">
<div class="panel-body" id="forecastSourceInfo"></div>
</div>
</fieldset>
</div>
<div class="col-md-4">
<div id="forecastDatasourceMap"></div>
</div>
</div>
<button class="btn btn-primary" type="button" onclick="submitData();">Submit</button> <button class="btn btn-primary" type="button" onclick="submitData();">Submit</button>
<div style="aspect-ratio: 2;"> <div style="aspect-ratio: 2;">
<canvas id="resultChart""></canvas> <canvas id="resultChart""></canvas>
...@@ -62,11 +80,17 @@ ...@@ -62,11 +80,17 @@
<pre id="modelDescription"></pre> <pre id="modelDescription"></pre>
</div> </div>
{% endblock %} {% endblock %}
{% block extendCSS %}
<link rel="stylesheet" href="{% static "css/3rdparty/ol.css" %}" type="text/css">
{% endblock%}
{% block customJS %} {% block customJS %}
<script src="https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script type="text/javascript" src="{% static "js/3rdparty/moment.min.js" %}"></script> <script type="text/javascript" src="{% static "js/3rdparty/moment.min.js" %}"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script> <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-moment"></script>
<script type="text/javascript" src="{% static "js/3rdparty/ol-debug.js" %}"></script>
<script type="text/javascript" src="{% static "ipmd/js/ipmdlib.js" %}"></script> <script type="text/javascript" src="{% static "ipmd/js/ipmdlib.js" %}"></script>
<script type="text/javascript"> <script type="text/javascript">
// Page globals // Page globals
...@@ -83,13 +107,19 @@ ...@@ -83,13 +107,19 @@
modelMetaData = await getModelMetadata("adas.dss","HAPDMA"); modelMetaData = await getModelMetadata("adas.dss","HAPDMA");
document.getElementById("modelDescription").innerHTML= await modelMetaData["description"]; document.getElementById("modelDescription").innerHTML= await modelMetaData["description"];
inputFormSchema = await getModelInputSchema("adas.dss","HAPDMA") inputFormSchema = await getModelInputSchema("adas.dss","HAPDMA")
console.info(inputFormSchema); inputFormSchema.title ="Model input data";
//console.info(inputFormSchema);
const element = document.getElementById('inputForm'); const element = document.getElementById('inputForm');
// See https://github.com/json-editor/json-editor#options
editor = new JSONEditor(element, editor = new JSONEditor(element,
{ {
ajax: true, ajax: true,
schema: inputFormSchema, schema: inputFormSchema,
theme: "bootstrap4" theme: "bootstrap4",
iconlib: "fontawesome4",
disable_edit_json: true,
disable_properties: true
}); });
let fullSchema = JSON.parse(modelMetaData["execution"]["input_schema"]); let fullSchema = JSON.parse(modelMetaData["execution"]["input_schema"]);
if(fullSchema["properties"]["weatherData"] !== undefined) if(fullSchema["properties"]["weatherData"] !== undefined)
...@@ -97,7 +127,7 @@ ...@@ -97,7 +127,7 @@
// Pull weather data sources from web service, render lists (historic and forecast sources, some are both) // Pull weather data sources from web service, render lists (historic and forecast sources, some are both)
weatherDatasources = await getWeatherDatasources(); weatherDatasources = await getWeatherDatasources();
console.info(weatherDatasources); //console.info(weatherDatasources);
weatherDatasources.sort((a, b) => { weatherDatasources.sort((a, b) => {
return (a.name < b.name) ? -1 : (a.name > b.name) ? 1 : 0; return (a.name < b.name) ? -1 : (a.name > b.name) ? 1 : 0;
}); });
...@@ -138,10 +168,21 @@ ...@@ -138,10 +168,21 @@
currentWeatherDatasource = getWeatherDatasource( currentWeatherDatasource = getWeatherDatasource(
weatherDatasources, weatherDatasources,
weatherDatasourceList.options[weatherDatasourceList.selectedIndex].value weatherDatasourceList.options[weatherDatasourceList.selectedIndex].value
); );
let sourceInfoPanel = document.getElementById("historicSourceInfoPanel");
if(currentWeatherDatasource == null)
{
sourceInfoPanel.style.display="none";
document.getElementById("stationFields").style.display = "none";
return;
}
// Display map
initDataSourceMap("historicDatasourceMap", JSON.parse(currentWeatherDatasource.spatial.geoJSON), currentWeatherDatasource.spatial.countries);
let sourceInfo = document.getElementById("historicSourceInfo"); let sourceInfo = document.getElementById("historicSourceInfo");
sourceInfo.innerHTML = currentWeatherDatasource.description; sourceInfo.innerHTML = currentWeatherDatasource.description;
sourceInfo.style.display="block"; sourceInfoPanel.style.display="block";
if(currentWeatherDatasource.access_type == "stations") if(currentWeatherDatasource.access_type == "stations")
{ {
// Display the weather stations // Display the weather stations
...@@ -156,7 +197,7 @@ ...@@ -156,7 +197,7 @@
// TODO: Add map? // TODO: Add map?
} }
console.info(currentWeatherDatasource); //console.info(currentWeatherDatasource);
} }
function handleForecastSourceSelected(forecastSourceSelectList) function handleForecastSourceSelected(forecastSourceSelectList)
...@@ -164,29 +205,36 @@ ...@@ -164,29 +205,36 @@
currentForecastWeatherDatasource = getWeatherDatasource( currentForecastWeatherDatasource = getWeatherDatasource(
weatherDatasources, weatherDatasources,
forecastWeatherDatasourceList.options[forecastWeatherDatasourceList.selectedIndex].value forecastWeatherDatasourceList.options[forecastWeatherDatasourceList.selectedIndex].value
); );
let sourceInfo = document.getElementById("historicSourceInfo");
sourceInfo.innerHTML = currentWeatherDatasource.description; let sourceInfoPanel = document.getElementById("forecastSourceInfoPanel");
sourceInfo.style.display="block"; if(currentForecastWeatherDatasource == null)
{
sourceInfoPanel.style.display="none";
return;
}
let sourceInfo = document.getElementById("forecastSourceInfo");
sourceInfo.innerHTML = currentForecastWeatherDatasource.description;
sourceInfoPanel.style.display="block";
} }
function handleWeatherStationSelected(weatherStationSelectList) function handleWeatherStationSelected(weatherStationSelectList)
{ {
let weatherStationId = selectList.options[selectList.selectedIndex].value; let weatherStationId = selectList.options[selectList.selectedIndex].value;
let stationCoordinate = getWeatherStationCoordinate(currentWeatherDatasource, weatherStationId); let stationCoordinate = getWeatherStationCoordinate(currentWeatherDatasource, weatherStationId);
console.info(stationCoordinate); //console.info(stationCoordinate);
document.getElementById("longitude").value = stationCoordinate[0]; document.getElementById("longitude").value = stationCoordinate[0];
document.getElementById("latitude").value = stationCoordinate[1]; document.getElementById("latitude").value = stationCoordinate[1];
} }
async function submitData(){ async function submitData(){
console.info("submitData!"); //console.info("submitData!");
let inputData = editor.getValue(); let inputData = editor.getValue();
console.info(inputData); //console.info(inputData);
// Add hidden parameters // Add hidden parameters
let fullSchema = JSON.parse(modelMetaData["execution"]["input_schema"]); let fullSchema = JSON.parse(modelMetaData["execution"]["input_schema"]);
const hiddenParameters = modelMetaData["execution"]["input_schema_categories"]["hidden"]; const hiddenParameters = modelMetaData["execution"]["input_schema_categories"]["hidden"];
console.info(hiddenParameters); //console.info(hiddenParameters);
for(let i=0;i<hiddenParameters.length;i++) for(let i=0;i<hiddenParameters.length;i++)
{ {
let hiddenParameter = hiddenParameters[i]; let hiddenParameter = hiddenParameters[i];
...@@ -195,7 +243,7 @@ ...@@ -195,7 +243,7 @@
// Check for weatherData element. Assuming it's at the root node // Check for weatherData element. Assuming it's at the root node
if(fullSchema["properties"]["weatherData"] !== undefined) if(fullSchema["properties"]["weatherData"] !== undefined)
{ {
console.info("Need to get weather data!"); //console.info("Need to get weather data!");
let forecastData = undefined; let forecastData = undefined;
// 1. Historic weather data // 1. Historic weather data
if(currentWeatherDatasource != undefined) if(currentWeatherDatasource != undefined)
...@@ -296,7 +344,7 @@ ...@@ -296,7 +344,7 @@
let chartData = []; let chartData = [];
// Generate dates // Generate dates
let dates = getDateArray(result.timeStart, 86400, result.locationResult[0].length); let dates = getDateArray(result.timeStart, 86400, result.locationResult[0].length);
console.info(dates); //console.info(dates);
for(let i=0; i< result.resultParameters.length;i++) for(let i=0; i< result.resultParameters.length;i++)
{ {
let dataset = {label:result.resultParameters[i], data: []} let dataset = {label:result.resultParameters[i], data: []}
...@@ -341,7 +389,8 @@ ...@@ -341,7 +389,8 @@
html += "</tr></thead>" html += "</tr></thead>"
html += "<tbody>"; html += "<tbody>";
for(let i=0;i< weatherData.locationWeatherData[0].length;i++) //console.info("Weatherdata length: " + weatherData.locationWeatherData[0].data.length);
for(let i=0;i< weatherData.locationWeatherData[0].data.length;i++)
{ {
html += "<tr><td>" + moment(dates[i]).format("YYYY-MM-DD HH:mm:ss") + "</td>"; html += "<tr><td>" + moment(dates[i]).format("YYYY-MM-DD HH:mm:ss") + "</td>";
weatherData.locationWeatherData[0].data[i].forEach(function(val){html+="<td>" + val + "</td>";}) weatherData.locationWeatherData[0].data[i].forEach(function(val){html+="<td>" + val + "</td>";})
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment