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

Merge branch 'feature/vipsutv-819' into develop

parents 582d1b8a c431ae47
No related branches found
No related tags found
No related merge requests found
Source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
......@@ -243,7 +243,7 @@ Created: 2024-10-28
<input type="radio" name="weatherdataType" id="coordinates" value="coordinates" onchange="displayCoordinatesInput();storeUserSettings();">
{% trans "for a specific location (coordinates)" %}
</label>
<div id="input-coordinates" class="form-inline" style="margin-top: 10px; display: none;"">
<div id="input-coordinates" class="form-inline" style="margin-top: 10px; display: none;">
<input type="hidden" class="form-control" name="latitude" id="latitude" placeholder="Breddegrad" aria-label="Breddegrad">
<input type="hidden" class="form-control" name="longitude" id="longitude" placeholder="Lengdegrad" aria-label="Lengdegrad">
<input type="hidden" class="form-control" name="timezone" id="timezone" placeholder="Tidssone" aria-label="Tidssone">
......
This diff is collapsed.
......@@ -49,7 +49,8 @@ var corePass = "";
// Location of weather data source
var weatherDataBaseUri = "https://lmt.nibio.no/agrometbase/export/getSeasonDailyTemperaturesJSON.php";
//var weatherDataBaseUri = "http://agrometbase-local/agrometbase/export/getSeasonDailyTemperaturesJSON.php";
const LMTServicesBaseUri = "http://localhost:8081/";
const OpenMeteoBaseUri = "http://localhost:8082/rest/grid/openmeteo/"
// Setting current time
var now = moment();
//var now = moment("2014-07-04");
......@@ -76,7 +77,6 @@ var oatForm = function(options)
var height = workspace.offsetHeight;
var width = workspace.offsetWidth;
DEBUG = options.debug != null ? options.debug : false;
workspace.innerHTML = getStartHTML();
var theForm = document.getElementById(theFormId);
......@@ -105,13 +105,13 @@ var submitForm = function()
var dateOfSowingLimit = moment(thisYear + "-07-01","YYYY-MM-DD");
if(getDateOfSowing().isAfter(dateOfSowingLimit))
{
alert("Saadato er etter 1. juli. Dette stemmer antakelig ikke. Ingen beregninger er foretatt.");
alert("Sådato er etter 1. juli. Dette stemmer antakelig ikke. Ingen beregninger er foretatt.");
return;
}
var theForm = document.getElementById(theFormId);
if(theForm.weatherStationId.options[theForm.weatherStationId.selectedIndex].value <= 0)
{
alert("Vennligst velg klimastasjon");
alert("Vennligst velg værstasjon");
return;
}
// See if test input now is set
......@@ -121,7 +121,9 @@ var submitForm = function()
}
// Erase previous results
displayResultHTML("");
document.getElementById("oatFloweringModelResults").style.display="none";
document.getElementById("progressIconRow").style.display="block";
document.getElementById("errorMsg").style.display="none";
// Start chain of async functions
createConfig();
......@@ -131,46 +133,82 @@ var submitForm = function()
/**
* Creates the configuration for weather data. Moves on to running model after data returns
*/
var createConfig = function(){
const createConfig = async function(){
var theForm = document.getElementById(theFormId);
var weatherStationId = theForm.weatherStationId.options[theForm.weatherStationId.selectedIndex].value;
var dateOfSowing = getDateOfSowing();
// Challenge: Get weather data asynchronously first....
//Tip: Use jQuery.stringify
//var theConfig =
var weatherDataUri = [weatherDataBaseUri,
"?startDate=", dateOfSowing.format("YYYY-MM-DD"),
(DEBUG ? "&today=" + now.format("YYYY-MM-DD") : ""),
"&weatherStationId=", weatherStationId//,
//"&callback=?"
].join("");
const theForm = document.getElementById(theFormId);
const weatherStationId = theForm.weatherStationId.options[theForm.weatherStationId.selectedIndex].value;
const dateOfSowing = getDateOfSowing();
const normalDataRequestUri = LMTServicesBaseUri + "rest/vips/getdata/grovfornormal?" +
"elementMeasurementTypes[]=TM&timeZone=Europe/Oslo" +
"&weatherStationId=" + weatherStationId +
"&startDate=" + now.format("YYYY-MM-DD") +
"&endDate=" + now.year() + "-12-31"
var jqxhr = $.ajax( {
url:weatherDataUri,
dataType: "json"
})
.done(function(data, textStatus, jqXHR) {
runModel(data);
})
.fail(function( jqXHR, textStatus,errorThrown ) {
alert( "Request failed: " + errorThrown );
})
.always(function() {
//alert( "complete" );
})
;
const normalDataResponse = await fetch(normalDataRequestUri);
if(normalDataResponse.status != 200)
{
let errorMsg = await normalDataResponse.text();
if(normalDataResponse.status == 204)
{
errorMsg = "Ingen normaldata funnet for værstasjon med id=" + weatherStationId;
}
document.getElementById("errorMsg").innerHTML = errorMsg;
document.getElementById("errorMsg").style.display="block";
document.getElementById("progressIconRow").style.display="none";
return;
}
const normalData = await normalDataResponse.json();
normalData.sort(sortWeatherData)
const measuredDataRequestUri = document.getElementById("coordinates").checked?
OpenMeteoBaseUri + "?longitude=" + document.getElementById("longitude").value +
"&elementMeasurementTypes[]=TM&logIntervalId=2" +
"&latitude=" + document.getElementById("latitude").value +
"&timeZone=Europe/Oslo" +
"&startDate=" + dateOfSowing.format("YYYY-MM-DD") +
"&endDate=" + moment(now).add(10, "days").format("YYYY-MM-DD")
: LMTServicesBaseUri + "rest/vips/getdata/forecastfallback?"+
"elementMeasurementTypes[]=TM&logInterval=1d" +
"&weatherStationId=" + weatherStationId +
"&timeZone=Europe/Oslo" +
"&startDate=" + dateOfSowing.format("YYYY-MM-DD") + "&startTime=00" +
"&endDate=" + moment(now).add(10, "days").format("YYYY-MM-DD") + "&endTime=00";
const measuredDataResponse = await fetch(measuredDataRequestUri);
if(measuredDataResponse.status != 200)
{
let errorMsg = await measuredDataResponse.text();
if(measuredDataResponse.status == 204)
{
errorMsg = "Ingen værdata funnet for valgt kilde";
}
document.getElementById("errorMsg").innerHTML = errorMsg;
document.getElementById("errorMsg").style.display="block";
document.getElementById("progressIconRow").style.display="none";
return;
}
const measuredData = await measuredDataResponse.json();
// Combine data. Normal data has lowest priority
measuredData.sort(sortWeatherData);
const maxMeasuredDataTimestamp = moment(measuredData[measuredData.length-1].timeMeasured);
const mergedData = measuredData.concat(normalData.filter((obs) => moment(obs.timeMeasured) > maxMeasuredDataTimestamp));
//console.info(mergedData);
runModel(mergedData);
};
function sortWeatherData(a,b)
{
return moment(a.timeMeasured).unix()- moment(b.timeMeasured).unix() ;
}
/**
* Calls the oatFlowering model in the VIPS forecasting system
* Displays data when results are returned
*/
var runModel = function(data)
const runModel = async function(data)
{
//console.log("runModel");
var dateOfSowing = getDateOfSowing();
......@@ -186,32 +224,31 @@ var runModel = function(data)
"observations": data
}
};
const modelResponse = await fetch(runUri, {
method: "POST",
body: JSON.stringify(modelConfig),
headers: {
"Content-Type": "application/json",
}
});
//console.log(data);
var request = $.ajax({
type:"POST",
url: runUri,
data: JSON.stringify(modelConfig),
dataType: "json",
contentType: "application/json; charset=utf-8",
})
.done(function(data, textStatus, jqXHR) {
displayResults(data);
})
.fail(function( jqXHR, textStatus,errorThrown ) {
alert( "Request failed: " + errorThrown );
})
.always(function() {
//alert( "complete" );
})
;
if(modelResponse.status == 200)
{
displayResults(await modelResponse.json());
}
else
{
document.getElementById("errorMsg").innerHTML = "En feil har oppstått: " + await modelResponse.text();
document.getElementById("errorMsg").style.display="block";
document.getElementById("progressIconRow").style.display="none";
return;
}
}
/**
* Analyze and display results from the OatFlowering model in VIPS
*/
var displayResults = function(data)
const displayResults = function(data)
{
// getting the dates
var dateOfSowing = getDateOfSowing();
......@@ -231,6 +268,7 @@ var displayResults = function(data)
console.log("z62.5: " + getDateForZ(data,62.5).tz("Europe/Oslo").format());
console.log("z69: " + dateZ69.tz("Europe/Oslo").format());
*/
// Scenario 1: Today is before date of sowing
if(now.isBefore(dateOfSowing))
{
......@@ -312,7 +350,10 @@ var getRawResults = function(data)
*/
var displayResultHTML = function(text)
{
document.getElementById("oatFloweringModelResults").innerHTML= "<h2>Resultater</h2>" + text;
document.getElementById("progressIconRow").style.display="none";
document.getElementById("oatFloweringModelResults").style.display="block";
}
/**
......@@ -372,34 +413,6 @@ function getNow()
else return now;
}
/**
* @return the HTML for the form
*/
var getStartHTML = function()
{
return [
"<form id='",theFormId,"' role='form'>",
"<div class='form-group'>",
"<label for='dateOfSowing'>S&aring;dato</label> ",
"<input class='form-control' type='date' name='dateOfSowing', value='",now.format("YYYY-MM-DD"),"'/><br/>",
"</div>",
(DEBUG ? "<div class='form-group'>" :""),
(DEBUG ? "<label for='now'>N&aring;dato </label>" : ""),
(DEBUG ? ["<input type='date' class='form-control' name='now' value='", now.format("YYYY-MM-DD"), "'/><br/>"].join("") : ""),
(DEBUG ? "</div>" :""),
"<div class='form-group'>",
"<label for='weatherStationId'>Målestasjon</label>",
"<select name='weatherStationId' class='form-control'>",
"<option value='-1'>-- Vennligst velg værstasjon --</option>",
"</select><br/>",
"<button type='button' class='btn btn-default' onclick='submitForm();'>Beregn</button>",
"</form>",
"</div>",
"<div id='resultsTable'></div>"
].join("");
}
var getAllValues = function(allValuesStr)
{
return JSON.parse(allValuesStr);
......
......@@ -3,17 +3,92 @@
{% block title%}{% trans "Oat flowering model" %}{%endblock%}
{% block extendCSS %}
{% endblock %}
{% block customCSS %}
<link type="text/css" rel="stylesheet" href="{{VIPSLOGIC_URL}}/css/3rdparty/leaflet.css" />
<link type="text/css" rel="stylesheet" href="{{VIPSLOGIC_URL}}/css/mapModal.css" />
{% endblock %}
{% block content %}
<div class="singleBlockContainer">
<h1>{% trans "Oat flowering model" %}</h1>
<p>
Her kan du beregne tidspunkt for n&aring;r havren er i blomst og dermed n&aring;r
en eventuell behandling med soppmiddel mot Fusarium m&aring; utf&oslash;res.
<a href='/forecasts/models/OATFLOWERM/' target='new'>Les mer</a>
</p>
<div id="oatFloweringModelForm" style="width:100%"></div>
<div id="oatFloweringModelResults" style="width:100%;"></div>
<div class="row">
<div class="col-md-12">
<h1>{% trans "Oat flowering model" %}</h1>
<p>
Her kan du beregne tidspunkt for n&aring;r havren er i blomst og dermed n&aring;r
en eventuell behandling med soppmiddel mot Fusarium m&aring; utf&oslash;res.
<a href='/forecasts/models/OATFLOWERM/' target='new'>Les mer</a>
</p>
</div>
</div>
<div class="row">
<div id="oatFloweringModelForm" style="width:100%">
<form id="_oatFloweringModelForm" role="form">
<div class="col-md-6">
<fieldset>
<legend>Værdata og prognoser</legend>
<div class="form-group">
<p>For værdata fram til nå og prognoser de nærmeste dagene fram i tid vil jeg bruke</p>
<div class="radio">
<div class="radio">
<label>
<input type="radio" name="weatherdataType" id="weatherstation" value="weatherstation" onchange="hideCoordinatesInput();storeUserSettings();">
data fra værstasjonen valgt for normaldata
</label>
</div>
<label>
<input type="radio" name="weatherdataType" id="coordinates" value="coordinates" onchange="displayCoordinatesInput();storeUserSettings();">
data for et spesifikt punkt (koordinater)
</label>
<div id="input-coordinates" class="form-inline" style="margin-top: 10px; display: none;">
<input type="hidden" class="form-control" name="latitude" id="latitude" placeholder="Breddegrad" aria-label="Breddegrad">
<input type="hidden" class="form-control" name="longitude" id="longitude" placeholder="Lengdegrad" aria-label="Lengdegrad">
<input type="hidden" class="form-control" name="timezone" id="timezone" placeholder="Tidssone" aria-label="Tidssone">
<div id="gridPointInfo"></div>
<button type="button" class="btn btn-primary" onclick="openCoordinatesMap();" style="margin-left: 5px;"><i class="fa fa-map-marker fa-lg"></i>&nbsp;&nbsp;{% trans "Select in map" %}</button>
</div>
<div id="coordinates-map" class="map-modal"></div>
</div>
</div>
</fieldset>
</div>
<div class="col-md-6">
<fieldset>
<legend>Normaldata</legend>
<div class="form-group form-inline">
<p>Brukes for beregning når tidspunkt for blomstring er senere enn 10 dager fram i tid</p>
<select name="weatherStationId" id="weatherStationId" class="form-control">
<option value="-1">-- Vennligst velg værstasjon --</option>
</select><button type="button" class="btn btn-primary" onclick="openPoiMap()" style="margin-left: 5px;"><i class="fa fa-map-marker fa-lg"></i>&nbsp;&nbsp;{% trans "Select in map" %}</button>
</div>
</fieldset>
<fieldset>
<legend>Sådato</legend>
<div class="form-group">
<input class="form-control" type="date" id="dateOfSowing" name="dateOfSowing" style="width: 50%;"><br>
</div>
</fieldset>
<div class="form-group">
<button type="button" class="btn btn-primary" onclick="submitForm();storeUserSettings();">Beregn</button>
</div>
</form>
<div id="poi-map" class="map-modal"></div>
</div>
</div>
</div>
<div class="row" id="progressIconRow" style="margin-bottom: 10px; display: none;">
<div class="col-md-6">
<button type="button" class="btn btn-info" style="margin-left: 5px;"><i class="fa fa-hourglass-half fa-lg"></i>&nbsp;&nbsp;Vennligst vent...</button>
</div>
</div>
<div id="errorMsg" class="alert alert-danger" style="display: none;"></div>
<div id="oatFloweringModelResults" class="alert alert-success" role="alert" style="width:100%; display: none;"></div>
</div>
{% endblock %}
{% block extendJS%}
......@@ -25,18 +100,42 @@
<script type="text/javascript" src="{% static "js/3rdparty/modernizr_custom.js"%}"></script>
<script type="text/javascript" src="{% url "javascript-catalog" %}"></script>
<script type="text/javascript" src="{% url "views.settings_js" %}"></script>
<script type="text/javascript" src="{% static "js/util.js" %}"></script>
<script src="{% static "fusarium/js/oatFloweringModelForm.js" %}"></script>
<script type="text/javascript">
var weatherStations = [];
$(document).ready(function() {
$.getJSON("https://lmt.nibio.no/agrometbase/export/getNormalDataStationsJSON.php", function( json ) {
<script type="module">
import MapModal from "{{VIPSLOGIC_URL}}/js/mapModal.js";
const userSettingsFields = ["latitude","longitude","timezone","weatherStationId","dateOfSowing"];
const userSettingsRadios = ["weatherdataType"];
window.weatherStations = [];
window.weatherStationIds = [];
const inputLatitudeElement = document.getElementById("latitude");
const inputLongitudeElement = document.getElementById("longitude");
const selectWeatherstationElement = document.getElementById("weatherStationId");
window.onload = (event) => {
let userSettings = getLocalSettings(getNameSpaced("{{ form_id }}",userSettingsFields.concat(userSettingsRadios)), false);
fetch("https://lmt.nibio.no/agrometbase/export/getNormalDataStationsJSON.php")
.then(response => {
if(response.ok)
{
return response.json();
}
else
{
throw new Error("Network response was not OK." + response.text);
}
})
.then(json => {
weatherStations = json;
weatherStationIds = weatherStations.map(ws=>ws.weatherstation_id);
var formApp = new oatForm({
target:"oatFloweringModelForm",
weatherStations:weatherStations,
//coreUsername:"gamlevips",
//corePass:"gamlevips123"
coreUsername:"testuser",
corePass:"testpass",
debug : false
......@@ -46,7 +145,157 @@
if (!Modernizr.inputtypes.date) {
$('input[type=date]').datepicker({ dateFormat: 'yy-mm-dd' });
}
// Settings found, render form and run model
if(Object.keys(userSettings).length > 0)
{
userSettingsFields.forEach((fieldId) =>{
document.getElementById(fieldId).value = userSettings[`{{ form_id }}.${fieldId}`];
});
userSettingsRadios.forEach((radioName) => {
let radioValue = userSettings[`{{ form_id }}.${radioName}`];
document.getElementsByName(radioName).forEach((radioElement) => {
radioElement.checked = (radioElement.value == radioValue);
});
});
// Check that sowing date is in current year. If not: Update to current year
let dateOfSowingElement = document.getElementById("dateOfSowing");
let dateOfSowing = moment(dateOfSowingElement.value);
if(dateOfSowing.year() != moment().year())
{
dateOfSowing.year(moment().year());
dateOfSowingElement.value = dateOfSowing.format("YYYY-MM-DD");
}
if(document.getElementById("coordinates").checked)
{
displayCoordinatesInput();
getTimezoneForPoint(inputLatitudeElement.value, inputLongitudeElement.value);
}
}
});
});
};
window.displayCoordinatesInput = function () {
document.getElementById("coordinates").checked = true;
document.getElementById('input-coordinates').style.display="block";
}
window.hideCoordinatesInput = function () {
document.getElementById("weatherstation").checked = true;
document.getElementById('input-coordinates').style.display="none";
}
// Callback for coordinates map
function selectCoordinates(coordinatesData) {
const selectedLatitude = coordinatesData ? coordinatesData.latitude : undefined;
const selectedLongitude = coordinatesData ? coordinatesData.longitude : undefined;
if(selectedLatitude && selectedLongitude) {
inputLatitudeElement.value = selectedLatitude;
inputLongitudeElement.value = selectedLongitude;
}
getTimezoneForPoint(selectedLatitude, selectedLongitude);
storeUserSettings();
}
const getTimezoneForPoint = (latitude, longitude) => {
getLocationInformation(latitude, longitude).then(locationInfo => {
document.getElementById("timezone").value = locationInfo.timezone;
document.getElementById("gridPointInfo").innerHTML = `<b>{% trans "Location name" %}</b> ${locationInfo.location}<br>
<b>{% trans "Latitude" %}</b> ${locationInfo.latitude}<br>
<b>{% trans "Longitude" %}</b> ${locationInfo.longitude}<br>
<b>{% trans "Timezone" %}</b> ${locationInfo.timezone}`
});
}
let selectedPoint = null;
let selectedFeature = undefined;
window.openCoordinatesMap = () => {
if (inputLatitudeElement.value && inputLongitudeElement.value) {
selectedPoint = 1;
selectedFeature = {
"type": "FeatureCollection", "features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [parseFloat(inputLongitudeElement.value), parseFloat(inputLatitudeElement.value)]
},
"properties": {
"pointOfInterestId": selectedPoint,
}
}]
};
} else {
selectedPoint = undefined;
selectedFeature = undefined;
}
const isPoiMap = false; // Map should enable selection of coordinates (not pois)
const allowNewPoints = true; // User should be able to select new pois
const coordinatesMapInstance = new MapModal('coordinates-map', selectedFeature, 'nb', isPoiMap, allowNewPoints, selectCoordinates);
coordinatesMapInstance.openModal(selectedPoint);
}
function selectPoi(poiData)
{
const selectedId = poiData ? poiData.pointOfInterestId : undefined;
if (selectedId) {
const optionIndex = Array.from(selectWeatherstationElement.options).findIndex(option => option.value == selectedId);
if (optionIndex !== -1) {
selectWeatherstationElement.selectedIndex = optionIndex;
}
}
}
window.openPoiMap = () => {
fetch("https://lmt.nibio.no/services/rest/weatherstation/ipmdecisions", {
method: 'GET'
})
.then(response => response.json())
.then(geoJson => {
// FILTER with only Ids from the Cydia station list
let filteredFeatures = geoJson["features"]
.filter(feature => window.weatherStationIds.indexOf(feature.id) >= 0)
.map(feature => {
feature["properties"]["pointOfInterestName"] = feature["properties"]["name"];
feature["properties"]["pointOfInterestId"] = feature["id"];
feature["properties"]["pointOfInterestTypeId"] = 1; // Type = Weather station
return feature;
});
geoJson["features"] = filteredFeatures;
const isPoiMap = true; // Map should enable selection of pois
const allowNewPoints = false; // User should not be able to create new pois
const poiMapInstance = new MapModal('poi-map', geoJson, 'nb', isPoiMap, allowNewPoints, selectPoi);
const selectedPoiId = parseInt(selectWeatherstationElement.options[selectWeatherstationElement.selectedIndex].value);
poiMapInstance.openModal(selectedPoiId >= 0 ? selectedPoiId : null);
})
.catch(error => {
console.error('Unable to retrieve weatherstation geojson', error);
});
}
window.storeUserSettings = function() {
let userSettings = {};
userSettingsFields.forEach((fieldId) => {
userSettings[`{{ form_id }}.${fieldId}`] = document.getElementById(fieldId).value;
});
userSettingsRadios.forEach((radioName) => {
document.getElementsByName(radioName).forEach((radioElement) => {
if(radioElement.checked)
{
userSettings[`{{ form_id }}.${radioName}`] = radioElement.value;
}
});
});
storeLocalSettings(userSettings);
}
</script>
{% endblock %}
......@@ -19,10 +19,13 @@
#
#
from django.shortcuts import render
from django.conf import settings
# Create your views here.
def index(request):
context = {}
context = {
"VIPSLOGIC_URL" : f"{settings.VIPSLOGIC_PROTOCOL}://{settings.VIPSLOGIC_SERVER_NAME}",
"form_id": "oatFloweringForm"
}
return render(request, 'fusarium/oat_flowering.html', context)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment