Canvas Nasal/JavaScript Subset

From FlightGear wiki
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.
Note  If you're interested in helping with this, just get in touch with Hooray and TheTom.


Motivation

The Nasal/JavaScript subset approach discussed below is about refactoring existing Canvas MFDs (or the underlying framework) so that the corresponding Nasal code becomes a valid subset of JavaScript (and vice versa) - that's just an idea that we ended up discussing behind the scenes when Torsten began his Phi/MFD (browser-based) work, because he began duplicating functionality that already existed elsewhere. The main reason being that a Canvas is just a property tree - and most elements are just textures or SVG images. In other words, it would not be that far-fetched to come up with a really tiny wrapper/subset of both, Nasal and JavaScript, that can be processed by both - part of this could be machine generated actually, i.e. dynamically compiling a simple subset of a DSL into whatever target platform is desired. The main thing this would require is what Torsten implemented already: APIs for setting/getting properties and running fgcommands, in conjunction with serving fgdata resources like textures and SVG files: Canvas Nasal/JavaScript Subset[1]


Objective

Determine if it's feasible to come up with a minimal/safe subset of Nasal and JavaScript for sharing animation/update logic for SVG-based instruments that may be either implemented by the built-in Mongoose httpd or by the Canvas subsystem. Almost certainly, this would be a very restricted subset of Nasal, and even more so, of JavaScript - but there's really only a handful of functions that cannot be directly mapped to their corresponding equivalents in the other language. Internally, more complex constructs would be handled by JavaScripts eval() API or Nasal's compile(). So this would involve a fair bit of meta programming - primarily, we'd need building blocks to deal with animated SVGs. Internally, a Canvas should then be dealt with like a SVG, i.e. no direct usage of CanvasText/CanvasPath. As long as these are set up via the SVG file and turned into a Canvas property tree, we can easily serve the same SVG file to a web browser over http.

Some kind of animation framework could then rewrite the animation logic to be valid JavaScript, so that the httpd can serve the code to the browser - while Canvas would internally keep using Nasal.

Canvas

Animations

Cquote1.png You would probably want to use something like SVG/SMIL to serve animated vector images, so would not even need to use HTML5/Canvas to recreate every instrument.
— Hooray (Dec 16th, 2013). Re: Virtual Panel/Control from Web Browser.
(powered by Instant-Cquotes)
Cquote2.png

For animations, it would make sense to come up with a subset of JavaScript and Nasal which wrappers to hide the differences between the browser and fgfs, i.e. by wrapping props.nas/maketimer and building an animation framework on top of this safe subset. That way, we could allow people to create MFDs/instruments in Inkscape and a restricted subset of JavaScript/Nasal, which would mean that we could collaborate and grow a shared library of instruments that would be useful to both "front-ends".

MFDs

Before any significant amount of time is spent on re-implementing functionality available available on Gijs' ND, I'd suggest to seriously consider collaborating whenever possible - all the artwork and animation logic can be easily made platform-agnostic, i.e. there's nothing Android/FlightGear or Canvas-specific about updating a SVG element and animating/transforming it. To make this work, you would merely need to use a tiny subset of JavaScript and Nasal and add a few of helper functions as wrappers for platform-specific functionality (think property tree access) - TorstenD has already written most of the code required for this as part of his mongoose work. That way, you could easily reuse the same SVG/artwork that's internally used by the Canvas ND.

Remote GUI

The only way for the Canvas UI to provide a remote UI would be to serve SVG files via httpd/mongoose and hook them up to a subset of Nasal/JavaScript that both languages "understand", i.e. to set/get properties and invoke RPC functionality (e.g. fgcommands).

In the days prior to Phi, we actually toyed with the idea of not just using SVG in FG to create/render a widget via Canvas (ShivaVG), but to also serve SVG files with embedded code - since Torsten's Phi effort, that idea has become kinda obsolete.

But technically it would be possible to serve a SVG-based widget to a browser - for that to work, all callbacks added to events, would need to be valid JavaScript AND Nasal - even though it would be possible to dynamically recompile Nasal to be valid JavaScript (in fact, you could make Phi work with existing PUI/XML dialogs, including Nasal, doing exactly that)

