JS9 can be used as a desktop replacement for SAOimage DS9: you can load images into the app's web page (or your own custom web page) and use the full power of JS9, including external messaging.
Advantages of using JS9 on the desktop include:
Advantages of using DS9 include:
Desktop JS9 is based on Electron.js, a widely-used framework for creating native applications with web technologies like JavaScript, HTML, and CSS. Install Electron.js by visiting the release page: http://electron.atom.io/releases and downloading the latest available stable release for your platform. On a Mac, the Electron.app should be installed in the /Applications or ~/Applications folder. On Linux, the electron program should be placed in your PATH. Note that Electron.js for Linux requires a relatively recent version of Linux: Ubuntu 12.04, Fedora 21, Debian 8, CentOS 7 (not CentOS 6). Note that Electron.js also is available for Windows, so desktop JS9 should also run on that OS, although we have not done any work in this direction. If you get desktop JS9 running under Windows, please let us know!
Once the Electron.js is installed, you can build JS9 as usual, taking care to configure use of the Node.js helper. Note that there is no need to actually install Node.js: desktop JS9 has its helper integrated into Electron.js already.
Moreover, if you are not planning to utilize server-side analysis tasks or large file support, you can skip the standard build and simply generate the JS9 quick-start files:
./mkjs9 -q Editing js9Prefs.json for Node.js helper ... Editing js9prefs.js for Node.js helper ... Generating js9 script for JS9 messaging and desktop use ... If you plan to use Electron.app with JS9, consider codesign'ing it: sudo codesign --force --deep --sign - /Applications/Electron.app/Contents/MacOS/Electron/ This will avoid repeated requests to allow incoming connections.The mkjs9 script will create a js9prefs.js file (for the browser) and a js9Prefs.json file (for the JS9 helper), which you can edit to add preferred JS9 properties, as well as a js9 script to start the JS9 app. On a Mac, you probably will want to codesign the Electron.app application to avoid repeated requests about incoming connections (see example above).
NB: if you are running cpu-intensive scripts that communicate with the Electron-based JS9 app, we recommend that you install Node.js as well as Electron.js, and start up the JS9 helper instead of using the built-in helper support in the Electron-based app. The startup will be considerably faster when using the Node helper.
The js9 script is normally made accessible by adding the JS9 install directory (when fully building JS9) or the source directory (for quick install) to your user PATH.
Run the js9 script with the -a switch to start the desktop app, display the default JS9 web page, and load one or more FITS files:
# the -a switch tells the script to bring up the desktop js9 app js9 -a ~/data/casa.fitsIn the desktop app, all relative paths are relative to current working directory, as would be expected with files passed to any desktop program. For consistency, this behavior extends to the case of files specified in web pages: relative files are still relative to the current directory, not the web page (as would be the case with browsers). It is controlled globally by the JS9.globalOpts.currentPath property and locally by the fixpath property. For example, if the desktop app loads a webpage, then the default call to JS9.Load():
<a href='javascript:JS9.Load("fits/casa.fits", {scale:"log", colormap: "cool"});'>CAS-A</a>specifies that the FITS file is relative to the current working directory, while use of fixpath:false:
<a href='javascript:JS9.Load("fits/casa.fits", {scale:"log", colormap: "cool", fixpath:false});'>CAS-A</a>specifies that the FITS file is relative to the web page.
The same js9 script (without the -a switch) can now be used to interact with the JS9 page (or any other JS9-enabled web page):
# without -a, the script sends commands to the JS9 display js9 SetColormap cool js9 AddRegions 'ICRS;ellipse(23:23:18.76, +58:47:27.252, 31.8", 15.9", 40)'See: External Messaging for more details.
You can also load remote images, as the script will call LoadProxy as needed:
js9 -a http://hea-www.cfa.harvard.edu/~eric/coma.fits.gz
A number of desktop-specific switches are available in the js9 script. Perhaps the most important is the --webpage switch, which allows you to specify a custom web page to display, so that you can tailor the desktop app to your specific needs:
js9 -a --webpage ~/myjs9/myjs9.html ~/data/casa.fitsWhen configuring your own web page, one simple possibility is to create a separate directory, parallel to the JS9 source (or install) directory, in which you can maintain your custom web page(s) and your customized js9prefs.js file. You might also create a myjs9 script that runs the js9 script. For example, this myjs9.html file might be stored in a myjs9 directory parallel to the js9 directory:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge;chrome=1" > <meta name="viewport" content="width=device-width, initial-scale=1"> <link type="image/x-icon" rel="shortcut icon" href="../js9/favicon.ico"> <link type="text/css" rel="stylesheet" href="../js9/js9support.css"> <link type="text/css" rel="stylesheet" href="../js9/js9.css"> <script type="text/javascript" src="js9prefs.js"></script> <script type="text/javascript" src="../js9/js9support.min.js"></script> <script type="text/javascript" src="../js9/js9.min.js"></script> <script type="text/javascript" src="../js9/js9plugins.js"></script> <title>my JS9 app</title> </head> <body> <div class="JS9Menubar" data-width="100%"></div> <p style="margin-top: -14px;"> <table cellspacing="0" style="width:100%;"> <tr valign="top"> <td align="left"> <div class="JS9" data-width="768px" data-height="768px"></div> <div style="margin-top: 2px;"> <div class="JS9Colorbar" data-width="768px" id="JS9Colorbar" data-showTicks="false" data-height="10px"></div> </div> </td> <td align="right"> <table cellspacing="0"> <tr valign="top"> <td> <div class="JS9Magnifier" data-width="250px" data-height="250px"></div> </td> </tr> <tr valign="top"> <td> <div class="JS9Panner" data-width="250px" data-height="250px"></div> </td> </tr> <tr valign="top"> <td> <div class="JS9Info" data-height="250px" style="margin-top: 2px;"></div> </td> </tr> </table> </td> </tr> </table> </body> </html>Note that the JavaScript and CSS files are loaded from the js9 source (or install) directory, but the js9prefs.js is loaded from the myjs9 directory. This separation allows you to configure site-wide js9 parameters without changing the any of the files in the source directory, and allows you to update the source directory very easily by executing "git pull".
A script such as the following can then be used to use this web page in the JS9 desktop:
#!/bin/bash WEBPAGE="$HOME/myjs9/myjs9.html"; WIDTH=1130; HEIGHT=860; if [ x${JS9_WEBPAGE} != x ]; then WEBPAGE=${JS9_WEBPAGE} fi if [ x${JS9_WEBPAGE_WIDTH} != x ]; then WIDTH=${JS9_WEBPAGE_WIDTH} fi if [ x${JS9_WEBPAGE_HEIGHT} != x ]; then HEIGHT=${JS9_WEBPAGE_HEIGHT} fi exec $HOME/js9/js9 -a --width $WIDTH --height $HEIGHT --webpage $WEBPAGE $*As shown above, the --width and --height switches are available to set the width and height of the Electron.js window which will contain the web page.
Another important switch is --title (and its generalized cousin, --renameid). This switch will rename the main JS9 display id in the web page (whose default is "JS9") to the specified id. It is useful in cases where you want to start up multiple desktops using the same web page, and communicate with each one separately. In such cases, the --title switch will change the id of the JS9 display element and its auxiliary elements (e.g. menubar, colorbar, etc) to the specified title:
js9 -a --title foo1 ~/data/casa.fitsYou will then be able to communicate with this web page using the specified id:
js9 --id foo1 GetColormap {"colormap":"heat","contrast":1,"bias":0.5}The --renameid switch allows you to specify multiple JS9 displays to rename, in cases where more than one JS9 display is part of a web page:
js9 -a --renameid "JS9:foo1,myJS9:foo2" ~/data/casa.fitswill rename the default "JS9" element to "foo1" and the "myJS9" element to "foo2".
The --savedir switch will set the directory into which files are saved, avoiding the display of an interactive dialog box when saving images:
js9 -a --savedir /Users/eric/Desktop ~/data/casa.fits ... js9 --id foo1 SavePNG casa.pngwill save the casa.png file on the desktop without a dialog box. This is especially useful in automatic scripting.
You can use the --cmds [cmds] and/or --cmdfile [file] switches to pass Javascript commands that will be executed when JS9 is ready and all files have been loaded. The former takes a string of commands as an argument:
# load a file and set the colormap and scale js9 -a --cmds 'JS9.SetColormap("cool");JS9.SetScale("log")' ~/data/casa.fitsThe latter takes a file containing commands, allowing you to perform more sophisticated processing. For example, the following script will load the Chandra image of the Kes 75 supernova remnant, display three energy cuts as separate images, assign red, green, and blue colormaps to the three energy cuts, and then blend them into a single display:
# run the script in the command file js9 -a --cmdfile eband.js // where eband.js contains the following Javascript: JS9.Load("kes75/kes75_evt2.fits.gz", {onload: function(im){ var i; // colormaps var c = ["red", "green", "blue"]; // energy filters var f = ["energy=500:1500", "energy=1500:2500", "energy=2500:8000"]; // set final configuration after each image is loaded var mkdo = function(i){ return function(xim){ JS9.SetScale("log", {display: xim}); if( c[i] ){ JS9.SetColormap(c[i], {display: xim}); } }; }; // turn blending off on the main image JS9.BlendImage(false); // process each of the event filters to make a separate image for(i=0; i<f.length; i++){ // display filtered image in a separate displayed JS9.DisplaySection({filter:f[i], separate:true, ondisplaysection: mkdo(i)}, {display: im}); } // blend the filtered images JS9.BlendDisplay(true); }});
The --merge switch allows you to utilize another user's setup, including their JS9 web page and analysis routines. Say, for example, a colleague has used Dropbox to share her JS9-enabled zhjs9 directory, containing the following files and sub-directories:
zhjs9.html js9prefs.js js9addons.js analysis-plugins: zhtools.json analysis-wrappers: zhjs9 params: adapt.html imexam.html mexhat.html atrous.html imsmo.html refinepos.htmlwhere zhjs9.html has a header in which the paths to JS9's files are matched to your colleague's setup, but not your own:
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=Edge;chrome=1" > <meta name="viewport" content="width=device-width, initial-scale=1"> <link type="image/x-icon" rel="shortcut icon" href="../../js9/favicon.ico"> <link type="text/css" rel="stylesheet" href="../../js9/js9support.css"> <link type="text/css" rel="stylesheet" href="../../js9/js9.css"> <link rel="apple-touch-icon" href="../../js9/images/js9-apple-touch-icon.png"> <script type="text/javascript" src="js9prefs.js"></script> <script type="text/javascript" src="../../js9/js9support.min.js"></script> <script type="text/javascript" src="../../js9/js9.js"></script> <script type="text/javascript" src="../../js9/js9plugins.js"></script> <script type="text/javascript" src="js9addons.js"></script> </head>Also note the presence of analysis tool definitions and scripts in the analysis-plugins, analysis-wrappers, and params sub-directories. Normally, in order to use the zhjs9 web page and associated analysis tools, you would need to edit the former and change the JS9 paths, and move the contents of the three analysis tools sub-directories into the appropriate sub-directories in the main JS9 install directory.
Instead, you can simply merge this directory into your desktop app, e.g.
js9 -a --merge ~/Dropbox/zhjs9/zhjs9.htmlThis will generate and load a temporary webpage using correct paths to the JS9 install directory and load the analysis tools into the JS9 helper. You can also merge the analysis tools without loading the web page by specifying only the directory:
js9 -a --merge ~/Dropbox/zhjs9In addition, if a bin directory is present, it will be added to the PATH used when processing analysis commands.
A merged web page can, of course, include its own javascript and css files, as shown in the example above. It can also include JS9.Load() commands, for example, to load files from a subdirectory. In this case, you should set the fixpath property to false so that the paths of the data files are not changed into paths relative to the current working directory (which is the default behavior for desktop JS9.Load() calls):
<a href='javascript:JS9.Load("fits/casa.fits", {scale:"log", colormap: "cool", fixpath:false});'>CAS-A</a>
Finally, the --node switch allows you to enable Node.js capabilities in a local (but not remote) web page environment. By default, this feature is turned off because, in principle, Node integration provides a greater attack surface for hackers. But since node integration is permitted only for local web pages, an attacker would have to be on your system ... so you're probably in big trouble anyway.
That said, there are two good reasons for turning on node integration:
When node integration is enabled, the JS9 app will (subject to the boolean value of the JS9.globalOpts.localAccess property) mount the local file system inside the web page and access FITS files directly, instead of fetching and storing them in browser memory. This can speed up the load/display time considerably, while minimizing the use of a browser memory. The list of file extensions which are accessed directly in this way is specified by the JS9.globalOpts.localTemplates property, which defaults to .fits and .fts. Note that bzip'ed (.bz2) and gzip'ed (.gz) files are not accessed directly: the former are not supported by the CFITSIO FITS access library, while the latter are supported by uncompressing the file in memory, which is done more efficiently by JS9 itself. Also, symbolic links currently are not accessed directly. We expect to remove this restriction in the near future.
With node integration, you can also run scripts that access local system resources. For example, the following script will load the Chandra image of the Kes 75 supernova remnant, display three energy cuts as separate images, find the total number of counts in each image, and write the results to a log file, using the Node.js 'fs' module.
# enable node support and run the script in the command file js9 -a --node true --cmdfile ecnts.js // where ecnts.js contains the following Javascript: var fs; try{ fs = require("fs"); } catch(e){ JS9.error("Node.js 'fs' module is unavailable. Did you enable node?"); } JS9.Load("kes75/kes75_evt2.fits.gz", {onload: function(im){ var i; var s = ""; var got = 0; // energy filters var f = ["energy=500:1500", "energy=1500:2500", "energy=2500:8000"]; // get counts in regions as each image is displayed var getcnts = function(i){ return function(xim){ s += xim.countsInRegions(); got++; if( got === 3 ){ // write the results to a log file fs.writeFile("countsInRegions.log", s, function(err) { if( err ) { JS9.error(err); } }); } }; }; // process each of the event filters to make a separate image for(i=0; i<f.length; i++){ // display filtered image in a separate displayed JS9.DisplaySection({filter:f[i], separate:true, ondisplaysection: getcnts(i)}, {display: im}); } }});
For a list of all js9 script switches, use the --help switch:
js9 --help
The JS9 File menu contains two options only available for Desktop use:
It is important to note that Electron.js is not a web browser, and web pages you load are not sandboxed. Our JS9 desktop application code takes additional precautions to enhance security:
Even with these safeguards in place, it is important that you load only local or trusted remote web pages into the JS9 desktop app. See: Electron.js security for more information.
You should update your copy of Electron.js periodically to ensure that you have the latest security fixes in place.