1
0
Fork 0
fgdata/webgui/topics/Aircraft/MassBalance.js
2015-02-13 16:27:56 +01:00

422 lines
14 KiB
JavaScript

define([
'jquery', 'knockout', 'text!./MassBalance.html', 'flot', 'kojqui/slider',
], function(jquery, ko, htmlString) {
ko.bindingHandlers.flotchart = {
init : function(element, valueAccessor, allBindings) {
// This will be called when the binding is first applied to an
// element
// Set up any initial state, event handlers, etc. here
var value = valueAccessor() || {};
var plot = jquery.plot(element, []);
ko.utils.domData.set(element, "flotchart-plot", plot);
if (value.hover && typeof (value.hover) === 'function') {
$(element).bind("plothover", function(event, pos, item) {
value.hover(pos, item);
});
}
if (ko.isObservable(value.options)) {
value.options.subscribe(function(newValue) {
var element = this;
// options changed - start with a new plot, reuse data
var plot = ko.utils.domData.get(element, "flotchart-plot");
plot = jquery.plot(element, plot.getData(), newValue);
ko.utils.domData.set(element, "flotchart-plot", plot);
}, element);
}
if (ko.isObservable(value.data)) {
value.data.subscribe(function(newValue) {
var element = this;
var plot = ko.utils.domData.get(element, "flotchart-plot");
plot.setData(newValue);
// TODO: setupGrid not always required
plot.setupGrid();
plot.draw();
}, element);
}
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
// This will be called when the element is removed by Knockout
// or
// if some other part of your code calls ko.removeNode(element)
var plot = ko.utils.domData.set(element, "flotchart-plot", null);
// TODO: unsubscribe from data and options observables!!
});
},
};
function ViewModel(params) {
var self = this;
var Series = {
ENVELOPE : 0,
PAYLOAD : 1,
FUEL : 2,
CG : 3
}
self.envelopeData = ko.observableArray([
// Series 0: Envelope
{
color : 'rgb(192, 128, 0)',
data : [],
label : "Envelope",
lines : {
show : true
},
points : {
show : false
},
bars : {
show : false
},
shadowSize : 0,
},
// Series 1: Payload
{
color : 'rgb(0, 0, 255)',
data : [],
label : "Payload",
lines : {
show : true
},
points : {
show : true
},
bars : {
show : false
},
},
// Series 2: Fuel
{
color : 'rgb(0, 255, 0)',
data : [],
label : "Fuel",
lines : {
show : true
},
points : {
show : true
},
bars : {
show : false
},
},
// Series 3: CG
{
color : 'rgb(255, 0, 0)',
data : [],
label : "CG",
lines : {
show : false
},
points : {
show : true
},
bars : {
show : false
},
},
]);
self.hover = function(pos, item) {
if( ! item ) {
self.hoverLabel("");
self.hoverMass(0);
self.hoverCG(0);
return;
}
switch (item.seriesIndex) {
case Series.CG:
self.hoverLabel("CG");
break;
case Series.PAYLOAD:
self.hoverLabel("Load"); //self.loads()[item.dataIndex].name;
break;
case Series.FUEL:
self.hoverLabel("Fuel"); //self.tanks()[item.dataIndex].name;
break;
}
self.hoverCG(item.datapoint[0]);
self.hoverMass(item.datapoint[1]);
}
self.hoverLabel = ko.observable();
self.hoverMass = ko.observable(0);
self.hoverCG = ko.observable(0);
self.envelopeOptions = ko.observable({
legend : {
show : false,
},
grid : {
hoverable : true,
}
});
self.tanks = ko.observableArray([]);
self.loads = ko.observableArray([]);
self.cglimits = ko.observableArray([]);
self.weight = ko.observable(0).extend({
fgprop : 'weight'
});
self.cg = ko.observable(0).extend({
fgprop : 'cg'
});
self.currentCG = ko.computed(function() {
return [
self.cg(), self.weight()
];
}).extend({
rateLimit : 1000
});
self.currentCG.subscribe(function(newValue) {
var data = self.envelopeData();
var p = newValue;
data[Series.CG].data = [
p
];
var fuelSeriesData = [
p
];
var moment = newValue[0] * newValue[1];
var mass = newValue[1];
self.tanks().forEach(function(tank) {
moment -= tank.moment();
mass -= tank.mass();
p = [
moment / mass, mass
];
fuelSeriesData.push(p);
});
data[Series.FUEL].data = fuelSeriesData;
var payloadSeriesData = [
p
];
self.loads().forEach(function(load) {
moment -= load.moment();
mass -= load.mass();
p = [
moment / mass, mass
];
payloadSeriesData.push(p);
});
data[Series.PAYLOAD].data = payloadSeriesData;
self.envelopeData(data);
});
self.cglimits.subscribe(function(newValue) {
var bounds = {
xMin : Number.MAX_VALUE,
xMax : Number.MIN_VALUE,
yMin : Number.MAX_VALUE,
yMax : Number.MIN_VALUE,
};
var envelope = [];
self.cglimits().forEach(function(entry) {
envelope.push([
entry.position, entry.mass
]);
if (entry.mass < this.yMin)
this.yMin = entry.mass;
if (entry.mass > this.yMax)
this.yMax = entry.mass;
if (entry.position < this.xMin)
this.xMin = entry.position;
if (entry.position > this.xMax)
this.xMax = entry.position;
}, bounds);
if (envelope.length > 0)
envelope.push(envelope[0]);
var options = self.envelopeOptions() || {};
options.xaxis = options.xaxis || {};
options.yaxis = options.yaxis || {};
options.xaxis.min = bounds.xMin;
options.xaxis.max = bounds.xMax;
options.yaxis.min = bounds.yMin;
options.yaxis.max = bounds.yMax;
self.envelopeOptions(options);
var ed = self.envelopeData();
ed[0].data = envelope;
self.envelopeData(ed);
});
var WeightViewModel = function(number) {
var self = this;
self.number = number;
self.name = 'Load' + number.toString();
self.arm = ko.observable(1);
self.mass = ko.observable(0);
self.min = 0;
self.max = 0;
self.moment = ko.pureComputed(function() {
return self.mass() * self.arm();
});
self.setLoad = function() {
jquery.post('/json/payload/weight[' + this.number + ']', JSON.stringify({
name : 'weight-lb',
value : this.mass()
}));
}
}
jquery.get('/json/payload?d=2', null, function(data) {
var assemble = function(data) {
var loads = [];
data.children.forEach(function(prop) {
if (prop.name === 'weight') {
var weight = new WeightViewModel(loads.length);
loads.push(weight);
prop.children.forEach(function(prop) {
if (prop.name === 'name') {
weight.name = prop.value;
} else if (prop.name === 'weight-lb') {
weight.mass(Number(prop.value));
} else if (prop.name == 'min-lb') {
weight.min = Number(prop.value);
} else if (prop.name == 'max-lb') {
weight.max = Number(prop.value);
} else if (prop.name == 'arm-in') {
weight.arm(Number(prop.value));
}
});
}
});
return loads;
}
self.loads(assemble(data));
});
jquery.get('/json/limits/mass-and-balance/cg/limit?d=2', null, function(data) {
var assemble = function(data) {
var cgLimits = [];
data.children.forEach(function(prop) {
if (prop.name === 'entry') {
var entry = {
position : 0,
mass : 0
};
cgLimits.push(entry);
prop.children.forEach(function(prop) {
if (prop.name === 'position') {
entry.position = Number(prop.value);
} else if (prop.name == 'mass-lbs') {
entry.mass = Number(prop.value);
}
});
}
});
return cgLimits;
}
self.cglimits(assemble(data));
});
var TankViewModel = function(number) {
var self = this;
self.name = 'Tank' + number.toString();
self.number = number;
self.capacity = 0;
self.content = ko.observable(0);
self.arm = ko.observable(1);
self.density = ko.observable(0);
self.hidden = false;
self.mass = ko.pureComputed(function() {
return self.content() * self.density();
});
self.moment = ko.pureComputed(function() {
return self.mass() * self.arm();
});
self.setTankLevel = function() {
jquery.post('/json/consumables/fuel/tank[' + this.number + ']', JSON.stringify({
name : 'level-gal_us',
value : this.content()
}));
}
}
jquery.get('/json/consumables/fuel?d=2', null, function(data) {
var assemble = function(data) {
var tanks = [];
data.children.forEach(function(prop) {
if (prop.name === 'tank') {
var tank = new TankViewModel(tanks.length);
tanks.push(tank);
prop.children.forEach(function(prop) {
if (prop.name === 'name') {
tank.name = prop.value;
} else if (prop.name == 'capacity-gal_us') {
tank.capacity = Number(prop.value);
} else if (prop.name == 'density-ppg') {
tank.density(Number(prop.value));
} else if (prop.name == 'level-gal_us') {
tank.content(Number(prop.value));
} else if (prop.name == 'arm-in') {
tank.arm(Number(prop.value));
} else if (prop.name == 'hidden') {
tank.hidden = prop.value !== 'false';
}
});
}
});
return tanks;
}
self.tanks(assemble(data));
});
}
ViewModel.prototype.dispose = function() {
}
// Return component definition
return {
viewModel : ViewModel,
template : htmlString
};
});