And once you think about it, any Canvas could be represented as a SVG in memory and vice versa - including evne complex MFDs - i.e. we already have a parser that turns svg/xml into Canvas nodes, we could just as well have a parser doing the opposite to serve a Canvas node/group as SVG using a little serialization scheme.

Had this relationship been obvious earlier, SVG could in fact be the internal representation format of any Canvas

Dialogs

there's an unfortunate amount of custom Nasal code embedded in all kinds of PUI dialogs and that it would be a good thing to get rid of that, or at least standardize on it - i.e. so that a safe subset of Nasal can be used that would also be valid JavaScript.

Background

Given the recent mongoose/httpd work, we've been seeing some overlapping functionality that's already available in Nasal space, for which Torsten specifically implemented JavaScript wrappers, i.e. to expose the Property Tree and its listeners to JavaScript.

One idea we discussed is to "compile" Nasal into Javascript and send it to the browser (together with the canvas as SVG), but we don't know yet if this is possible with a reasonable effort. Also we should ensure that the JavaScript API and Nasal API are identical, such the code can be easily converted/ported. So we need to define a safe subset of Nasal and JavaScript and come up with corresponding classes to wrap identical stuff. And there are a quite a few useful JS features that Nasal will never support, so we need to use factories for those to hide differences between both languages (sounds like something that Philosopher might enjoy), or someone will end up complaining that jQuery breaks Nasal...

Cquote1.png For the sake of completeness, you could also use a completely different approach suggested by TorstenD: the new integrated mongoose httpd and JavaScript/DHML to create an animated website and serve that via FG (which would have nothing to do with FlightGear's hardware-accelerated Canvas system)
— Hooray (Fri Jul 18). Re: Need to Create a Standalone PFD.
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png I have uploaded a new free Android App in the Play Store. This time it is a NAV display for airliners. At the moment the App works with the Boeing 777 and Airbus 330 (Omega), but I will start adding support to other planes in the near future. Many details like fixes, nav aids, waypoints (up to 12) have been carefully implemented so that the App resembles as much fatefully as possible the Boeing NAV display. The modes APP,VOR,MAP, ARC views, etc. are controlled from the panel in flightgear.
Cquote2.png
Cquote1.png in the long term it would however make sense to re-implement this on top of Torsten's mongoose work, and maybe reusing some of Gijs' Canvas/ND work (certainly the SVG stuff could be reused, maybe even some generic Nasal/JavaScript code).
Cquote2.png
Cquote1.png Would love to see future enhancements. Specifically ILS, QNS/STD and Roll Scale. If you need support, just let me know.
Cquote2.png
Cquote1.png Before any significant amount of time is spent on re-implementing functionality available available on Gijs' ND, I'd suggest to seriously consider collaborating whenever possible - all the artwork and animation logic can be easily made platform-agnostic, i.e. there's nothing Android/FlightGear or Canvas-specific about updating a SVG element and animating/transforming it. To make this work, you would merely need to use a tiny subset of JavaScript and Nasal and add a few of helper functions as wrappers for platform-specific functionality (think property tree access) - TorstenD has already written most of the code required for this as part of his mongoose work.

That way, you could easily reuse the same SVG/artwork that's internally used by the Canvas ND.


Cquote2.png
Cquote1.png For animations, it would make sense to come up with a subset of JavaScript and Nasal which wrappers to hide the differences between the browser and fgfs, i.e. by wrapping props.nas/maketimer and building an animation framework on top of this safe subset. That way, we could allow people to create MFDs/instruments in Inkscape and a restricted subset of JavaScript/Nasal, which would mean that we could collaborate and grow a shared library of instruments that would be useful to both "front-ends".
Cquote2.png
Cquote1.png Understandably, all of this is still in a very early state, i.e. just being discussed currently - but it would obviously be great if we could work out a way to better collaborate, because ideally, we'd really become front-end agnostic, so that we can provide the infrastructure that would allow people to create MFDs/instruments using just SVGs and a subset of JavaScript/Nasal. Alternatively, we can dynamically rewrite a subset of Nasal code to turn it into valid JavaScript - e.g. props.nas would be mapped to your ported JavaScript props APIs. I am sufficiently familiar with both, JavaScript and Nasal, and both languages provide support for dynamically compiling program code at run-time - so we could just as well come up with a very limited "instrument animation markup" that is interpreted by roughly ~250 lines of Nasal code, and mapped to JavaScript or Nasal/Canvas animation logic respectively.


I don't think this would necessarily be a lot of work, it's primarily a matter of agreeing that we want to support these use-cases in the mid-term.
Also, serializing an existing Canvas to a SVG could be done by introducing a handful of wrappers for mapping Canvas elements back to valid SVG markup, we can certainly prototype that in scripting space (which is how svg parsing currently works already) - even though some more C++ hooks would definitely be possible.


Cquote2.png
Cquote1.png If we could manage to pull this off, there'd no longer be any disparity between both approaches, and they would be fully compatible - and people interested in either method could help grow the library of instrument. The only thing that we might want to explore sooner or later is serializing a Canvas to a raster image that can be served by mongoose - you already seem to have code serializing screen shots to an osg::Image, so we could use the same method to serve an arbitrary Canvas to a browser, which will be useful for more complex layers that cannot be easily represented using just scripting (no matter if it's JavaScript or Nasal).
Cquote2.png

