304992be59
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.
396 lines
14 KiB
JavaScript
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
|
|
};
|
|
});
|