1
0
Fork 0
fgdata/Phi/topics/Environment/Weather2.js
Torsten Dreyer 304992be59 Phi: initial commit for experimental weather dialog
new manual weather configuration based on a
http://en.wikipedia.org/wiki/St%C3%BCve_diagram Stuve (Stüve) Diagram.
work in progress, up to now it's just displaying current weather, edits
are not yet written to fg.
2015-04-18 13:10:48 +02:00

396 lines
14 KiB
JavaScript

define([
'knockout', 'jquery', 'text!./Weather2.html', 'props', 'flot', 'flotresize'
], function(ko, jquery, htmlString, SGPropertyNode) {
function ViewModel(params, componentInfo) {
// componentInfo.element
var self = this;
function createIsotherms() {
var reply = [];
for (x = -50; x < 50; x += 10) {
reply.push([
x, -0.02
]);
reply.push([
x, 16
]);
reply.push(null);
}
/*
* for (x = -160; x < 50; x += 10) { reply.push([ x, -56 ]);
* reply.push([ x + 116, 50 ]); reply.push(null); }
*/
return reply;
}
function createDryAdiabates() {
var reply = [];
/*
* for (x = -35; x <= 200; x += 20) { reply.push([ x, 1050 ]);
* reply.push([ x-160, 100 ]); reply.push(null); }
*/
return reply;
}
function createClouds() {
var reply = [];
reply.push([
-50, 0.3, 0.
]);
reply.push([
-30, 3.0, 1.8
]);
reply.push([
-10, 5.0, 4
]);
reply.push([
10, 7.5, 4
]);
reply.push([
30, 12, 11.5
]);
return reply;
}
jquery.get('/json/environment/config?d=4', null, function(data) {
var wx = new SGPropertyNode(data);
function createProbes(k) {
var probes = [];
wx.getNode("boundary").getChildren("entry").forEach(function(entry) {
probes.push([
entry.getValue(k, 15), entry.getValue("elevation-ft", 0) * 0.3048 / 1000
// km
]);
});
wx.getNode("aloft").getChildren("entry").forEach(function(entry) {
probes.push([
entry.getValue(k, 15), entry.getValue("elevation-ft", 0) * 0.3048 / 1000
// km
]);
});
return probes;
}
function createWind() {
var wind = [];
wx.getNode("boundary").getChildren("entry").forEach(function(entry) {
wind.push([
entry.getValue("wind-speed-kt", 0), entry.getValue("elevation-ft", 0) * 0.3048 / 1000, // km
entry.getValue("wind-from-heading-deg", 0),
]);
});
wx.getNode("aloft").getChildren("entry").forEach(function(entry) {
wind.push([
entry.getValue("wind-speed-kt", 0), entry.getValue("elevation-ft", 0) * 0.3048 / 1000, // km
entry.getValue("wind-from-heading-deg", 0),
]);
});
return wind;
}
self.wxData()[3].data = createProbes("temperature-degc");
self.wxData()[4].data = createProbes("dewpoint-degc");
self.wxData()[5].data = createWind();
self.wxData.notifySubscribers(self.wxData.peek());
});
self.wxData = ko.observableArray([
{// Series: Isotherms
color : 'rgb(0, 0, 255)',
data : createIsotherms(),
label : "Isotherm",
lines : {
lineWidth : 0.5,
show : true
},
points : {
show : false
},
bars : {
show : false
},
shadowSize : 0,
yaxis : 2, // on linear scale
}, {// Series: Dry Adiabat
color : 'rgb(0, 255, 0)',
data : createDryAdiabates(),
label : "dry adiabat",
lines : {
lineWidth : 0.5,
show : true
},
points : {
show : true
},
bars : {
show : false
},
shadowSize : 0,
yaxis : 1,
}, { // clouds
color : 'rgb(128,128,128)',
data : createClouds(),
label : 'clouds',
lines : {
show : false
},
bars : {
show : true,
lineWidth : 0,
barWidth : 20,
fillColor : {
colors : [
{
opacity : 0.2
}, {
opacity : 0.9
}
]
}
},
shadowSize : 2,
yaxis : 2,
}, { // Temperature
color : 'rgb(255, 0, 0)',
data : [],
label : "temperature",
lines : {
lineWidth : 2,
show : true
},
points : {
show : true
},
bars : {
show : false
},
shadowSize : 0,
yaxis : 2,
}, { // dewpoint
color : 'rgb(0, 255, 0)',
data : [],
label : "dewpoint",
lines : {
lineWidth : 2,
show : true
},
points : {
show : true
},
bars : {
show : false
},
shadowSize : 0,
yaxis : 2,
}, {
color : 'rgb(0, 255, 0)',
data : [],
label : "windarrows",
lines : {
show : false
},
points : {
show : false
},
bars : {
show : false
},
windarrows : {
show : true,
},
shadowSize : 0,
yaxis : 2,
}
]);
self.wxOptions = {
legend : {
show : false,
},
xaxis : {
show : true,
position : "bottom",
color : 'blue',
tickColor : 'green',
min : -56,
max : 50,
tickLength : 0,
},
yaxes : [
{ // Axis 1: Pressure (hpa), Log-P
show : true,
position : "left",
color : 'blue',
tickColor : 'blue',
min : 100,
max : 1050,
// tickLength : 0,
transform : function(v) {
return -Math.log(v);
},
inverseTransform : function(v) {
return Math.exp(-v);
},
}, { // Axis 2: Altitude (km)
show : true,
position : "right",
color : 'black',
tickColor : 'green',
min : -.020,
max : 16,
tickLength : 0,
}
],
grid : {
hoverable : true,
clickable : true
},
hooks : {
processRawData : function(plot, series, data, datapoints) {
if (series.windarrows && series.windarrows.show) {
datapoints.format = [
{
x : true,
number : true,
required : true
}, {
y : true,
number : true,
required : true
}, {
number : true,
required : true
}
]
}
},
drawSeries : function(plot, ctx, series) {
if (series.windarrows && series.windarrows.show) {
function drawSeriesWindarrows(datapoints) {
var points = datapoints.points, ps = datapoints.pointsize;
for (var i = 0; i < points.length; i += ps) {
var ws = points[i], y = points[i+1], wd = points[i+2];
var x = series.xaxis.p2c(40);
y = series.yaxis.p2c(y);
ctx.save();
ctx.translate(x,y);
ctx.rotate((wd+180) * Math.PI/180);
ctx.beginPath();
ctx.arc(0,0, 3, 0, Math.PI * 2, false);
ctx.closePath();
ctx.moveTo(0,0);
ctx.lineTo(0,9*5);
var pos = 0;
while( ws >= 5 ) {
if( ws >= 50 ) {
ws -= 50;
ctx.moveTo(0,(9-pos)*5);
ctx.lineTo(-10,(8.5-pos)*5);
ctx.lineTo(0,(8-pos)*5);
pos++;
} else if( ws >= 10 ) {
if( pos > 0 ) pos++;
ws -= 10;
ctx.moveTo(0,(9-pos)*5);
ctx.lineTo(-10,(9.5-pos)*5);
} else {
pos++;
ws -= 5;
ctx.moveTo(0,(9-pos)*5);
ctx.lineTo(-5,(9.25-pos)*5);
}
}
ctx.stroke();
ctx.restore();
}
}
var plotOffset = plot.getPlotOffset();
ctx.save();
ctx.translate(plotOffset.left, plotOffset.top);
ctx.lineWidth = 1.5;
ctx.strokeStyle = 'black';
drawSeriesWindarrows(series.datapoints);
ctx.restore();
}
}
},
};
self.afterUpdate = function(element) {
var yaxisLabel = jquery("<div class='axisLabel yaxisLabel'></div>").text("Pressure (hpa)").appendTo(element);
// Since CSS transforms use the top-left corner of the label as the
// transform origin,
// we need to center the y-axis label by shifting it down by half
// its
// width.
// Subtract 20 to factor the chart's bottom margin into the
// centering.
yaxisLabel.css("margin-top", yaxisLabel.width() / 2 - 20);
}
var highlighted = null;
self.plotHover = function(pos, item) {
if (highlighted) {
self.wxData()[highlighted.seriesIndex].data[highlighted.dataIndex] = [
pos.x1, highlighted.datapoint[1]
];
this.setData(self.wxData());
this.draw();
}
}
self.plotClick = function(pos, item) {
if (highlighted) {
this.unhighlight(highlighted.series, highlighted.datapoint);
highlighted = null;
} else {
if (item && item.seriesIndex != 3 && item.seriesIndex != 4)
return;
highlighted = item;
if (highlighted)
this.highlight(highlighted.series, highlighted.datapoint);
}
}
}
ViewModel.prototype.dispose = function() {
}
// Return component definition
return {
viewModel : {
createViewModel : function(params, componentInfo) {
return new ViewModel(params, componentInfo);
},
},
template : htmlString
};
});