Mapping

Note  we should take a look at the existing JavaScript wrappers for props.nas etc)


Nasal JavaScript Comments
var var
func function
call()/compile() eval()
settimer/maketimer setTimeout()
props.nas jQuery/WebSockets


var new_function =  func(keyword) {
return 
  func(name, params, body) 
  print("var ", name, "=", keyword, "(",params,")", body);
}

##
# Nasal test case:
var make_nasal_function = new_function('func');
var test = make_nasal_function(name: "hello", params: "name", body: "print(name);");
var test_obj = compile(test);

Goals

Come up with a common Nasal/JavaScript subset that works in both environments (browser/fgfs), and use factories for hiding platform differences, for example:

  • property tree
  • listeners
  • props.nas

For reference, look at TorstenD's WebGUI work which is heavily overlapping with props.nas stuff. However, we need to keep in mind that there are certain APIs that will never be supported out of the FG context, while others may simply be "delegated" via FlightGear (webSockets, e.g. timers/listeners).

So we kinda need to formalize both environments and come up with a minimal API subset that supports versioning.

We also need to keep in mind that props.nas may be updated using cppbind sooner or later to reduce Nasal space overhead.

APIs

  • setprop/getprop
  • setlistener
  • settimer

(it might make sense to directly encapsulate those APIs and use helper objects, as discussed on the forum)

Design

Mongoose-based FGPanel

Cquote1.png I have been dreaming of a cross-platform, simple

solution to render 2d panels on a remote device.

I have just succeeded with my first partial implementation of a EFIS PFD
rendered in a web browser using nothing but existing web standards and a
running FlightGear instance having the internal web server enabled.

The EFIS is created from scalable vector graphics (svg), is animated by
JavaScript and driven by properties from FlightGear over websockets.
The same svg files that are used for the FlightGear internal canvas
based instruments can also be used for the browser based display, so
both instruments (that of the 3d model and that in your browser) look
100% alike. Websocket properties are exchanged at frame rate making
animations as smooth as they can get. Because it uses SVG, instruments
are always rendered at the highest available resolution of the device
without scaling artefacts.


— Torsten Dreyer (2014-09-17). [Flightgear-devel] Goodbye fgpanel - hello fgpanel 2.0.
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png It runs on any device that has a web browser. So yes, if your FlightGear

computer can run Firefox, Opera or alike you can run it on the same
computer, too.
It is not related to the "classical" way of rendering instruments within
flightgear, so everything in this area works as before.

Probably a video is more descriptive, here is a shot of an earlier
(incomplete) version:
http://youtu.be/sYM7uiWIprc
You can see a FlightGear instance on the top right of the big monitor
and Firefox on the left showing the EFIS. Both run on the same computer.
Below the monitor are an old iPod touch (left) and a Nexus 7 (right),
both running the EFIS as a web-app in full screen mode connected over WLAN.
The EFIS in the FlightGear window is based on Canvas/Nasal. The other
EFISes are 100% Nasal free, just HTML/SVG/CSS/JavaScript


— Torsten Dreyer (2014-09-17). Re: [Flightgear-devel] Goodbye fgpanel - hello fgpanel 2.0.
(powered by Instant-Cquotes)
Cquote2.png

References

References
  1. Hooray  (Oct 10th, 2016).  Re: Canvas remote drawing .