Phi: Initial draft for plugins and instruments
Gauge with ticks
This commit is contained in:
parent
62b7946a0a
commit
a9bd141153
7 changed files with 255 additions and 21 deletions
126
webgui/instruments/DualArcGauge.js
Normal file
126
webgui/instruments/DualArcGauge.js
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
define([
|
||||||
|
'jquery', 'knockout', 'text!./DualArcGauge.svg', 'sprintf'
|
||||||
|
], function(jquery, ko, svgString, sprintf) {
|
||||||
|
|
||||||
|
function getXY(positionNorm, r) {
|
||||||
|
var a = (120*positionNorm-60)/180*Math.PI;
|
||||||
|
return {
|
||||||
|
'x': 50+r*Math.sin(a),
|
||||||
|
'y': 52-r*Math.cos(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Tick( width, positionNorm, color ) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.width = width;
|
||||||
|
self.color = color;
|
||||||
|
|
||||||
|
var xy = getXY( positionNorm, 45 );
|
||||||
|
self.getStartXY = xy.x.toString()+","+ xy.y.toString();
|
||||||
|
|
||||||
|
xy = getXY( positionNorm, 50 );
|
||||||
|
self.getEndXY = xy.x.toString()+","+ xy.y.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function Marker( label, positionNorm, color ) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.label = label;
|
||||||
|
self.color = color;
|
||||||
|
|
||||||
|
var xy = getXY( positionNorm, 52 );
|
||||||
|
self.getX = xy.x;
|
||||||
|
self.getY = xy.y;
|
||||||
|
|
||||||
|
self.anchor = 'middle';
|
||||||
|
if( positionNorm < 0.4 ) self.anchor = 'end';
|
||||||
|
if( positionNorm > 0.6 ) self.anchor = 'start';
|
||||||
|
}
|
||||||
|
|
||||||
|
function Arc( color, start, end ) {
|
||||||
|
var self = this;
|
||||||
|
self.color = color;
|
||||||
|
|
||||||
|
if( start == end ) {
|
||||||
|
start -= 0.005;
|
||||||
|
end += 0.005;
|
||||||
|
}
|
||||||
|
|
||||||
|
var xy = getXY( start, 47.5 );
|
||||||
|
self.getStartXY = xy.x.toString()+","+ xy.y.toString();
|
||||||
|
|
||||||
|
xy = getXY( end, 47.5 );
|
||||||
|
self.getEndXY = xy.x.toString()+","+ xy.y.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ViewModel(params) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.config = {
|
||||||
|
label : params.label || '',
|
||||||
|
min : params.min || 0,
|
||||||
|
max : params.max || 1,
|
||||||
|
left : {
|
||||||
|
value : params.left.value || 0,
|
||||||
|
format : params.left.format || '%d',
|
||||||
|
},
|
||||||
|
right : {
|
||||||
|
value : params.right.value || 0,
|
||||||
|
format : params.right.format || '%d',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRotationNorm(value) {
|
||||||
|
if (value < self.config.min)
|
||||||
|
return 0;
|
||||||
|
if (value > self.config.max)
|
||||||
|
return 1;
|
||||||
|
return (value - self.config.min) / (self.config.max - self.config.min);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.leftRotationNorm = ko.pureComputed(function() {
|
||||||
|
return getRotationNorm(ko.utils.unwrapObservable(self.config.left.value));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.rightRotationNorm = ko.pureComputed(function() {
|
||||||
|
return getRotationNorm(ko.utils.unwrapObservable(self.config.right.value));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.leftText = ko.pureComputed(function() {
|
||||||
|
return sprintf.sprintf(self.config.left.format, ko.utils.unwrapObservable(self.config.left.value));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.rightText = ko.pureComputed(function() {
|
||||||
|
return sprintf.sprintf(self.config.right.format, ko.utils.unwrapObservable(self.config.right.value));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.label = self.config.label;
|
||||||
|
|
||||||
|
self.markers = [];
|
||||||
|
self.ticks = [];
|
||||||
|
self.arcs = [];
|
||||||
|
|
||||||
|
for ( var pos in params.marker) {
|
||||||
|
var m = params.marker[pos];
|
||||||
|
self.markers.push( new Marker( pos, getRotationNorm(Number(pos)), m) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( var pos in params.ticks) {
|
||||||
|
var t = params.ticks[pos];
|
||||||
|
self.ticks.push( new Tick( t.width || 1, getRotationNorm(Number(pos)), t.color || 'white' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( params.arcs ) params.arcs.forEach(function(arc) {
|
||||||
|
var end = arc.end || arc.start;
|
||||||
|
self.arcs.push( new Arc(arc.color,getRotationNorm(Number(arc.start)),getRotationNorm(Number(end))));
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return component definition
|
||||||
|
return {
|
||||||
|
viewModel : ViewModel,
|
||||||
|
template : svgString
|
||||||
|
};
|
||||||
|
});
|
62
webgui/instruments/DualArcGauge.svg
Normal file
62
webgui/instruments/DualArcGauge.svg
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<!-- don't add the xml-declaration here -->
|
||||||
|
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" class="dualarcgauge"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" viewBox="-10 -10 120 55"
|
||||||
|
preserveAspectRatio="xMinYMin meet">
|
||||||
|
|
||||||
|
<text class="dualarcgauge-label" x="50" y="35" stroke="black"
|
||||||
|
font-size="5" text-anchor="middle" data-bind="text: label"></text>
|
||||||
|
|
||||||
|
<g data-bind="foreach: markers">
|
||||||
|
<text class="dualarcgauge-marker"
|
||||||
|
data-bind="attr: { x: getX, y: getY, 'text-anchor': anchor, 'fill': color }, text: label"
|
||||||
|
font-size="5"></text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g data-bind="foreach: arcs">
|
||||||
|
<path class="dualarcgauge-scale-arc" stroke-linecap="butt"
|
||||||
|
data-bind="attr: { stroke: color, d: 'M' + getStartXY + ' A 47.5 47.5 0 0 1 ' + getEndXY }"
|
||||||
|
stroke-width="5" fill="none" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g data-bind="foreach: ticks">
|
||||||
|
<path class="dualarcgauge-scale-tick" stroke-linecap="butt"
|
||||||
|
data-bind="attr: { stroke: color, 'stroke-width': width, d: 'M' + getStartXY + ' L ' + getEndXY }" fill="none" />
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Scale Outline -->
|
||||||
|
<path class="dualarcgauge-scale-stroke"
|
||||||
|
d="M11,29.5 a 45,45 0 0 1 78,0 L93.3,27 A 50,50 0 0 0 6.7,27 z"
|
||||||
|
stroke="black" stroke-width="0.5" fill="none" />
|
||||||
|
|
||||||
|
<!-- Needle 1 -->
|
||||||
|
<g
|
||||||
|
data-bind="attr { transform: 'rotate('+ (rightRotationNorm()*120-60) +',50,52)' }">
|
||||||
|
<path d="M45,25 l4.5,-8.66 v-10 h1 v10 l4.5,8.66z" stroke="black"
|
||||||
|
stroke-width="0.5" fill="white" />
|
||||||
|
<text x="50" y="23.7" stroke="none" fill="black" font-size="6"
|
||||||
|
text-anchor="middle">R</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Needle 2 -->
|
||||||
|
<g
|
||||||
|
data-bind="attr { transform: 'rotate('+ (leftRotationNorm()*120-60) +',50,52)' }">
|
||||||
|
<path d="M45,16 l5,-8.66 l5,8.66z" stroke="black" stroke-width="0.5"
|
||||||
|
fill="white" />
|
||||||
|
<text x="50" y="14.7" stroke="none" fill="black" font-size="6"
|
||||||
|
text-anchor="middle">L</text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Left Label -->
|
||||||
|
<g class="dualarcgauge-value">
|
||||||
|
<rect x="-9" y="-9" width="20" height="10" rx="2" ry="2" />
|
||||||
|
<text x="10" y="-1" stroke="black" font-size="8" text-anchor="end"
|
||||||
|
data-bind="text: leftText"></text>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<!-- Right Label -->
|
||||||
|
<g class="dualarcgauge-value">
|
||||||
|
<rect x="89" y="-9" width="20" height="10" rx="2" ry="2" />
|
||||||
|
<text x="108" y="-1" stroke="black" font-size="8" text-anchor="end"
|
||||||
|
data-bind="text: rightText"></text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
|
@ -13,7 +13,8 @@ require.config({
|
||||||
flottime : '3rdparty/flot/jquery.flot.time',
|
flottime : '3rdparty/flot/jquery.flot.time',
|
||||||
fgcommand : 'lib/fgcommand',
|
fgcommand : 'lib/fgcommand',
|
||||||
props : 'lib/props2',
|
props : 'lib/props2',
|
||||||
sammy: '3rdparty/sammy-latest.min'
|
sammy: '3rdparty/sammy-latest.min',
|
||||||
|
aircraft: '../aircraft-dir',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -135,6 +136,14 @@ require([
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
koObservable.fgPropertyPath = path;
|
||||||
|
koObservable.fgBaseDispose = koObservable.dispose;
|
||||||
|
koObservable.dispose = function() {
|
||||||
|
if( this.fgPropertyPath ) {
|
||||||
|
self.removeListener( this.fgPropertyPath, this );
|
||||||
|
}
|
||||||
|
this.fgBaseDispose.call(this);
|
||||||
|
}
|
||||||
listeners.push(koObservable);
|
listeners.push(koObservable);
|
||||||
|
|
||||||
if (1 == listeners.length) {
|
if (1 == listeners.length) {
|
||||||
|
@ -165,19 +174,21 @@ require([
|
||||||
return self.props[prop];
|
return self.props[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
var p = (self.props[prop] = ko.pureComputed({
|
return (self.props[prop] = self.observedProperty( target, prop ));
|
||||||
read : target,
|
}
|
||||||
write : function(newValue) {
|
|
||||||
if (newValue == target())
|
self.observedProperty = function( target, prop ) {
|
||||||
|
var reply = ko.pureComputed({
|
||||||
|
read: target,
|
||||||
|
write: function(newValue) {
|
||||||
|
if( newValue == target() )
|
||||||
return;
|
return;
|
||||||
target(newValue);
|
target(newValue);
|
||||||
target.notifySubscribers(newValue);
|
target.notifySubscribers(newValue);
|
||||||
}
|
}
|
||||||
}));
|
});
|
||||||
|
self.addListener(prop, reply);
|
||||||
self.addListener(prop, p);
|
return reply;
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write = function(prop, value) {
|
self.write = function(prop, value) {
|
||||||
|
@ -186,6 +197,11 @@ require([
|
||||||
console.log("can't write " + prop + ": unknown alias.");
|
console.log("can't write " + prop + ": unknown alias.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.setPropertyValue(path,value);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.setPropertyValue = function(path, value) {
|
||||||
this.ws.send(JSON.stringify({
|
this.ws.send(JSON.stringify({
|
||||||
command : 'set',
|
command : 'set',
|
||||||
node : path,
|
node : path,
|
||||||
|
@ -212,6 +228,10 @@ require([
|
||||||
ko.extenders.fgprop = function(target, prop) {
|
ko.extenders.fgprop = function(target, prop) {
|
||||||
return ko.utils.knockprops.get(target, prop);
|
return ko.utils.knockprops.get(target, prop);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ko.extenders.observedProperty = function(target,prop) {
|
||||||
|
return ko.utils.knockprops.observedProperty(target,prop);
|
||||||
|
};
|
||||||
|
|
||||||
ko.extenders.fgPropertyGetSet = function(target,option) {
|
ko.extenders.fgPropertyGetSet = function(target,option) {
|
||||||
|
|
||||||
|
@ -440,6 +460,10 @@ require([
|
||||||
ko.components.register('Stopwatch', {
|
ko.components.register('Stopwatch', {
|
||||||
require : 'widgets/Stopwatch'
|
require : 'widgets/Stopwatch'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ko.components.register('dualarcgauge', {
|
||||||
|
require: 'instruments/DualArcGauge'
|
||||||
|
})
|
||||||
|
|
||||||
ko.bindingHandlers.flotchart = {
|
ko.bindingHandlers.flotchart = {
|
||||||
init : function(element, valueAccessor, allBindings) {
|
init : function(element, valueAccessor, allBindings) {
|
||||||
|
|
|
@ -9,4 +9,5 @@
|
||||||
click: $parent.selectTopic"></li>
|
click: $parent.selectTopic"></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id="vtabs-content" data-bind="component: { name: selectedComponent }"></div>
|
<div id="vtabs-content" data-bind="component: { name: selectedComponent }">
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
define([
|
define([
|
||||||
'knockout', 'text!./Aircraft.html', './SubtopicViewmodel'
|
'jquery', 'knockout', 'text!./Aircraft.html', './SubtopicViewmodel'
|
||||||
], function(ko, htmlString, SubtopicViewmodel) {
|
], function(jquery, ko, htmlString, SubtopicViewmodel) {
|
||||||
ko.components.register('Aircraft/Select', {
|
ko.components.register('Aircraft/Select', {
|
||||||
require : 'topics/Aircraft/Select'
|
require : 'topics/Aircraft/Select'
|
||||||
});
|
});
|
||||||
|
@ -21,11 +21,34 @@ define([
|
||||||
require : 'topics/Aircraft/Panel'
|
require : 'topics/Aircraft/Panel'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function Viewmodel(topics, prefix, params) {
|
||||||
|
var self = this;
|
||||||
|
SubtopicViewmodel.call(self, topics, prefix, params);
|
||||||
|
|
||||||
|
self.config = ko.observable({});
|
||||||
|
|
||||||
|
jquery.get('/aircraft-dir/Phi/config.json', null, function(config) {
|
||||||
|
self.config(config);
|
||||||
|
|
||||||
|
if (config && config.plugins && config.plugins.Aircraft) {
|
||||||
|
for ( var p in config.plugins.Aircraft) {
|
||||||
|
var plugin = config.plugins.Aircraft[p];
|
||||||
|
if (plugin.component && plugin.component.key && plugin.component.lib) {
|
||||||
|
if (false == ko.components.isRegistered(plugin.component.key)) {
|
||||||
|
ko.components.register(plugin.component.key, { require: plugin.component.lib });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.topics.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Return component definition
|
// Return component definition
|
||||||
return {
|
return {
|
||||||
viewModel : {
|
viewModel : {
|
||||||
createViewModel : function(params, componentInfo) {
|
createViewModel : function(params, componentInfo) {
|
||||||
return new SubtopicViewmodel([
|
return new Viewmodel([
|
||||||
'Help', 'Mass & Balance', 'Checklists', 'Failures', 'Panel', 'Select'
|
'Help', 'Mass & Balance', 'Checklists', 'Failures', 'Panel', 'Select'
|
||||||
], "Aircraft", params);
|
], "Aircraft", params);
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
define([
|
define([
|
||||||
'jquery', 'knockout', 'text!./Screenshot.html', 'kojqui/spinner'
|
'jquery', 'knockout', 'text!./Screenshot.html', 'kojqui/spinner'
|
||||||
], function(jquery, ko, htmlString, fgcommand ) {
|
], function(jquery, ko, htmlString ) {
|
||||||
|
|
||||||
function ViewModel(params) {
|
function ViewModel(params) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -18,11 +18,9 @@ define([
|
||||||
if( id != self.updateId )
|
if( id != self.updateId )
|
||||||
return;
|
return;
|
||||||
self.imageUrl("/screenshot?type=jpg&t=" + Date.now());
|
self.imageUrl("/screenshot?type=jpg&t=" + Date.now());
|
||||||
console.log(self.updateInterval(), self.imageUrl());
|
|
||||||
|
|
||||||
setTimeout( function() { self.update(id); }, self.updateInterval()*1000);
|
setTimeout( function() { self.update(id); }, self.updateInterval()*1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.update(++self.updateId);
|
self.update(++self.updateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
function SubtopicViewModel(topics, prefix, params) {
|
function SubtopicViewModel(topics, prefix, params) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self.topics = topics;
|
self.topics = ko.observableArray(topics);
|
||||||
|
|
||||||
self.selectedTopic = ko.observable();
|
self.selectedTopic = ko.observable();
|
||||||
|
|
||||||
|
@ -24,9 +24,9 @@
|
||||||
self.selectedTopic(topic);
|
self.selectedTopic(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
var topic = (params && params.topic) ? ko.unwrap(params.topic) : self.topics[0];
|
var topic = (params && params.topic) ? ko.unwrap(params.topic) : self.topics()[0];
|
||||||
if( self.topics.indexOf(topic) == -1 )
|
if( self.topics.indexOf(topic) == -1 )
|
||||||
topic = self.topics[0];
|
topic = self.topics()[0];
|
||||||
self.selectTopic(topic);
|
self.selectTopic(topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue