The JS9 Public API provides a JavaScript programming interface for interacting with JS9. Obviously, all of JS9 JavaScript code is available to you within a Web page, but the public API is designed to stable and well-documented for users and Web designers. It also will provide the basis for planned language bindings (python, perhaps C/Fortran).
In general, the public API routines act on the current image being displayed in the default JS9 div element. Since most Web pages will have only a single JS9 div element, this behavior is usually what you want. It parallels DS9's behavior in which XPA commands act on the currently displayed image. For example, to change the colormap of the current image, use:
JS9.SetColormap("cool");
However, for cases where multiple JS9 div elements are defined on a single page, you can specify the specific div element to process by adding an display object argument to the calling sequence with a single display property:
{display: [div_id]}where [div_id] is the id of the target JS9 div element. For example, if two JS9 divs with ids "JS9" and "myJS9", respectively, are present on a single Web page, you can set the colormap of the second one this way:
JS9.SetColormap("cool", {display: "myJS9"})Note that this display object contains only the display property and always is specified as the final argument in a call.
The display property can specify an image handle instead of a JS9 div element id. This is a minor optimization for cases where you want to call a routine such as JS9.WCSToPix() or JS9.PixtoWCS() many times:
var im = JS9.GetImage({display: "myJS9"}); for(i=0; i<1000; i++){ x = ... y = ... wcs = JS9.PixtoWCS(x, y, {display: im}); console.log("%s %s -> %s %s", x, y, wcs.ra, wcs.dec); }Passing the image handle will speed up processing very slightly, but it makes us programmers feel much better.
The optional display object argument is not explicitly documented in the routines below (except as an example in JS9.Load()), but it is always available.
Choose from the following sections:
Load an image into JS9
JS9.Load(url, opts)
where:
Load a FITS file or a PNG representation file into JS9. You also can pass an in-memory buffer containing a FITS file, or a string containing a base64-encoded FITS file.
Finally, you can pass a fits object containing the following properties:
To override default image parameters, pass the image opts argument:
JS9.Load("png/m13.png", {scale:"linear", colormap:"sls"});
If an onload callback function is specified in opts, it will be called after the image is loaded:
JS9.Load("fits/3c273.fits", {scale: "linear", onload: func});The image handle is passed as the first argument to the callback.
To load an image into a specified display, pass the display object as the last argument:
JS9.Load("fits/3c273.fits", {scale: "linear"}, {display: "myJS9"});
See Displaying Your Data for further discussion of how to use this routine.
Load an image into a light window or a new (separate) window
JS9.LoadWindow(url, opts, type, html, winopts)
where:
The type argument determines whether to create a light-weight window or a new (separate) window.
By default, the new window will contain a Menubar above an image display area:
<div class='JS9Menubar' id='[id]Menubar'></div> <div class='JS9' id='[id]'></div>You can use the html argument to supply different Web page elements for the window. Furthermore, if you create a light window, a default set of DynamicDrive dhtmlwindow parameters will be used to make the window the correct size for the default html:
"width=512px,height=542px,center=1,resize=1,scrolling=1"You can supply your own parameters for the new dhtmlwindow using the winOpts argument. See: DynamicDrive for more information about their light-weight window.
See js9create.html for examples of how to use this routine.
Load an FITS image link into JS9 using a proxy server
JS9.LoadProxy(url, opts)
where:
Load a FITS file specified by an arbitrary URL into JS9 using the JS9 back-end helper as a proxy server.
For security reasons, JavaScript contained in one Web page can access data in another Web page only if both Web pages have the same origin (i.e., basically coming from the same host). This policy is called the Same Origin Policy. This means that JS9 cannot load a FITS file from an arbitrary URL without using special techniques.
One such technique is Cross-Origin Resource Sharing, by which the second server grants permission to access its image data. Dropbox is CORS-enabled, so that FITS files can be loaded directly into JS9. But obviously this requires that explicit permission be granted by the other server.
A second technique is to use a proxy server: the URL is not loaded directly into JS9, but instead is copied back to the server from which JS9 itself was loaded. The file is then retrieved by JS9 from this server so that the "same origin" rules are not violated.
The JS9 Node.js back-end helper can be configured to support proxy server mode by setting the JS9.globalOpts.loadProxy property. In addition, the back-end server must be configured to support temporary working directories for each loaded page by setting the JS9.globalOpts.workDir property. If the back-end server is thus configured as a proxy server, JS9 will support the JS9.LoadProxy() call and allow you to load FITS files from arbitrary URLs. JS9 also will display a open link via proxy menu option in the File menu.
The JS9.LoadProxy() call takes a URL as its first argument. This URL will be retrieved using curl or wget and stored on the back-end server in a directory specifically tied to the Web page. (The directory and its contents will be deleted when the page is unloaded.) JS9 then will load the file from this directory. Note that since the file resides on the back-end server, all back-end analysis defined on that server is available.
To override default image parameters, pass the image opts argument:
JS9.LoadProxy("http://hea-www.cfa.harvard.edu/~eric/coma.fits", {scale:"linear", colormap:"sls"});'
If an onload callback function is specified in opts, it will be called after the image is loaded:
JS9.LoadProxy("http://hea-www.cfa.harvard.edu/~eric/coma.fits", {scale: "linear", onload: func});'The image handle is passed as the first argument to the callback.
To load an image into a specified display, pass the display object as the last argument:
JS9.LoadProxy("http://hea-www.cfa.harvard.edu/~eric/coma.fits", {scale: "linear"}, {display: "myJS9"});'
Note again that not all back-end servers support the proxy functionality. The main JS9 Web site does support proxy service, and can be used to view images from arbitrary URLs.
Load one or more images when the Web page is ready
JS9.Preload(url1, opts1, url2, opts2, ... url2, optsn)
where:
It is worth emphasizing that JS9.Preload() should not be called until the Web page is fully loaded, since JS9 itself is not fully initialized until then. It is for this reason that JS9.Preload() generally is called using an onload routine tied to the Web page body.
Get Load Status
status = JS9.GetLoadStatus(id)
where:
tfits = "foo.fits" hdul = fits.open(tfits) ... j = JS9() j.SetFITS(hdul, tfits) while j.GetLoadStatus(tfits) != "complete": time.sleep(0.1) j.SetZoom(2)
Get image handle for the current image
im = JS9.GetImage()
returns:
The routine returns the image handle associated with the current image.
The returned image handle can be passed in the display object. This is marginally more efficient than the default behavior, which is to determine the current image for each call.
Get image data and auxiliary info for the specified image
imdata = JS9.GetImageData(dflag)
where:
returns:
The image data object contains the following information:
If dflag is the string "array", a JavaScript array is returned. This is not a reference to the real data and will utilize additional memory, but the values can be manipulated safely.
If dflag is the string "base64", a base64-encoded string is returned. Oddly, this seems to be the fastest method of transferring data to via socket.io an external process such as Python, and, in fact, is the method used by the pyjs9.py interface. (The "array" method also can be used, but seems to be slower.)
The file value can be a FITS file or a representation PNG file. The fits value will be the path of the FITS file associated with this image. For a presentation PNG file, the path generally will be relative to the JS9 install directory. For a normal FITS file, the path usually is an absolute path to the FITS file.
If you are calling JS9.GetImageData() from an external process (via the msg protocol), you almost certainly want to set dflag to "array". Doing so will serialize the data as an array instead of as an object, saving a considerable amount of transfer data.
Given a FITS-standard 1-indexed image pixel x,y, you can find the data value at that location using:
val = obj.data[Math.floor(y-0.5) * obj.width + Math.floor(x-0.5)];Note the need to integerize the x and y values: JavaScript arrays are objects and so floating point array indices do not get truncated automatically as in C. They will return null values.
Also note that since we need 0-based data array indexes, we subtract 1 from the 1-based image position. But then we must add 0.5 before rounding because by convention, x.0, y.0 is the middle of the pixel.
Get image data for all images loaded into the specified display
imarr = JS9.GetDisplayData()
returns:
The JS9.GetDisplayData() routine returns an array of image data objects, one for each images loaded into the specified display. That is, it returns the same type of information as JS9.GetImageData(), but does so for each image associated with the display, not just the current image.
Display an image
JS9.DisplayImage(step)
where:
The default step is "primary", which displays the image without recalculating color data, scaled data, etc. This generally is what you want, unless you have explicitly changed parameter(s) used in a prior step.
Re-read the image data and re-display
JS9.RefreshImage(input, func)
where:
Ordinarily, when refreshing an image, there is no need to specify the optional axis, bitpix, or header properties. But note that you actually can change these values on the fly, and JS9 will process the new data correctly. Also, if you do not pass dmin or dmax, they will be calculated by JS9.
Note that you can pass a blob containing a complete FITS file to this routine. The blob will be passed to the underlying FITS-handler before being displayed. Thus, processing time is slightly greater than if you just pass the image data directly.
The main difference between JS9.RefreshImage() and JS9.Load() is that the former updates the data into an existing image, while the latter adds a completely new image to the display.
Blend the image in an image stack using W3C composite/blend modes
JS9.BlendImage(blendMode, opacity)
Calling sequences:
JS9.BlendImage() # return current blend params JS9.BlendImage(true||false) # turn on/off blending JS9.BlendImage(mode, opacity) # set blend mode and/or opacity
where:
JS9 allows you to use these modes to blend images together. If you load two images of the same object into JS9, you can use the JS9.ReprojectData() routine to align them by WCS. You then can blend one image into the other by specifying a blend mode and an optional opacity. For example, if chandra.fits and spitzer.fits are two aligned images of the same object, and chandra.fits is currently being displayed, you can blend spitzer into chandra using the "screen" blend and opacity 0.9 mode this way:
JS9.BlendImage("screen", 0.9);After the spitzer image is blended, both images will be displayed as part of the chandra.fits display. However, changing the colormap, scale, contrast, or bias will only affect the current chandra image, not the blended spitzer part. In this way, you can continue to manipulate the current image and the image blending will update automatically.
Also note that the spitzer image is still available separately for display and manipulation. You can switch to displaying spitzer and change colormap, scale, bias, contrast, etc. But since the images are now blended, changes to spitzer will be reflected in the spitzer part of the blended chandra display. Thus, if you change the colormap on the display of spitzer, and change back to chandra, the blended chandra image will utilize the new colormap.
This linkage is maintained during zoom and pan operations. If you display the blended chandra image and then zoom or pan it, both images will be updated correctly to maintain alignment. But note that this means when you go back to the spitzer display, its zoom and/or pan values will have been updated. In this way, the spitzer image always is correctly linked to the blended version. The JS9.BlendImage() call accepts a variable number of arguments to perform a variety of functions:
Clear the image from the display and mark resources for release
JS9.CloseImage()
Each loaded image claims a non-trivial amount of memory from a finite amount of browser heap space. For example, the default 32-bit version of Google Chrome has a memory limit of approximately 500Mb. If you are finished viewing an image, closing it tells the browser that the image's memory can be freed. In principle, this is can help reduce overall memory usage as successive images are loaded and discarded. Note, however, that closing an image only provides a hint to the browser, since this sort of garbage collection is not directly accessible to JavaScript programming.
Some day, all browsers will support full 64-bit addressing and this problem will go away ...
Get the image colormap
cmap = JS9.GetColormap()
returns:
Set the image colormap
JS9.SetColormap(colormap, [contrast, bias])
where:
Save current colormap definition
JS9.SaveColormap(filename)
where:
Add a colormap to JS9
JS9.AddColormap(name, aa|rr,gg,bb|obj|json)
where:
JS9.AddColormap("i8", [[0,0,0], [0,1,0], [0,0,1], [0,1,1], [1,0,0], [1,1,0], [1,0,1], [1,1,1]]));Here, the colormap is divided into 8 sections having the following colors: black, green, blue, cyan (green + blue), red, yellow (red + green), purple (red + blue), and white. A colormap such as sls also utilizes an array of RGB triplets, but it has 200 entries, leading to much more gradual transitions between colors.
The second colormap format consists three arrays of vertices defining the change in intensity of red, green, and blue, respectively. For each of these three color triplets, the first coordinate of each vertex is the x-distance along the colormap axis (scaled from 0 to 1) and the second coordinate is the y-intensity of the color. Colors are interpolated between the vertices. For example, consider the following:
JS9.AddColormap("red", [[0,0],[1,1]], [[0,0], [0,0]], [[0,0],[0,0]]); JS9.AddColormap("blue", [[0,0],[0,0]], [[0,0], [0,0]], [[0,0],[1,1]]); JS9.AddColormap("purple", [[0,0],[1,1]], [[0,0], [0,0]], [[0,0],[1,1]]);In the red (blue) colormap, the red (blue) array contains two vertices, whose color ranges from no intensity (0) to full intensity (1) over the whole range of the colormap (0 to 1). The same holds true for the purple colormap, except that both red and blue change from zero to full intensity.
For a more complicated example, consider the a colormap, which is defined as:
JS9.AddColormap("a", [[0,0], [0.25,0], [0.5,1], [1,1]], [[0,0], [0.25,1], [0.5,0], [0.77,0], [1,1]], [[0,0], [0.125,0], [0.5, 1], [0.64,0.5], [0.77, 0], [1,0]]);Here we see that red is absent for the first quarter of the colormap, then gradually increases to full intensity by the half mark, after which it stays at full intensity to the end. Green ramps up to full intensity in the first quarter, then drops to zero by the half and stays that way until a bit more than three-quarters along, after which it gradually increases again. Blue starts off at no intensity for an eighth, then gradually increases to full intensity by the half-way mark, decreasing gradually to zero by the three-quarter mark. The result is that you see, for example, green at the beginning and yellow (red + green) at the end, with some purple (red + blue) in the middle of the colormap.
As a convenience, you also can pass an object or JSON string containing the colormap definition:
# RGB color triplets for the I8 colormap in a "colors" property {"name":"i8","colors":[[0,0,0],[0,1,0],[0,0,1],[0,1,1],[1,0,0],[1,1,0],[1,0,1],[1,1,1]]} # all 3 vertex arrays for the purple colormap in one "vertices" property {"name":"purple","vertices":[[[0,0],[1,1]],[[0,0],[0,0]],[[0,0],[1,1]]]}
Finally, note that JS9.AddColormap() adds its new colormap to all JS9 displays on the given page.
Get the image scale
scale = JS9.GetScale()
returns:
Set the image scale
JS9.SetScale(scale, smin, smax)
where:
Get the image zoom factor
zoom = JS9.GetZoom()
returns:
Set the image zoom factor
JS9.SetZoom(zoom)
where:
Get the image pan position
ipos = JS9.GetPan()
returns:
Set the image pan position
JS9.SetPan(x, y)
where:
Get the display coordinates from an event
dpos = JS9.EventToDisplayPos(evt)
where:
Get the image coordinates from the display coordinates
ipos = JS9.DisplayToImagePos(dpos)
where:
Get the display coordinates from the image coordinates
dpos = JS9.ImageToDisplayPos(ipos)
where:
Get the image coordinates from the logical coordinates
ipos = JS9.LogicalToImagePos(lpos, lcs)
where:
This routine will convert from logical to image coordinates. By default, the current logical coordinate system is used. You can specify a different logical coordinate system (assuming the appropriate keywords have been defined).
Get the logical coordinates from the image coordinates
lpos = JS9.ImageToLogicalPos(ipos, lcs)
where:
This routine will convert from image to logical coordinates. By default, the current logical coordinate system is used. You can specify a different logical coordinate system (assuming the appropriate keywords have been defined).
Get value/position information
valpos = JS9.GetValPos(ipos, display)
where:
Set the value/position display mode
JS9.SetValPos(mode)
where:
Get the current WCS units
unitsstr = JS9.GetWCSUnits()
returns:
Set the current WCS units
JS9.SetWCSUnits(unitsstr)
where:
Get the current World Coordinate System
sysstr = JS9.GetWCSSys()
returns:
Set the current World Coordinate System
JS9.SetWCSSys(sysstr)
where:
Convert image pixel position to WCS position
wcsobj = JS9.PixToWCS(x, y)
where:
The wcs object contains the following properties:
Convert WCS position to image pixel position
pixobj = JS9.WCSToPix(ra, dec)
where:
Display a text message
JS9.DisplayMessage(which, text)
where:
Create or Modify a Raw Data Layer
JS9.RawDataLayer(opts, func)
where:
To create a new raw data layer (or edit an existing layer), call the JS9.RawDataLayer() with two arguments: layer opts (or layer name) and a function. The layer opts object can have the following properties:
The pixel modifying function should have the following calling sequence:
func(oraw, nraw, opts)where:
Note that the nraw object will contain the raw data for this layer, if it already exists. Otherwise, it will contain a copy of the from data.
For example, the following routine creates a new "clip" layer and clips the original raw data at the specified nmax level:
im.rawData({rawid: "clip", nmax: n}, function (oraw, nraw, opts){ var i, len; opts = opts || {}; if( opts.nmax === undefined ){ opts.nmax = 0; } len = nraw.width * nraw.height; for(i=0; i<len; i++){ if( oraw.data[i] < opts.nmax ){ nraw.data[i] = 0; } else { nraw.data[i] = oraw.data[i]; } } return true; });When clipping, the nraw pixel values are taken from the oraw values, so that you can clip to a value of 100, then clip to a value of 50, and get the right result. This is different from the following example "add" layer, which adds a constant value to the existing data:
im.rawData({rawid: "add", val: n}, function (oraw, nraw, opts){ var i, len; opts = opts || {}; if( opts.val === undefined ){ opts.val = 1; } len = nraw.width * nraw.height; for(i=0; i<len; i++){ nraw.data[i] += opts.val; } return true; });Here, the operation is performed on the existing "add" layer each time, so that the addition is cumulative.
The oraw and nraw objects contain a subset of the properties returned by JS9.GetImageData():
To switch to a layer, call JS9.RawDataLayer() with a single argument, the layer name:
JS9.RawDataLayer("raw0") # switch to original data JS9.RawDataLayer("clip") # switch to clipped data JS9.RawDataLayer("add") # switch to add dataTo get the currently displayed layer, call the routine with no arguments:
JS9.RawDataLayer() # returns "clip"
Shift Raw Data
JS9.ShiftData(x, y, opts)
where:
Gaussian Blur of Raw Data
JS9.GaussBlurData(sigma, opts)
where:
Apply a Filter to the RGB Image
JS9.FilterRGBImage(filter, args)
where:
The JS9.FilterRGBImage() routine supports a number of image processing routines, which are listed below. To call one of them using JS9.FilterRGBImage(), supply the filter name, followed by any filter-specific arguments, e.g.:
JS9.FilterRGBImage("luminance", {display: "myJS9"}); JS9.FilterRGBImage("duotone", "g", {display: "myJS9"}); JS9.FilterRGBImage("convolve", [-1,-1,-1,-1,8,-1,-1,-1,-1]);You can, of course, use the default arguments where applicable.
Note that the standard JS9 colormaps, scale, contrast and bias selections are applied to the raw data to regenerate the RGB image. Thus, if you use any of the image processing techniques listed below and then change colormap, contrast, bias, or scale, you will undo the applied image processing. This is a good way to reset the displayed image. The same thing can be accomplished programmatically by specifying "reset" as the filter name:
JS9.FilterRGBImage("reset", {display: "myJS9"});
The following simple image processing filters are available:
The following image convolutions are available:
With no arguments, the routine returns an array of available filters:
JS9.FilterRGBImage() ["convolve", "luminance", ..., "blur", "emboss", "lighten", "darken"]
Reproject an Image Using a Specified WCS
JS9.ReprojectData(wcsim, opts)
where:
mProjectPP performs a plane-to-plane transform on the input image, and is an adaptation of the Mopex algorithm and developed in collaboration with the Spitzer Space Telescope. It provides a speed increase of approximately a factor of 30 over the general-purpose mProject. However, mProjectPP is only suitable for projections which can be approximated by tangent-plane projections (TAN, SIN, ZEA, STG, ARC), and is therefore not suited for images covering large portions of the sky. Also note that it does not directly support changes in coordinate system (i.e. equatorial to galactic coordinates), though these changes can be facilitated by the use of an alternate header.
The wcsim argument is an image id, image filename, or image object pointing to the WCS image.
The opts object can contain the following reproject-specific properties:
{cmdswitches: "-d 1 -z .75"}will set the mProjectPP debugging and the drizzle factor, resulting in a command line that looks like this:
mProjectPP -d 1 -z .75 -s statusfile in.fits out.fits template.hdrSee the mProjectPP documentation for more information about command switches.
Reprojection is an intensive process which can take a considerable amount of memory and processing time. To avoid crashes, we currently restrict the WCS image size used for reprojection to a value defined by JS9.REPROJDIM, currently 2200 x 2200. Even this might be too large for iOS devices under certain circumstances, although issues regarding memory are evolving rapidly.
Spatial regions of interest are a crucial part of astronomical data analysis. The regions layer is a special case of the more generalized shape layers, automatically created by JS9 to support the options in the Regions menu, as well as local and server-side data analysis using regions.
The regions layer has the special property that, by default, its z-index is higher than other shape layers, so that regions are displayed on top of other shape layers.
Note that the GetRegions(), ChangeRegions(), RemoveRegions() calls all take a regions specification as the second argument, which can be any of the following (in order of precedence):
Add one or more regions to the regions layer
id = JS9.AddRegions(rarr, opts)
where:
Get information about one or more regions
rarr = JS9.GetRegions(regions)
where:
Each returned region object contains the following properties:
obj = JS9.GetImageData(); xreg = JS9.GetRegions("selected")[0]; val = obj.data[Math.floor(xreg.y-0.5) * obj.width + Math.floor(xreg.x-0.5)];
Note the need to integerize the x and y values: JavaScript arrays are objects and so floating point array indices do not get truncated automatically as in C. They will return null values.
Also note that since we need 0-based data array indexes, we subtract 1 from the 1-based image position. But then we must add 0.5 before rounding because by convention, x.0, y.0 is the middle of the pixel.
Change one or more regions
JS9.ChangeRegions(regions, opts)
where:
Remove one or more regions from the region layer
JS9.RemoveRegions(regions)
where:
JS9 supports individual layers for drawing 2D graphics. The regions layer is a special case of a shape layer, created automatically by JS9. The Catalog plugin creates a separate layer for each catalog. You can define your own shape layer using the NewShapeLayer() call and then add geometric shapes to it.
Note that the JS9.GetShapes(), JS9.ChangeShapes(), JS9.RemoveShapes() calls all take a shape specification as the second argument, which can be any of the following (in order of precedence):
Save regions from the current image to a file
JS9.SaveRegions(filename, which)
where:
Load regions from a file into the current image
JS9.LoadRegions(filename)
where:
Create a new shape layer
lid = JS9.NewShapeLayer(layer, opts)
where:
The optional opts parameter allows you to specify default options for the new layer. You can set a default for any property needed by your shape layer. See JS9.Regions.opts in js9.js for example of the default options for the regions layer.
The JS9.Catalogs.opts object is also supplied as a possible default object for new shape layers. It differs from the JS9.Regions.opts object in that it does not define regions-specific processing (such as double-click to edit a region parameters). It also makes the new layer non-interactive: individual shapes cannot be moved, rotated, resized, or deleted, nor do they respond to events.
Starting with the JS9.Catalogs.opts object as a default, you can make the new layer interactive in a few different ways. The first way is to set the movable property in the opts object to true. This will permit individual shapes to be moved, rotated, resized and deleted. Shapes also will be movable and resizeable as a group.
The second way is to supply one or more event callbacks as properties to the opts object:
opts.onmouseover = function(im, xreg, evt){ console.log("mouseover: %s %s", im.id, xreg.data.tag); }; opts.onmousedown = function(im, xreg, evt){ console.log("mousedown: %s %s", im.id, xreg.data.tag);Note that the shapes are still not movable unless you also set the movable property.
In addition to firing callbacks on events for individual shapes, you can set the ongroupcreate property in the opts object to a function that will fire when two or more objects are selected into a group (which is done using the Command key on a Mac, or Control key everywhere else):
opts.ongroupcreate = function(im, xregs, evt){ var i, nshape, xcen, ycen; var xtot=0, ytot=0; nshape = xregs.length; for(i=0; i<nshape; i++){ xtot += xregs[i].x; ytot += xregs[i].y; } xcen = xtot / nshape; ycen = ytot / nshape; console.log("average pos for %s objects: %s,%s", nshape, xcen, ycen); }
The final way to make a shape layer interactive is to specify a tooltip to display when hovering over objects in this shape layer. This is done by assigning a tooltip format string to the tooltip property of the opts object. This string can contain HTML directives, and it also can contain references to properties in the im, xreg, and evt objects. When the mouse hovers over an object, a tooltip string is generated by macro-expanding the values for these properties. The generated tooltip string is displayed as the inner HTML of the tooltip. When the mouse leaves the object, the tooltip is hidden.
For example, consider the following tooltip string:
opts.tooltip = "<b>id: $im.id</b><br>pos: $xreg.x $xreg.y<br><i>$xreg.data.tag</i>";Note how properties of the im and xreg objects are specified with a "$" prefix. When the mouse hovers over an object, the generated tooltip will display current image id in bold, followed by that object's x,y pixel position, followed by a user tag property passed in the data object when the shape was added.
Show or hide the specified shape layer
JS9.ShowShapeLayer(layer, mode)
where:
Add one or more shapes to the specified layer
JS9.AddShapes(layer, sarr, opts)
where:
Remove one or more shapes from the specified shape layer
JS9.RemoveShapes(layer, shapes)
where:
Get information about one or more shapes in the specified shape layer
JS9.GetShapes(layer, shapes)
where:
Each returned shape object contains the following properties:
Change one or more shapes in the specified layer
JS9.ChangeShapes(layer, shapes, opts)
where:
Run a simple server-side analysis task
JS9.RunAnalysis(name, parr, func)
where:
http://api.jquery.com/serializeArray/
The func() routine is a callback function to process the returned results from the analysis task. The calling sequence is:
func(stdout, stderr, errcode, aobj)where:
If no func callback is specified, the default processing will display "text" in a new light window. If the return type is "plot", the results are assumed to be in flot format and will be plotted.
Run a server-side analysis task, utilizing parameters in a form
JS9.SubmitAnalysis(el, name, func)
where:
The func callback is the same as for JS9.RunAnalysis() above.
Resize the JS9 Display
JS9.ResizeDisplay(width, height, opts)
where:
The opts object can contain the following properties:
If no arguments are passed to this routine, it returns an object containing the current display width and height. Otherwise, the display object is returned.
Print an image
JS9.Print(opts)
where:
Print the currently displayed image. A new window is displayed containing the image, along with regions and other graphical layers (the 2D graphics having been converted to a re-scalable format). The standard Print dialog box also is displayed and can be used to print this new window. Dismiss both windows when you are finished.
By default, if a colorbar is active on the page, it will be placed beneath the image. You can pass the colorbar: false option in the opts object to avoid printing the active colorbar.
Save image as a FITS file
JS9.SaveFITS(filename)
where:
Save image as a PNG file
JS9.SavePNG(filename)
where:
Save image as a JPEG file
JS9.SaveJPEG(filename, quality)
where:
Get FITS header as a string
JS9.GetFITSHeader(nlflag)
where:
Note that the JS9.GetImageData() routine also returns the FITS header, but as an object whose properties contain the header values. For example, obj.SIMPLE will usually have a value of true, obj.BITPIX will have contain the bits/pixel, etc. This object is more useful for programming tasks, but does not contain the FITS comments associated with each header card.
Display help in a light window
JS9.DisplayHelp(name)
where:
Display plugin in a light window
JS9.DisplayPlugin(name)
where:
You can supply the full class and plugin name or just the name, using exact case or lower case, e.g.:
As with plugins in the View and Analysis menus, this routine does nothing if the plugin is explicitly defined on the Web page.
This routine is useful if you are building a Web interface that supports the JS9 menu functions.
Use the file dialog box to load a FITS file
JS9.OpenFileMenu()
Calling this routine brings up the browser's file dialog box. When a FITS file is selected, if will be loaded into the JS9 display.
This routine is useful if you are building a Web interface that supports the JS9 menu functions.
Use the file dialog box to load a region file
JS9.OpenRegionsMenu()
Calling this routine brings up the browser file menu. When a region file is selected, if will be loaded into the JS9 display.
This routine is useful if you are building a Web interface that supports the JS9 menu functions.
Use the file dialog box to load a colormap file
JS9.OpenColormapMenu()
Calling this routine brings up the browser file menu. When a JSON-format colormap file is selected, it will be loaded into the JS9 display. The colormap file can take one of two forms (without the comments):
# RGB color triplets for the I8 colormap in a "colors" property {"name":"i8","colors":[[0,0,0],[0,1,0],[0,0,1],[0,1,1],[1,0,0],[1,1,0],[1,0,1],[1,1,1]]} # all 3 vertex arrays for the purple colormap in one "vertices" property {"name":"purple","vertices":[[[0,0],[1,1]],[[0,0],[0,0]],[[0,0],[1,1]]]}This routine is useful if you are building a Web interface that supports the JS9 menu functions. See JS9.AddColormap() for more information about colormap formats.
Get location of JS9 installation directory
rpath = JS9.InstallDir(file)
where:
Send a message to a back-end server
JS9.Send(msg, obj, cb)
where:
Communication with the back-end is usually done behind the scenes and need not concern users or application programmers. However, if you write your own socket.io-based server, you might want to add project-specific messages to your implementation. For example, a Perl-based or Python-based server might add its own special messages that execute Perl or Python commands within the server in response to JS9 messages. In this case, you can use JS9.Send() to send a message to these message handlers.
The msg name is the name of the message, as defined by the server. By convention, an object is usually passed to the message handler. JS9 will add a dataPath property to this object to indicate the current list of directories in which to search for data. All other properties are specific to the message being handled. You can pass a null instead of an object and JS9.Send() will generate a temporary object to hold the dataPath.
The cb function will be called if the message sends an acknowledgment. The arguments passed to this function call by the server are specific to the message being handled.
For example, you can send a message to the back-end server to retrieve the list of available analysis tasks and then display this list using the call:
JS9.Send("getAnalysis", null, function(s){alert(s)});The "getAnalysis" message passes no parameters to the server. The server returns a list of available analysis tasks in JSON format.
Add a JS9 display div and/or associated plugins
JS9.AddDivs(id1, id2, ...)
where:
The routine will accept a list of JS9 display divs to initialize. If all you are doing is adding one or more plugins to an existing display, leave the argument list empty.
For example, to add a new JS9 display and menubar at the end of a Web page and load an image into that display:
var html = "<div class='JS9Menubar' id='myJS9Menubar'></div><div class='JS9' id='myJS9'></div>"; // jquery append to end of page $(html).appendTo($("body")); // create the new JS9 display, with associated plugins JS9.AddDivs("myJS9"); // just a standard load to that display JS9.Load("foo.fits", {scale: "log"}, {display: "myJS9"});See also JS9.LoadWindow() for a nice way to load images into a light-weight or completely new window.
NB: The routines in this section are prototypes and therefore are subject to change. Feel free to contact us to discuss your needs so that we can gain a better understanding of what is required in these cases.
Load an auxiliary file
JS9.LoadAuxFile(name, func)
where:
It sometimes is desirable to process auxiliary files when an image is first loaded. Examples include overlaying an image mask on an image, and pre-loading regions from a region file. The JS9.LoadAuxFile prototypes this sort of functionality.
Auxiliary files are defined in the js9Prefs.json file by means of the JS9.auxfiles array containing one or more auxfile objects. Each auxfile specification has the following properties:
"auxFiles": [{"type": "mask", "name": "sciencemasks", "image": "casa.*.png", "url": "../myauxfiles/casa-mask.png"}, {"type": "regions", "name": "scienceregions", "image": "casa.*.png", "url": "../myauxfiles/casa.reg"}],Here, a mask auxfile and a regions auxfile are defined for Cas-A dataset(s). These auxfiles are brought into play as follows:
// run this routine after loading each image function onImageLoad(im){ JS9.LoadAuxFile("sciencemasks", function(im, aux){ // if we succeed in loading the mask, set up the onchange callback im.onregionschange = regionOnChange; // view the image through the mask data im.maskData = aux.im.raw.data; // I mean now! im.displayImage("all"); }); JS9.LoadAuxFile("scienceregions"); } // tell JS9 about the onload callback JS9.imageOpts.onload = onImageLoad;An onImageLoad function is defined that will try to load auxfiles of types "sciencemasks" and "scienceregions". This routine is set to be called whenever a new image is loaded.
On image load, when JS9.LoadAuxFile() is called, it looks in the list of known auxfiles for an entry that matches both the class name and the image name. If found (in the example above, for Cas-A datasets), the associated auxfile URL is loaded and type-specific processing is performed:
As should be clear from the description above, considerable "black magic" currently is involved when processing auxiliary files. Visibility is required into the inner properties of the image object. Please contact us if you want to work with auxiliary files, so that we can continue to think about what is required for their support.
The JS9 Public API is meant to be stable and well-documented. If we are forced to make an incompatible change to the API, it will be documented here.
20151218: OpenFileMenu and OpenRegionsMenu don't require a display argument
The routines OpenFileMenu() and OpenRegionsMenu() required a display argument, instead of utilizing the standard optional display object. This mistake has been corrected, with the result that both routines now target the default display, as expected, if no display is passed.
20141117: The Set routines now return "OK" instead of true on success
The public Set routines (SetZoom(), SetColormap(), etc) were returning a boolean true when successful. This has been changed to "OK", to make it clear that the return value is a status value, not a boolean data value.
20141028: callback function to RunAnalysis and SubmitAnalysis
Due to an oversight, the signature of the callback function supplied to RunAnalysis() (and its derivative function, SubmitAnalysis()) was missing the errcode argument. To correct this mistake, the signature was changed from:
func(stdout, stderr, aobj)to:
func(stdout, stderr, errcode, aobj)See js9onchange.html for an example of using this callback function.