1
0
Fork 0

Phi: Initial draft for plugins and instruments

Gauge with ticks
This commit is contained in:
Torsten Dreyer 2015-03-20 12:02:12 +01:00
parent 62b7946a0a
commit a9bd141153
7 changed files with 255 additions and 21 deletions

View 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
};
});

View 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

View file

@ -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) {

View file

@ -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>

View file

@ -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);
}, },

View file

@ -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);
} }

View file

@ -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);
} }