1
0
Fork 0
fgdata/Phi/topics/Environment/Weather2.js
Torsten Dreyer 5d78ffa668 Phi: tweaking the weather diagram
- render actual cloud layers instead of dummy values
2015-04-23 09:27:39 +02:00

423 lines
15 KiB
JavaScript

define([
'knockout', 'jquery', 'text!./Weather2.html', 'props', 'flot', 'flotresize'
], function(ko, jquery, htmlString, SGPropertyNode) {
if (typeof Math.roundTo === "undefined") {
Math.roundTo = function(num, step) {
return Math.floor((num / step) + .5) * step;
}
}
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;
}
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());
});
jquery.get('/json/environment/clouds?d=4', null, function(data) {
var clouds = new SGPropertyNode(data);
function createClouds() {
var reply = [];
clouds.getChildren("layer").forEach(function(layer) {
var coverage = layer.getValue("coverage");
if( coverage == "clear" ) return;
var base = layer.getValue("elevation-ft", -9999 );
if( base < -9000 ) return;
var tops = base + layer.getValue("thickness-ft",0) + base;
if( tops == base ) return;
base *= 0.3048/1000;
tops *= 0.3048/1000;
reply.push( [reply.length, tops, base] );
});
return reply;
}
self.wxData()[2].data = createClouds();
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
xaxis : 1,
}, {// 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,
xaxis : 1,
}, { // clouds
color : 'rgb(128,128,128)',
data : [],
label : 'clouds',
lines : {
show : false
},
bars : {
show : true,
lineWidth : 0,
barWidth : 1,
fillColor : {
colors : [
{
opacity : 0.2
}, {
opacity : 0.9
}
]
}
},
shadowSize : 2,
yaxis : 2,
xaxis : 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,
xaxis : 1,
}, { // dewpoint
color : 'rgb(0, 255, 0)',
data : [],
label : "dewpoint",
lines : {
lineWidth : 2,
show : true
},
points : {
show : true
},
bars : {
show : false
},
shadowSize : 0,
yaxis : 2,
xaxis : 1,
}, {
color : 'rgb(0, 255, 0)',
data : [],
label : "windarrows",
lines : {
show : false
},
points : {
show : false
},
bars : {
show : false
},
windarrows : {
show : true,
},
shadowSize : 0,
yaxis : 2,
xaxis : 1,
}
]);
self.wxOptions = {
legend : {
show : false,
},
xaxes : [
{ // Axis 1: Temperature
show : true,
position : "bottom",
color : 'blue',
tickColor : 'green',
min : -56,
max : 50,
tickLength : 0,
}, { // Axis 2: Cloud Layer
show : false,
min : 0,
max : 5,
},
],
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 = Math.roundTo(points[i], 5), 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
};
});