### The JS9 Public API

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 display (i.e., the HTML div element that defines the JS9 display.) Since most web pages will have only a single JS9 display, 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 displays are defined on a single page, you can specify the specific display to process by adding an display object argument to the calling sequence with a single display property:

        {display: [display_id]}

where [display_id] is the id of the target JS9 display (i.e. the id of the HTML div element.) For example, if two JS9 displays 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.

For image-based API routines (not display-based routines with names ending in Display, e.g., JS9.ResizeDisplay or JS9.BlendDisplay), the display property can specify an image handle or image id instead of a JS9 display id. When the image handle in question points to the currently displayed image, this alternate usage is nothing more than a trivial optimization. Thus, to call a routine such as JS9.WCSToPix() or JS9.PixtoWCS():

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

However, the image handle does not need to point to the currently displayed image. When it does not, the public routine will act on the image associated with the image handle, not the current image. In particular, you can use JS9.LookupImage() to get the image handle of any image, and then act on that image. For example, if two images, foo1.fits and foo2.fits, are loaded into a JS9 display, and foo1.fits is currently being displayed, you can close foo2.fits this way:

        var im = JS9.LookupImage("foo2.fits");
        if( im ){
            JS9.CloseImage({display: im});
        }

The optional display object argument generally is not mentioned in the routines below, but it is always available.

Choose from the following sections:

- Loading Images
- Working with Images
- Working with Regions
- Working with Shape Layers
- Mouse/Touch Gestures
- Server-side Analysis
- Working with Displays
- Miscellaneous
- Prototypes (in development)
- API Change History

#### Loading Images

##### Load an image into JS9

`JS9.Load(url, opts)`

where:

- url: url, in-memory FITS, FITS blob, data object
- opts: optional object or JSON string containing image parameters

Load a FITS file (or a PNG/JPEG file) into JS9. You also can pass an in-memory buffer containing a FITS file, a blob containing a FITS file, or a string containing a base64-encoded FITS file. Finally, you can pass a generic data object containing the following properties:

- naxis: number of axes in the image
- axis: array of image dimensions for each axis or ...
- naxis[n] image dimensions of each axis (naxis1, naxis2, ...)
- bitpix: FITS bitpix value
- head: object containing header keywords as properties
- image: typed data array containing image data (native format)
- dmin: data min (optional)
- dmax: data max (optional)
- refresh: refresh data when reloading image?
- allext: load all image extensions?
- file: set the file property in cases where the url is a script
- id: set the id property
- proxy: use experimental CGI proxy to load a remote URL

An image URL can only be loaded from the same origin as the JS9 JavaScript code, which is called the Same Origin Policy. This means that this routine cannot load an image file (i.e., FITS, PNG, or JPG) from an arbitrary URL. You can, however, load remove URLs using the JS9.LoadProxy() routine, which retrieves the image into a temp directory before loading it locally.

For FITS files, we are experimenting with a second way to retrieve remote URLs: using a CGI script that adds the required CORS header to the retrieved FITS data on the fly. The CGI script is controlled by the JS9.globalOpts.cgiProxy global property and has the default value https://js9.si.edu/cgi-bin/FITS-proxy.cgi. If you pass proxy: true in opts, this CGI script will be used to retrieve the FITS file and return it with the required CORS header.

The JS9.RefreshImage() and JS9.Load() routines differ in that the former always updates the data into an existing image, while the latter generally adds a completely new image to the display.

However, in the case where an image already is loaded, JS9.Load() does not reload the image into a new display: this would initiate another (often time-consuming) download, resulting in two identical images. Instead, behavior is dependent on the value of the refresh property passed in opts (or, if that is not set, by the JS9.globalOpts.reloadRefresh property), as follows:

- if refresh is true, the existing image is refreshed
- if refresh is false, the existing image is redisplayed

The global default is to redisplay instead of refreshing. Site authors can change this property in js9prefs.js, while users can change this via the Global tab of the Preferences plugin.

To override default image parameters, pass the image opts argument:

        JS9.Load("data/fits/casa.fits", {scale:"linear", colormap:"sls"});

You can also pass a regions property to add regions or load a region file:

        # but oh my, its dicey mixing quotes and wcs arcsec/arcmin delims
        JS9.Load("data/fits/casa.fits", {regions:'ICRS; box(23:23:40.340, +58:47:04.059, 29.5", 29.5", 0)'});
        # much easier to pass a filename, if possible
        JS9.Load("data/fits/casa.fits", {regions:"casa/casa.reg"});

or a pan position:

        # pan to physical coords (usually file coords)
        JS9.Load("data/fits/casa.fits", {px: 4009, py: 3926});
        # pan to ra, dec using file's wcs
        JS9.Load("data/fits/casa.fits", {ra: 350.866689, dec: 58.811671});
        # pan to ra, dec using specified wcs
        JS9.Load("data/fits/casa.fits", {wcs: "23:23:27.942 +58:48:42.02 ICRS"});

If an onload callback function is specified in opts, it will be called after the image is loaded. By default, the image handle is passed as the first argument to the callback:

        JS9.Load("data/fits/3c273.fits", {scale: "linear", onload: func});
    #    function func(im){
    #        JS9.SetColormap("rainbow", {display: im});
    #        JS9.SetScale("log", {display: im});
    #    }

You can specify the name of a routine as a string (instead of the function itself):

        JS9.Load("data/fits/3c273.fits", {scale: "linear", onload: "myfunc"});'

Assuming the function "myfunc" is defined in the window context, it will be called with the image handle as the first argument.

Note that you can supply arguments along with a string-name function:

        JS9.Load("data/fits/3c273.fits", {scale: "linear", onload: "docmap('viridis')"});'

As a convenience, you can also pass a JS9 public routine name:

        JS9.Load("data/fits/3c273.fits", {scale: "linear", onload: "SetColormap('viridis')"});'

The string-name capability is especially valuable when calling Load() from the shell or Python using External Messaging:

        js9 Load ~/data/coma.fits '{"onload":"SetColormap(viridis,4.5,0.35)"}'

Note that you don't need to quote the string arguments ('viridis' in the example above), but also note that all arguments are passed as strings and must be converted to the correct data type in your own bespoke functions (as is done in JS9 public routines).

If your url is a function returning a FITS file (e.g. CGI or PHP script accessing an archive), the filename will end up being the name of the script, which probably is not what you want. In this case, you can set the file property explicitly:

        JS9.Load("mycgi?FITSFILE=acisf00361N003_evt2.fits", {file:"acisf00361N003_evt2.fits"})

Similarly, you can set the id property explicitly (without setting the file) to tailor the id for special needs.

To load an image into a specified display, pass the display object as the last argument:

        JS9.Load("data/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:

- url: url to load
- opts: optional object or JSON string containing image parameters and/or the display id
- type: "light" or "new"
- html: html for the new page (default is to display a menubar above the image and a colorbar below)
- winopts: for "light", optional dhtml window options

returns:

- id: the id of the JS9 display div

This routine will load an image into a light-weight window or an entirely new window. The url and opts arguments are identical to the standard JS9.Load() call, except that opts can contain:

- id: string specifying the id of the JS9 display being created. If no id is specified, a unique id is generated.
- clone: the id of a display to clone: the menubar, colorbar, statusbar will be created if and only if they are present in the cloned display (for light window creation only.)

The type argument determines whether to create a light-weight window ("light", which is the default) or a new, separate window ("new".)

By default, the created window will contain a Menubar above a JS9 Display area and a Colorbar below:

        <div class='JS9Menubar' id='[id]Menubar'></div>
        <div class='JS9' id='[id]'></div>
        <div style="margin-top: 2px;">
        <div class='JS9Colorbar' id='[id]Colorbar'></div>
        <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.

To create a new light window without loading an image, use:

        JS9.LoadWindow(null, null, "light");

See js9create.html for examples of how to use this routine.

##### Load an image URL into JS9 using a proxy server

`JS9.LoadProxy(url, opts)`

where:

- url: remote URL link to load
- opts: optional object or JSON string containing image parameters

Load a FITS, PNG, or JPEG 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 image files (i.e., FITS, PNG, or JPG) 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 image 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, PNG, and JPG 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"});'

By default, the retrieved file is given a filename based on the base of the URL. When a gzip'ed file is retrieved, the filename is taken from the original ungzip'ed file, with a .gz extension added. As an alternative, you can specify the name of the output file using the ofile property.

        JS9.LoadProxy("http://nxsa.esac.esa.int/nxsa-sl/servlet/data-action-aio?obsno=0801931101&name=OEXPMP&level=MT_PPS&extension=FTZ",
                      {ofile: "MP_P0801931101EPX000OEXPMP8000.FIT.gz"})

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:

- url: url to load
- opts: optional object or JSON string containing image parameters

This routine will pre-load images into a JS9 display. It can be added to the web page body element using the onload() JavaScript call or called in a JavaScript init routine tied to onload. See index.html and js9preload.html for examples.

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.

You can load URLs outside the current web page domain if you are running a JS9 helper which has enabled the server side Proxy Load capability. See Server-side Analysis Tasks for more information.

##### Get Processing Status

`status = JS9.GetStatus(type, id)`

where:

- type: the type of status
- id: the id or image handle of the image

returns:

- status: status of processing

This routine returns the status of one of the following specified asynchronous processing types: "Load", "CreateMosaic", "DisplaySection", "LoadCatalog", "LoadRegions", "ReprojectData", "RotateData", "RunAnalysis".

A status of "complete" means that the image is fully processed. Other statuses include:

- processing: the image is being processed
- loading: the image is in process of loading ("Load" only, for backward compatibility)
- error: processing did not complete, due to an error
- other: another image is loaded into this display
- none: no image is loaded into this display

Thus, to check for image load, one can do this in Python:

        tfits = "foo.fits"
        hdul = fits.open(tfits)
        ...
        j = JS9()
        j.Load(hdul, tfits)
        while j.GetStatus("load", tfits).strip() != "complete":
            time.sleep(0.1)
        j.SetZoom(2)

##### Get Load Status

`status = JS9.GetLoadStatus(id)`

where:

- id: the id or image handle of the file that was loaded into JS9

returns:

- status: status of the load

This routine returns the status of the load of this image. Provided for backward compatibility, it simply calls the more general JS9.GetStatus() routine with "Load" as the first argument.

A status of "complete" means that the image is fully loaded. Other statuses include:

- loading: the image is in process of loading
- error: image did not load due to an error
- other: another image is loaded into this display
- none: no image is loaded into this display

Thus, to check for image load, one can do this in Python:

        tfits = "foo.fits"
        hdul = fits.open(tfits)
        ...
        j = JS9()
        j.Load(hdul, tfits)
        while j.GetLoadStatus(tfits) != "complete":
            time.sleep(0.1)
        j.SetZoom(2)

#### Working with Images

##### Get image handle for the current image

`im = JS9.GetImage()`

returns:

- im: image handle

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.

##### Lookup an image by id

`im = JS9.LookupImage(id)`

where:

- id: image id

returns:

- im: image handle

The JS9.LookupImage() routine takes a string id as input and returns the image handle of the image having that id (or null.) The id is the same as is found in the File menu list of displayed images. This routine is similar to the standard JS9.GetImage() routine, but returns an image by name, regardless of whether it is currently being displayed.

You can use this routine, for example, so close an image that is not currently being displayed. If two images, foo1.fits and foo2.fits, are loaded into a JS9 display, and foo1.fits is currently being displayed, you can close foo2.fits this way:

        var im = JS9.LookupImage("foo2.fits");
        if( im ){
            JS9.CloseImage({display: im});
        }

##### Get image data and auxiliary info for the specified image

`imdata = JS9.GetImageData(dflag)`

where:

- dflag: specifies whether the data should also be returned

returns:

- imdata: image data object

The image data object contains the following information:

- id: the id of the file that was loaded into JS9
- file: the file or URL that was loaded into JS9
- fits: the FITS file associated with this image
- source: "fits" if a FITS file was loaded, "img" if PNG or JPEG
- imtab: "image" for FITS images and PNG/JPEG files, "table" for FITS binary tables
- width: x dimension of image
- height: y dimension of image
- fwidth: x dimension of image or fully binned table in original file
- fheight: y dimension of image or fully binned table in original file
- dwidth: width of JS9 display (div element)
- dheight: height of JS9 display (div element)
- bitpix: FITS bits/pixel of each image element (8 for unsigned char, 16, 32 for signed integer, -32 or -64 for float)
- bin: current binning factor
- header: JavaScript object containing FITS header values
- hdus: JavaScript array containing objects that describe the FITS HDU structure (FITS files only)
- data: buffer containing raw data values

This call can return raw data for subsequent use in local analysis tasks. The format of the returned data depends on the exact value of dflag. If dflag is the boolean value true, an HTML5 typed array is returned. In JavaScript, typed arrays are more efficient than ordinary JavaScript arrays, and, in this case, the returned data is actually just reference to the real JS9 image data (so be careful about changing values.)

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. Early on, this seems to be the fastest method of transferring data via socket.io an external process such as Python. Currently, the "array" method should generally be used (this is now the default for the pyjs9 interface to Python.)

The file the path of the FITS file associated with this image.

The header object contains FITS header keywords. Note that all HISTORY and COMMENT keywords have two underscores and a numeric value appended, in order to make them unique within the object.

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.

##### Get image data for all images loaded into the specified display

`imarr = JS9.GetDisplayData()`

returns:

- imdataArr: array of image data objects

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:

- step: starting step to take when displaying the image

The display steps are: "colors" (remake color data when cmap has changed), "scaled" (rescale data values), "primary" (convert scaled data values to color values), and "display" (write color values to the web page.)

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 redisplay

`JS9.RefreshImage(input, opts)`

where:

- input: object, javascript array, typed array, FITS blob, or string
- opts: optional options or function to call when refresh is complete

The RefreshImage routine re-reads image data and updates the the current image. It can be used, for example, in laboratory settings where data is being gathered in real-time and the JS9 display needs to be refreshed periodically. The first input argument can be one of the following:

- a text string specifying a new URL to retrieve
- a javascript array containing raw image data
- a typed array containing raw image data
- a blob containing a FITS image file
- an object containing a required image property and any of the following optional properties:
  - naxis: number of axes in the image
  - axis: array of image dimensions for each axis or ...
  - naxis[n]: image dimensions of each axis (naxis1, naxis2, ...)
  - bitpix: FITS bitpix value
  - head: object containing header keywords as properties
  - dmin: data min (optional)
  - dmax: data max (optional)

A text string passed to the input argument is assumed to be a URL (or local file pathname) to retrieve and utilize when refreshing the data in the current image. This option is used, for example, where an external program rewrites the image file, and the new data are then used to refresh the display. Note that the specified file becomes the current image file and will be used for subsequent server-based analysis request as well as refreshImage() calls with a null input argument (see next paragraph.)

If the input argument is null, the current image file is reloaded, assuming its file path (or URL) is known. For security reasons, browsers do not expose the path of files loaded via Drag and Drop or Open Local File. On a local web page, you can safely use the File -> set this image file's path menu option to enter the image path here for subsequent reloading (or analysis.)

When passing an object as input, the required image property containing the image data can be a javascript array or a typed data array. It also can contain a base64-encoded string containing an array. This latter can be useful when calling JS9.RefreshImage() via HTTP.

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 image 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 second optional argument can be an object containing the following:

- onrefresh: function to perform when refresh is complete

For backwards compatibility, the onrefresh function can be specified directly by this argument. In both cases, the image handle is passed to the function:

        # preferred method
        JS9.RefreshImage(blob, {onrefresh: xrefresh});
        # for backwards compatibility
        JS9.RefreshImage(blob, xrefresh);
        # both call this function
        function xrefresh(im){ ... };

Advanced use: it is possible to load several images into an instance of JS9 and then refresh any of them regardless of which image is currently displayed. To do this, you pass the display property in a trailing object, with the id of the image to refresh. For example, if foo1.fits and foo2.fits are loaded and foo2.fits is currently displayed:

        # refresh foo2.fits using foo2.fits as the new image
        JS9.RefreshImage();
        # refresh foo2.fits using foo3.fits as the new image
        JS9.RefreshImage("foo3.fits");

        # refresh foo1.fits (even though its not currently displayed)
        # it will be currently displayed once this operation is complete
        JS9.RefreshImage({display:"foo1.fits"});
        # refresh foo1.fits using foo4.fits as the new image
        JS9.RefreshImage("foo4.fits", {display:"foo1.fits"});

        # warning: this refreshes foo2.fits using foo1.fits as the new image,
        # rather than refreshing foo1.fits!!
        JS9.RefreshImage("foo1.fits");

The main difference between JS9.RefreshImage() and JS9.Load() is that the former updates the data in the currently displayed image, while the latter adds a completely new image to the display.

##### Extract and display a section of a FITS file

`JS9.DisplaySection(opts)`

where:

- opts: object containing section options or "full"

This routine allows you to extract and display a section of FITS file. If the first argument is the text string "full", the full image is displayed (assuming there is sufficient memory available.) Otherwise the opts object contains properties specifying how to generate and display the section:

- xcen: x center of the section in file (physical) coords
- ycen: y center of the section in file (physical) coords
- xdim: x dimension of section to extract before binning
- ydim: y dimension of section to extract before binning
- bin: floating bin factor or bin directive string
- binMode: "a" to average binned pixels, "s" to sum binned pixels
- filter: for tables, row/event filter to apply when extracting section
- columns: alternate columns for binning a table (def: "X Y")
- cubecol: table to cube conversion column (col[:min:max][:bitpix])
- separate: display as a separate image (default is to refresh the current image)
- refresh: display as a refreshed image in a different display (default is to refresh the current image)
- ondisplaysection: function to perform after section is displayed

Numeric bin values are floating point numbers. A negative bin value means 1 / abs(bin), i.e. bin value of -4 means to bin at 0.25. The string-valued bin directives are:

- x[n]|X[n]|*[n]: multiply the current bin by n (e.g., "x2")
- /[n]: divide the current bin by n (e.g., "/2")
- in|In: multiply the current bin by 2
- out|Out: divide the current bin by 2
- [n]a: bin by n, averaging the binned pixels
- [n]s: bin by n, summing the binned pixels

Note that the JS9.globalOpts.binMode property specifies the default action for whether the binned pixels are summed together (if the global binMode is "s") or averaged (if the global binMode is "a".) This behavior can be overridden by the binMode option or by last two bin directives listed above.

All properties are optional: if a property is not specified, the routine will use the center of the file, with dimensions and binning specified by JS9.globalOpts.table and JS9.globalOpts.image objects. the image's current settings. This allows you to set up the section once, and then repeatedly change a property such as the center or filter, without having to specify the other properties.

For example, if an image has dimensions 4096 x 4096, then specifying:

- center: 1024, 1024
- dimensions: 1024, 1024
- bin: 2

will bin the upper left 1024 x 1024 section of the image by 2 to produce a 512 x 512 image. Subsequent calls to change the center values will pan the image using the same bin factor and dimension.

Note that setting xcen,ycen to 0,0 will specify the file center.

By default, the new section replaces the data in the currently displayed image. You can display the section as a separate image in the current display by supplying an opts object with the separate property set to true. For example:

      JS9.DisplaySection({ ... separate: true});

will display the new section separately from the original file, allowing blinking, image blending, etc. between the two "files".

You also can display the section as a separate image in a different display by supplying a string value to the opts.separate property. The string value takes two forms:

- [display]: display the image in the specified JS9 display, using the same image id
- [display]:[id]: display the image in the specified JS9 display, using the specified image id

For example:

      # separate into a new display, same image id
      JS9.DisplaySection({ ... separate: "myJS9"});
      # separate into a new display, and with a new image id
      JS9.DisplaySection({ ... separate: "myJS9:newsection.fits"});

Both of these commands will display the new section "myJS9" display. The first will retain the original image id, while the second will use "newsection.fits" as the image id. Alternatively, you can display the section by refreshing the image in a different display by supplying a string value to the opts.refresh property. Again, the string value takes two forms:

- [display]: refresh the image in the specified JS9 display, using the same image id
- [display]:[id]: refresh the image in the specified JS9 display, using the specified image id

For example:

      # refresh image in a new display, same image id
      JS9.DisplaySection({ ... refresh: "myJS9"});
      # refresh the new display, and change to a new image id
      JS9.DisplaySection({ ... refresh: "myJS9:newsection.fits"});

If no image is currently loaded in the specified display, the first call to this routine using the refresh property will create a new image in that display. Subsequent calls will refresh that image.

Table filtering allows you to select rows from an FITS binary table (e.g., an X-ray event list) by checking each row against an expression involving the columns in the table. When a table is filtered, only valid rows satisfying these expressions are used to make the image.

A filter expression consists of an arithmetic or logical operation involving one or more column values from a table. Columns can be compared to other columns or to numeric constants. Standard JavaScript math functions can be applied to columns. JavaScript (or C) semantics are used when constructing expressions, with the usual precedence and associativity rules holding sway:

      Operator                                Associativity
      --------                                -------------
      ()                                      left to right
      !  (bitwise not) - (unary minus)        right to left
      *  /                                    left to right
      +  -                                    left to right
      < <= > >=                               left to right
      == !=                                   left to right
      &  (bitwise and)                        left to right
      ^  (bitwise exclusive or)               left to right
      |  (bitwise inclusive or)               left to right
      && (logical and)                        left to right
      || (logical or)                         left to right
      =                                       right to left

For example, if energy and pha are columns in a table, then the following are valid expressions:

      pha > 1
      energy == pha
      pha > 1 && energy ≤ 2
      max(pha,energy) ≥ 2.5

NB: JS9 uses cfitsio by default (you can, but should not, use the deprecated fitsy.js), and therefore follows cfitsio filtering conventions, which are documented here.

By default, tables are binned into an image using the "X" and "Y" columns. You can specify different binning columns using the opts.columns property:

      JS9.DisplaySection({ ... columns: "DX DY"});

Tables can be converted into 3D cubes by specifying the opts.cubecol property. The cubecol value should be a string containing the column name and, optionally, the min and max values and/or the bin size:

      # each image in the cube has an width of 100 energy units
      JS9.DisplaySection({ ... cubecol: "energy:100"});
      # image cube 3rd dimension is 60 ... each image having a bin width of 100
      JS9.DisplaySection({ ... cubecol: "energy:1000:7000:100"});

By default, when opts.cubecol is specified, the opts.separate property is set to true, i.e. a separate image is displayed, leaving the original intact.

Obviously, cube generation will require a considerable amount of memory since the resulting file is maintained in the Emscripten heap. Because browser memory generally is limited, JS9 enforces a memory limit on the size of the cube, specified by JS9.globalOpts.maxMemory (and currently set to 2Gb). To avoid exceeding this limit, you usually try adjusting the xdim, ydim, and/or bitpix values as well as the binsize of the specified cube column:

      # each image utilizes approx 2Mb, so that 400 slices should fit ...
      JS9.DisplaySection({xdim:1024, ydim:1024, bitpix:16, cubecol:"energy:1000:7000:20"});

Once a cube has been created, you can use the Cube plugin to blink each image slice. You can also run external analysis on individual slices.

##### Display an extension from a multi-extension FITS file

`JS9.DisplayExtension(extid, opts)`

where:

- extid: HDU extension number or the HDU's EXTNAME string or "all"
- opts: object containing options

This routine allows you to display images and binary tables from a multi-extension FITS file. The first argument is the 0-indexed HDU number or the EXTNAME name value of the HDU extension to display. If "all" is specified, then all 2D image extensions are loaded in order and displayed as separate images.

The optional opts object can contain:

- separate: boolean determining whether images are loaded separately

If separate is true, the new extension is displayed as a separate image. Otherwise, the new extension replaces the current display.

See the FITS Primer for more information about HDUs and multi-extension FITS.

##### Display a slice of a FITS data cube

`JS9.DisplaySlice(slice, opts)`

where:

- slice: slice description, slice number, or "all"
- opts: object containing options

This routine allows you to display a 2D slice of a 3D or 4D FITS data cube, i.e., a FITS image containing 3 or 4 axes.

The slice parameter can either be the numeric value of the slice in the third (or fourth) image dimension (starting with 1) or it can be a slice description string: a combination of asterisks (or commas) and a numeric value defines the slice axis. Thus, for example, in a 1024 x 1024 x 16 cube, you can display the sixth slice along the third axis in one of two ways:

      JS9.DisplaySlice(6);

or:

      # sixth slice along third axis
      JS9.DisplaySlice("*:*:6");
      # comma separators also can be used
      JS9.DisplaySlice("*,*,6");

If the image was organized as 16 x 1024 x 1024, you would use the string description:

      JS9.DisplaySlice("6:*:*");

By default, the new slice replaces the data in the currently displayed image. You can display the slice as a separate image in the current display by supplying an opts object with the separate property set to true. For example:

      JS9.DisplaySlice("6:*:*", {separate: true});

will display the sixth slice of the first image dimension separately from the original file, allowing blinking, image blending, etc. between the two "files". Note that the new id and filename are adjusted to be the original file's values with the cfitsio image section [6:6:*:*] appended.

If the first argument is "all", then all slices will be loaded into JS9 separately.

##### 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:

- mode: one of the W3C bend modes
- opacity: the opacity of the blended image (percent from 0 to 1)

Image processing programs such as Adobe Photoshop and Gimp allow you to blend a stack of images together by mixing the RGB colors. The W3C has defined a number of composite and blending modes which have been implemented by Firefox, Chrome, and Safari (what about Edge?):

- normal
- multiply
- screen
- overlay
- darken
- lighten
- color-dodge
- color-burn
- hard-light
- soft-light
- difference
- exclusion
- hue
- saturation
- color
- luminosity

In addition, the following Porter-Duff compositing modes are available (though its unclear how useful they are in JS9 image processing):

- clear
- copy
- source-over
- destination-over
- source-in
- destination-in
- source-out
- destination-out
- source-atop
- destination-atop
- xor
- lighter

Blending and compositing modes are described in detail in this W3C candidate recommendation and in this Mozilla document.

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:

- JS9.BlendImage() returns an object containing the following properties:
  - active: boolean specifying whether this image is to be blended
  - mode: string specifying the blend mode
  - opacity: opacity value (0 to 1)
- JS9.BlendImage() returns a blend object for the current image
- JS9.BlendImage(true||false) turns on/off blending of
- JS9.BlendImage(blend, opacity) set or modify the blend mode and/or opacity

Other actions will be added as we gain experience with blending operations

##### Set the global image blend more for the specified display

`mode = JS9.BlendDisplay(true|false)`

returns:

- mode: current blend mode

This routine will turn on/off the global image blend mode for the specified display. If no argument is specified, it returns the current blend mode.

If the first argument is "reset", the blend mode for all images in this display will be set to false, along with the display's blend mode. This is useful if you have loaded/blended a number of images, and want to load/blend another set of images.

If the first argument is "list", an array is returned containing the image id's of all images that have blend mode turned on for this display. This is useful for changing the blend modes of all active images at once.

##### Synchronize operations between two or more images

`JS9.SyncImages(ops, images, opts)`

Calling sequences:

        JS9.SyncImages([ops], [images], [opts])  # set up synchronization
        JS9.SyncImages(true||false)              # turn on/off synchronization

where:

- ops: operation or array of operations on which to sync
- images: image or array of images to sync with this image
- opts: options for sync'ing

Synchronize two or more images, so that when an operation is performed on one image, it also is performed on the other(s). For example, when the colormap or scale is changed on an image, it also is changed on the sync'ed images. Or, when a region is created, moved, resized, or removed on an image, the same happens on the sync'ed images.

When the JS9.SyncImages() call is invoked, the current image is configured to synchronize the specified images. In addition, if the reciprocate property is set in the opts object (see below), the other images are also configured to synchronize one another (as well as the current image.) Once configuration is complete, a sync command is executed immediately. If the current image already displays one or more regions, these will be created in the target images.

The operations that can be specified for sync'ing are: "alignment", "colormap", "contrastbias" (i.e., both "contrast" and "bias"), "flip", "pan", "regions", "rot90", "rotate", "scale", "wcs" (i.e., both "wcssys" and "wcsunits"), and "zoom". If no array is specified, the default array in JS9.globalOpts.syncOps is used.

Regions calls the JS9.CopyRegions() routine. Alignment calls JS9.AlignPanZoom() in order to keep the pixel size and displayed center position constant between the sync'ed images. It assumes no rotation between the two images.

Images to synchronize can be specified singly or as an array of image handles or image ids. If no array is specified, all currently displayed images are sync'ed.

The optional opts object can contain:

- reverse: boolean to reverse this image and target images (def: false)
- reciprocate: boolean determining whether images sync one another
- syncwcs: use WCS header params to sync (e.g., pan), where available

If the opts object is not specified, the default values of reciprocate and syncwcs are the values of the JS9.globalOpts.syncReciprocate and JS9.globalOpts.syncWCS, respectively.

Examples:

        # the current image will sync all operations for all images
        # this will happen reciprocally, so that changing any image syncs the others
        JS9.SyncImages()

        # the current image will sync the specified ops for foo1.fits, foo2.fits:
        JS9.SyncImages(["scale", "colormap"], ["foo1.fits", "foo2.fits"])

        # the current image will sync two images with default ops,
        # but the two images themselves will not sync images reciprocally
        JS9.SyncImages(null, ["foo1.fits", "foo2.fits"], {reciprocate: false});

Note that if the pan operation syncs two images having differently sized fields of view, the smaller image will stop panning when it reaches its edge, rather than displaying a blank field.

You can turn on/off syncing for a given image by specifying a single boolean argument:

        # turn off sync'ing temporarily
        JS9.SyncImages(false);

This is different from unsync'ing in that you can turn sync'ing back on without having to re-sync the images.

##### Unsynchronize two or more previously synchronized images

`JS9.UnsyncImages(ops, images, opts)`

Calling sequence:

        JS9.UnsyncImages([ops], [images], [opts])  # clear synchronization

where:

- ops: array of operations to unsync
- images: array of images to unsync with this image
- opts: options for unsync'ing

Unsynchronize previously sync'ed images.

The operations that can be specified for unsync'ing are: "alignment", "colormap", "contrastbias" (i.e., both "contrast" and "bias"), "flip", "pan", "regions", "rot90", "rotate", "scale", "wcs" (i.e., both "wcssys" and "wcsunits"), and "zoom". If no array is specified, the default array in JS9.globalOpts.syncOps is used. Thus, you can turn off sync'ing for specified operations, while leaving others to be sync'ed.

Images to be unsync'ed can be specified as an array of image handles or image ids. If no array is specified, all currently displayed images are unsync'ed.

The optional opts object can contain:

- reciprocate: boolean determining whether images sync one another
- reverse: boolean to reverse this image and target images (def: false)

If the opts object is not specified, the default is to reciprocate based on the value of the JS9.globalOpts.syncReciprocate property.

Examples:

        # this image will no longer sync on scale for foo1.fits and foo2.fits,
        # and they also will stop sync'ing
        JS9.UnsyncImages(["scale"], ["foo1.fits", "foo2.fits"])

        # this image will still sync foo1.fits and foo2.fits, but
        # foo1.fits and foo2.fits will no longer sync this image:
        JS9.UnsyncImages(null, ["foo1.fits", "foo2.fits"], {reverse: true, reciprocal: false})

##### Mask an image using values in another image

`JS9.MaskImage(image, opts)`

Calling sequences:

        JS9.MaskImage()                   # return current mask params
        JS9.MaskImage(true||false)        # turn on/off masking
        JS9.MaskImage(image, opts)        # set mask and optionally, its params
        JS9.MaskImage(opts)               # set mask params

where:

- image: image handle or image id to use as a mask
- opts: optional mask properties

and where the mask properties are:

- mode: "mask", "opacity", or "overlay"
- value: mask value that triggers masking (def: 0) for "mask" mode
- invert: whether to invert the mask (def: false) for "mask" mode
- sync: true or false for "overlay" mode
- opacity: opacity to use when masking (def: 0, range 0 to 1) for "mask" and "overlay" mode

The pixel values in one image can be used to mask the pixels in another image if the two images have the same image dimensions. The type of masking depends on the mode: "overlay" (default) or "mask".

For "mask" mode, if the value of a pixel in the mask is less than or equal to the value property, the opacity of the displayed pixel is set to the opacity property. You can also invert the mask using the invert property. In effect, this mode displays only the image pixels "covered" by a mask.

For "opacity" mode, each image pixel is assigned an opacity equal to the value of the mask pixel (whose values are assumed to range from 0 to 1.)

For "overlay" mode, if the mask pixel has a non-zero alpha, its color is blended with the image pixel using source-atop composition. Otherwise, the image pixel color alone is used in the display. This is one way you can display a mask overlay on top of an image. A static colormap is usually used in conjunction with an overlay mask, since pixel values not explicitly assigned a color are transparent. Note that, when blending a mask and image pixel, the global mask opacity and the individual pixel opacity are multiplied to get the final pixel opacity. If "sync" is not explicitly false, this mode will call JS9.SyncImages() to keep the mask and image file in sync. The maskOpts property sync contains the array of operations to sync.

To set up a mask initially, call the routine with an already-loaded mask image as the first parameter, and an optional opts object as the second parameter:

        # default is "overlay"
        JS9.ImageMask("casa_mask.fits");
        JS9.ImageMask("casa_mask.fits", {mode: "overlay"});

        # "mask" mode: set lower threshold for masking and masked opacity
        JS9.ImageMask("casa_mask.fits", {mode: "mask", value: 5, opacity: 0.2});

You can change the mask parameters at any time:

        JS9.ImageMask({value: 2, opacity: 0});

or temporarily turn off and on the mask:

        JS9.ImageMask(false);
        ...
        JS9.ImageMask(true);

##### Clear the image from the display and mark resources for release

`JS9.CloseImage(opts)`

where:

- opts: optional object or JSON string containing image parameters

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 and happens when it happens.

The optional first argument is an opts object (or a JSON-formatted string) containing:

- clear: if explicitly set to false, the image will not be cleared

The clear option is useful if you are repeatedly loading the same image and want to avoid the image blink associated with the clear.

##### Get the image colormap

`cmap = JS9.GetColormap()`

returns:

- cmap: object containing colormap information

The returned cmap object will contain the following properties:

- colormap: colormap name
- contrast: contrast value (range: 0 to 10)
- bias: bias value (range 0 to 1)

##### Set the image colormap

`JS9.SetColormap(colormap, [contrast, bias])` Calling sequences:

        JS9.SetColormap(colormap)
        JS9.SetColormap(colormap, contrast, bias)
        JS9.SetColormap(colormap, staticOpts)
        JS9.SetColormap(contrast, bias)
        JS9.SetColormap(staticOpts)

where:

- colormap: colormap name
- contrast: contrast value (range: 0 to 10)
- bias: bias value (range 0 to 1)
- staticOpts: static colormap opts

Set the current colormap, contrast/bias, or both. This call takes one (colormap), two (contrast, bias) or three (colormap, contrast, bias) arguments. It also takes the following single arguments:

- rgb: toggle RGB mode
- invert: toggle inversion of the colormap
- overlay: toggle image overlay mode (PNG and JPEG files only)
- reset: reset contrast, bias, and invert values
- staticOpts: opts for a static colormap

The staticOpts argument is an array of parameters to change in a static colormap. Each parameter can take one of two forms:

- [color, min, max]
- [color, opacity|alpha]
- [color, true|false]

The color parameter must match one of the colors specified when the static colormap was created. The min and max properties replace the originally specified min and max values. Specifying a number between 0 and 1 (inclusive) will change the opacity, while specifying a number greater than 1 will change the alpha (i.e., opacity * 255.) Specifying true or false will set or unset the active flag for that color, i.e. it will turn on or off use of that color. When turned off, the pixels in that range will be transparent. For example:

      SetColormap([["red", 0.5], ["green", true], ["blue", false]]);

sets the opacity of red pixels to 0.5, turns on the green pixels, and turns off the blue pixels in the currently active static colormap.

Finally, note that PNG and JPEG images have a "private" colormap associated with them, which is an approximation of the original colors used in these images. You can set this colormap by specifying "private":

      SetColormap("private");

This private colormap is static: you cannot change contrast and bias. It also cannot be modified using staticOpts because there is no color string value associated with each entry in the colormap.

##### Save colormap(s)

`JS9.SaveColormap(fname, cmapArray)`

Calling sequences:

        JS9.SaveColormap()                 # save current colormap to "js9.cmap"
        JS9.SaveColormap(fname)            # save current colormap to fname
        JS9.SaveColormap(cmapArray)        # save array of colormaps to "js9.cmap"
        JS9.SaveColormap(fname, cmapArray) # save array of colormaps to fname

where:

- fname: output file name
- cmapArray: optional array of colormap names to save

As shown by the calling sequences above, you can use this routine to save either the current colormap or a list of colormaps taken from the specified array. You also can choose to save to a particular filename or the default "js9.cmap":

      # save the current colormap in js9.cmap
      JS9.SaveColormap()
      # save the current colormap in foo.cmap
      JS9.SaveColormap("foo.cmap")
      # save the foo1 and foo2 colormaps in js9.cmap
      JS9.SaveColormap(["foo1", "foo2"])
      # save the user-defined foo1 and foo2 colormaps in foo.cmap
      JS9.SaveColormap("foo.cmap", ["foo1", "foo2"])

The colormaps are saved in JSON format. Multiple saved colormaps will be stored in a JSON array, while a single saved colormap will be saved at the top level.

Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.

##### Add a colormap to JS9

`JS9.AddColormap(name, aa|rr,gg,bb|ss|obj|json, opts)`

where:

- name: colormap name
- aa: an array containing RGB color triplets
- rr,gg,bb: 3 arrays of vertices specifying color changes
- ss: an array static color assignments
- obj: object containing one of the three colormap definition formats
- json: JSON string containing one of the colormap definition formats
- opts: optional object to set toplevel property to false

You can add new colormaps to JS9 using one of three formats. The first is an array of RGB triplets (i.e., an array of 3-D arrays), where each triplet defines a color. The elements of the colormap are divided evenly between these 3-D triplets. For example, the i8 colormap is defined as:

        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.

The third colormap format consists of an array of color and pixel range specifications: color, min, max. This defines a static colormap in which colors are assigned based on whether an image pixel is within a range. For example:

      JS9.AddColormap("mask",
                      [["#ff000080", 1, 31],
    		   ["cyan", 32, 32],
    		   ["rgba(0,255,0,0.5)", 37, 99],
    		   ["blue", 100, Infinity]]);

Image pixel values between 1 and 31 (inclusive) are assigned a red color (#ff0000) with an opacity of approximately 0.5. The image pixel value 32 is assigned the color cyan. Image pixel values between 37 and 99 are assigned the color green with opacity 0.5. All image pixel values greater than or equal to 100 are blue. (You can also specify the string "Infinity".) If an image pixel value is not within any range, it is assigned the color specified by JS9.imageOpts.nocolor. By default, this is black with an opacity of 0, so nothing is displayed at all (you'll probably see the default grey background of the JS9 display element.) Static colormaps are mostly used as image masks. See JS9.MaskImage() for more information.

Note the different ways in which colors can be specified: more information about accepted color formats is available on the TinyColor website.

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]]]}

The colormap will be added to the toplevel of the Colormap menu, unless you pass a final opts argument that sets the toplevel property to false:

      JS9.AddColormap("cyan", [[0,0],[0,0]], [[0,0],[1,1]], [[0,0],[1,1]], {toplevel:false});

Finally, note that JS9.AddColormap() adds its new colormap to all JS9 displays on the given page.

##### Load a colormap file into JS9

`JS9.LoadColormap(filename, opts)`

where:

- filename: input file name or URL
- opts: optional object to set toplevel property to false

Load the specified colormap file into the web page. The filename, which must be specified, can be a local file (with absolute path or a path relative to the displayed web page) or a URL. It should contain a JSON representation of a colormap (or an array of colormaps), either in RGB color format or in vertex format (see JS9.AddColormap() above):

        # RGB color format
        {
          "name": "purplish",
          "colors": [
    	[0.196, 0.196, 0.196],
    	[0.475, 0, 0.608],
    	[0, 0, 0.785],
    	[0.373, 0.655, 0.925],
    	[0, 0.596, 0],
    	[0, 0.965, 0],
    	[1, 1, 0],
    	[1, 0.694, 0],
    	[1, 0, 0]
          ]
        }

        # vertex format
        {
          "name": "aips0",
          "vertices": [
    	[
    	    [0.203, 0],
    	    [0.236, 0.245],
    	    [0.282, 0.5],
    	    [0.342, 0.706],
    	    [0.411, 0.882],
    	    [0.497, 1]
    	],
    	[
    	    [0.394, 0],
    	    [0.411, 0.196],
    	    [0.464, 0.48],
    	    [0.526, 0.696],
    	    [0.593, 0.882],
    	    [0.673, 1],
    	    [0.94, 1],
    	    [0.94, 0]
    	],
    	[
    	    [0.091, 0],
    	    [0.091, 0.373],
    	    [0.262, 1],
    	    [0.94, 1],
    	    [0.94, 0]
    	]
          ]
        }

The colormap will be added to the toplevel of the Colormap menu, unless you pass a final opts argument that sets the toplevel property to false:

      JS9.LoadColormap("secondary.cmap", {toplevel:false});

As with JS9.AddColormap(), the new colormap will be available in all displays.

##### Get RGB Mode for this display

`JS9.GetRGBMode()`

returns:

- obj: object containing RGB mode information

The returned object will contain the following properties:

- active: boolean specifying whether RGB mode is active
- rid: image id of "red" image
- gid: image id of "green" image
- bid: image id of "blue" image

##### Set RGB Mode for this display

`JS9.SetRGBMode(mode, [imobj])`

where:

- mode: boolean true to activate RGB mode, false to disable
- imobj: optional object specifying three images to set to the "red", "green", and "blue" colormaps

In RGB mode, three images assigned the "red", "green", and "blue" colormaps are displayed as a single image. The RGB color of each displayed pixel is a combination of the "red", "green", and "blue" pixel value taken from the appropriate image. Note that all three images are not required: you can display an RGB image using two of the three colors simply by not assigning the third colormap.

The JS9.SetRGBMode() call turns on or off RGB mode. The boolean mode argument specifies whether to activate or de-activate RGB mode. The optional imobj object specifies (already-loaded) images to assign to the three colormaps:

- rid: image id (or handle) to set to the "red" colormap
- gid: image id (or handle) to set to the "green" colormap
- bid: image id (or handle) to set to the "blue" colormap

If imobj is not specified, it is assumed that images have been assigned the "red", "green", and "blue" colormaps by another means. (Once again, it is not necessary to assign all three colormaps.)

If no arguments are specified, the current RGB mode is toggled;

##### Get the image scale

`scale = JS9.GetScale()`

returns:

- scale: object containing scale information

The returned scale object will contain the following properties:

- scale: scale name
- scalemin: min value for scaling
- scalemax: max value for scaling

##### Get the image opacity

`opacity = JS9.GetOpacity()`

returns:

- opacity: object containing opacity information

The returned opacity object will contain the following properties:

- opacity: opacity value assigned to image pixels
- flooropacity: opacity assigned when the image pixel value is less than or equal to the floor value (if defined)
- floorvalue: floor value to test image pixel values against (if defined)

##### Set the image opacity

`JS9.SetOpacity(opacity, floorvalue, flooropacity)`

calling sequences:

        JS9.SetOpacity(opacity)      # set def opacity for all image pixels
        JS9.SetOpacity(floorvalue, flooropacity) # pixels <= floorvalue get flooropacity
        JS9.SetOpacity(opacity, floorvalue, flooropacity)  # set def and floor opacity
        JS9.SetOpacity("reset")      # reset def opacity to 1
        JS9.SetOpacity("resetfloor") # remove opacity floor
        JS9.SetOpacity("resetall")   # reset def opacity to 1, remove floor opacity

where:

- opacity: opacity value for image pixels
- floorvalue: floor value to test image pixel values against
- flooropacity: floor opacity value to set if image pixel value is less than or equal to the floor opacity value

Set the current opacity, floor opacity, or both. This call takes one (opacity), two (floorvalue, flooropacity) or three (opacity, floorvalue, flooropacity) arguments.

The floor value & opacity option allows you to set the opacity for pixels whose image value is less then or equal to a specified floor value. It takes two arguments: the floor pixel value to check, and the floor opacity to apply. For example, when both arguments are 0, pixels whose image values are less than or equal to 0 will be transparent. Specifying 5 and 0.5, respectively, means that pixels whose image values less than or equal to 5 will have an opacity of 0.5. A useful case is to make the pixels transparent at a given value, allowing features of one image to be blended into another, without blending extraneous pixels.

The various reset options allow you to reset the default value, floor values, or both.

##### Set the image scale

`JS9.SetScale(scale, smin, smax)`

where:

- scale: scale name, "zscale", "zmax", or "dataminmax"
- smin: scale min value
- smax: scale max value

Set the current scale, min/max, or both. This call takes one (scale), two (smin, max) or three (scale, smin, smax) arguments. (If "zscale" or "zmax" is specified, any supplied smin and smax values are ignored.)

##### Get the image zoom factor

`zoom = JS9.GetZoom()`

returns:

- zoom: floating point zoom factor

Get the zoom factor.

##### Set the image zoom factor

`JS9.SetZoom(zoom)`

where:

- zoom: floating or integer zoom factor or zoom directive string

The zoom directives are:

- x[n]|X[n]|*[n]: multiply the current zoom by n (e.g., "x2")
- /[n]: divide the current zoom by n (e.g., "/2")
- in|In: multiply the current zoom by 2
- out|Out: divide the current zoom by 2
- toFit|ToFit: zoom to fit image in display

##### Get the image pan position

`ipos = JS9.GetPan()`

returns:

- ipos: object containing image information for pan

The returned ipos object will contain the following properties:

- x: calculated (from section) x image coordinate of center
- y: calculated (from section) y image coordinate of center
- ox: original (input) x image coordinate of center
- oy: original (input) y image coordinate of center
- x0: x start of image section
- y0: y start of image section
- x1: x end of image section
- y1: y end of image section
- ix: x offset of center from center of display
- iy: y offset of center from center of display

Note that the x and y values are the center of the image section, which might be different from the input x and y values passed JS9.SetPan(). The latter are returned as ox and oy. The image section parameters are also returned. Finally, the ix and iy values will be non-zero in cases of unconstrained, off-centered panning.

##### Set the image pan position

`JS9.SetPan(x, y)`

where:

- x: x image coordinate (or an object containing a position)
- y: y image coordinate

Set the current pan position using image coordinates. Note that you can use JS9.WCSToPix() and JS9.PixToWCS() to convert between image and WCS coordinates.

An object can also be supplied with a position specified in image, physical, or WCS coordinates:

- x: image x position
- y: image y position
- px: physical x position
- py: physical y position
- ra: RA in degrees
- dec: Dec in degrees
- wcs: sexagesimal WCS string with optional WCS system

For example:

        JS9.SetPan({wcs: "23:23:28.895 +58:49:43.50 ICRS"});

will set the pan position to the specified RA and Dec using the ICRS system. Note that the WCS string above is returned by the Edit menu's "copy wcs pos" option (i.e., the "/" keystroke.)

Finally, if you pass the string "mouse" as the sole argument, the image is panned to the current mouse position. This is especially useful in conjunction with keyboard shortcuts (where currently the "m" key uses this routine to pan to the current mouse position.)

By default, panning is unconstrained: you can pan the image so that some (or even all) of the display does not contain image data (e.g., if you pan an image to point 0,0, the image origin will be the center of the display and only the upper right quadrant will contain data.) If you want to avoid blank areas in the display, set the JS9.globalOpts.panWithinDisplay property to true. Site authors can change this property in js9prefs.js, while users can change this via the Global tab of the Preferences plugin.

##### Align pan and zoom of the current image to a target image

`JS9.AlignPanZoom(im, opts)`

where:

- im: target image containing the WCS used to perform the alignment
- opts: optional object

This routine changes the pan and zoom of the current image to match a target image. By default, it is assumed that both have WCS info available. The image is panned to the RA, Dec at the center of the target image's display. The zoom is also matched. The pixel size (as specified by the FITS CDELT1 parameter) will be taken into account when zooming, but not the image rotation or flip. This routine is faster than JS9.ReprojectData() for aligning reasonably similar images.

For specialized needs, you can set the syncwcs property to false in the opts object so that WCS will not be used in the alignment. Instead, the image will be panned to the target's current center (in image coordinates) and the image zoom will be set to the target's zoom. Obviously, this assumes identical image dimensions and pixel sizes. It can be useful when working with lab data and simulations.

No attempt is make to keep the images aligned after the call. This allows you to make adjustments to the current and/or target images and then re-align as needed.

##### Flip an image around the x or y axis

`JS9.SetFlip(flip)`

where:

- flip: "x", "y"

Flip an image around the specified axis. Flipping is relative to the current state of the display, so flipping by x twice will return you to the original orientation.

Since this operation is applied to the entire display canvas instead of the image, image parameters such as the WCS are not affected.

##### Get flip state of an image

`flip = JS9.GetFlip()`

returns:

- flip: the current flip state

Possible returned flip states are: "x", "y", "xy", or "none". The state is normalized, so that, for example, two "x" flips are replaced by "none".

##### Rotate an image by a specified number of degrees

`JS9.SetRotate(rot)`

where:

- rot: rotation in degrees

Set the rotation of an image to the specified number of degrees. The rotation is performed in terms of an absolute angle: if you rotate by 20 degrees and then do it again, there is no change. Also, setting the rotation to 0 sets the angle to 0.

In the rotation argument is the string "north" or "northisup", the rotation angle is calculated so that north is up in the current coordinate system.

Since this operation is applied to the entire display canvas instead of the image, image parameters such as the WCS are not affected.

##### Get rotate state of an image

`rot = JS9.GetRotate()`

returns:

- rot: current rotation value for this image

Return the current rotation.

##### Rotate an image by +/- 90 degrees

`JS9.SetRot90(rot90)`

where:

- rot90: a multiple of 90 degrees (+/-90)

Rotate an image by a multiple of 90 degrees. Rot90 rotations are relative to the current state of the display, so four rotations will return you to the original orientation.

Since this operation is applied to the entire display canvas instead of the image, image parameters such as the WCS are not affected.

##### Get rotate state of an image

`rot = JS9.GetRot90()`

returns:

- rot: current rotation value for this image

The returned rotation value will be a multiple of 90, depending on how many rotations have been executed and in which direction.

##### Get an image parameter value

`val = JS9.GetParam(param)`

where:

- param: name of the parameter or "all"

returns:

- val: value of the parameter

Return the value of an image parameter. The available parameters are listed below in the JS9.SetParam() section.

In the value of param is "all", the entire param object is returned.

##### Set an image parameter value

`ovalue = JS9.SetParam(param, value)`

where:

- param: name of the parameter or "all"
- val: new value of the parameter or param object to merge

returns:

- ovalue: the previous value of the parameter or the new param object

A number of miscellaneous image parameters are copied from the JS9.imageOpts object to each image when it is first loaded. You can use the JS9.SetParam() routine to modify these values subsequently. The available parameters and their current default values are listed below:

- exp: 1000, default exp value for scaling
- disable: which core services to disable for this image
- listonchange: false, list regions after a region change?
- opacity: 1.0, image display opacity, between 0 and 1
- overlay: whether PNG/JPEG display the image instead of using cmaps
- nancolor: "#000000", 6-digit #hex color for NaN values
- valpos: true, display value/position?
- wcsalign: true, align image using WCS after reproj?
- xeqonchange: true, xeq an onchange callback after a region change?
- zscalecontrast: 0.25, default zscale value from ds9
- zscalesamples: 600, default zscale value from ds9
- zscaleline: 120, default zscale value from ds9

In addition, you can set the internal values associated with core functionality ("colormap", "pan", "regions", "scale", "wcs", or "zoom") and the corresponding core function will be called. The core parameters that can be set in this way are:

- colormap: calls JS9.SetColormap()
- contrast: calls JS9.SetColormap()
- bias: calls JS9.SetColormap()
- flip: calls JS9.SetFlip()
- rot90: calls JS9.SetRot90()
- rot: calls JS9.SetRotate()
- scale: calls JS9.SetScale()
- scalemin: calls JS9.SetScale()
- scalemax: calls JS9.SetScale()
- scaleclipping: calls JS9.SetScale()
- wcssys: calls JS9.SetWCSSys()
- wcsunits: calls JS9.SetWCSUnits()
- zoom: calls JS9.SetZoom()

The routine returns the previous value of the parameter, which can be useful when temporarily turning off a function. For example:

        oval = JS9.SetParam("xeqonchange", false);
        .... processing ...
        JS9.SetParam("xeqonchange", oval);

will temporarily disable execution of the previously defined regions onload callback, resetting it to the old value after processing is complete.

If param is "all" and the second argument is an object, this object is merged into the current param object. This allows you to save the params from one image and restore them to another. If the object contains internal core parameters (see above), the corresponding core function will be called.

If param is "disable", the specified value (or array of values) is added to the disable array for this image, thereby disabling core functionality. The resulting disable array is returned. Thus, for example:

        JS9.SetParam("disable", ["zoom", "pan"]);

will disable zoom and pan functionality for this image. Note that disabling regions means that you cannot create new regions, but you can still change and even remove existing regions.

If param is "enable", the specified value (or array of values) is removed to the disable array for this image, thereby enabling core functionality. The resulting disable array is returned.

##### Copy image parameter(s) to one or more images

`JS9.CopyParams(param, image, opts)`

where:

- param: name of the parameter or array or parameters to copy
- image: target image or array of image to copy to
- opts: optional object

Copy parameters from the current image to one or more images. Any image parameter can be copied, but the most common ones are: "alignment", "colormap", "contrastbias" (i.e., both "contrast" and "bias"), "flip", "pan", "rot90", "rotate", "scale", "wcs" (i.e., both "wcssys" and "wcsunits"), and "zoom". Note that copying a parameter results in JS9.SetParam() being called, triggering the corresponding core function if necessary. Thus, for example, copying the colormap will change the colormap of the target image. See JS9.SetParam() for more details about setting parameters.

Regions calls the JS9.CopyRegions() routine. Alignment calls JS9.AlignPanZoom() in order to keep the pixel size and displayed center position constant between the sync'ed images. It assumes no rotation between the two images. Finally, you can also copy "shapes", which calls the JS9.CopyShapes() routine. In the latter case, you will need to pass the shape layer name in the layer property of the opts argument.

The target image(s) to copy to can be specified singly or as an array of image handles or image ids. If no images are specified, all images are used as targets.

##### Get the display coordinates from an event

`dpos = JS9.EventToDisplayPos(evt)`

where:

- evt: a JavaScript or jQuery event

returns:

- dpos: display position object containing 0-indexed x and y display coordinate values

If you define your own event callbacks, you can use this routine to convert the event position to a display position, which can then be used to get the image position (see below.)

##### Get the image coordinates from the display coordinates

`ipos = JS9.DisplayToImagePos(dpos)`

where:

- dpos: display position object containing 0-indexed x and y display coordinate values

returns:

- ipos: image position object containing 1-indexed x and y image coordinate values

Note that image coordinates are one-indexed, as per FITS conventions, while display coordinate are 0-indexed.

##### Get the display coordinates from the image coordinates

`dpos = JS9.ImageToDisplayPos(ipos)`

where:

- ipos: image position object containing 1-indexed x and y image coordinate values

returns:

- dpos: display position object containing 0-indexed x and y display coordinate values

Get display (screen) coordinates from image coordinates. Note that image coordinates are one-indexed, as per FITS conventions, while display coordinate are 0-indexed.

##### Get the image coordinates from the logical coordinates

`ipos = JS9.LogicalToImagePos(lpos, lcs)`

where:

- lpos: logical position object containing 1-indexed x and y logical coordinate values

returns:

- ipos: image position object containing 1-indexed x and y image coordinate values

Logical coordinate systems include: "physical" (defined by LTM/LTV keywords in a FITS header), "detector" (DTM/DTV keywords), and "amplifier" (ATM/ATV keywords.) Physical coordinates are the most common. In the world of X-ray astronomy, they refer to the "zoom 1" coordinates of the data file.

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:

- ipos: image position object containing 1-indexed x and y image coordinate values

returns:

- lpos: logical position object containing 1-indexed x and y logical coordinate values

Logical coordinate systems include: "physical" (defined by LTM/LTV keywords in a FITS header), "detector" (DTM/DTV keywords), and "amplifier" (ATM/ATV keywords.) Physical coordinates are the most common. In the world of X-ray astronomy, they refer to the "zoom 1" coordinates of the data file.

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:

- ipos: image position object containing 1-indexed x and y image coord values
- display: boolean value specifying whether the info box display should be updated (default is true)

returns:

- valpos: value/position object

This routine determines the data value at a given image position and returns an object containing the following information:

- ix: image x coordinate
- iy: image y coordinate
- isys: image system (i.e., "image")
- px: physical x coordinate
- py: physical y coordinate
- psys: currently selected pixel-based system (i.e., "image" or "physical") for the above px, py values
- ra: ra in degrees (if WCS is available)
- dec: dec in degrees (if WCS is available)
- wcssys: wcs system (if WCS is available)
- val: floating point pixel value
- val3: pixel value as a string truncated to 3 decimal digits
- vstr: string containing value and position info
- id: id of the image
- file: filename of the image
- object: object name of the image from the FITS header

##### Set the value/position display mode

`JS9.SetValPos(mode)`

where:

- mode: true (show valpos display) or false (hide valpos display)

Set the display mode of the value/position display for the specified image.

##### Get the image inherit mode

`inherit = JS9.GetImageInherit()`

returns:

- inherit: true if new image inherits params from current image

The JS9.GetImageInherit() routine returns a boolean specifying whether a new image grabs the image params (e.g., colormap, scale, zoom, etc.) from the currently displayed image. If false, these params are taken from the default JS9.imageOpts object.

##### Set the image inherit mode

`JS9.SetImageInherit(mode)`

where:

- mode: true (inherit params from currently displayed image) or false

The JS9.SetImageInherit() routine specifies whether a new image grabs the image params (e.g., colormap, scale, zoom, etc.) from the currently displayed image. If false, these params are taken from the default JS9.imageOpts object.

##### Get information about the current WCS

`wcsobj = JS9.GetWCS()`

returns:

- wcsobj: object containing WCS info

Get information about the current WCS, including:

- version: the WCS version ("default" or the letter "A"-"Z" for an alternate WCS)
- wcsname: the value of the WCSNAME header parameter associated with this WCS, if present
- crot: crot value (i.e., the CROT1 value) from WCS library
- crpix[1,2]: crpix values from WCS library
- crval[1,2]: crval values from WCS library
- crdelt[1,2]: crdelt values from WCS library
- crtype[1,2]: crtype values (e.g., "RA" and "Dec") from WCS library
- ptype: ptype value (e.g., "TAN") from WCS library
- radecsys: radecsys value (e.g., "ICRS") from the WCS library

##### Set the current WCS

`JS9.SetWCS(which)`

where:

- which: WCS name or id

Set the current WCS, in cases where alternate WCS's are available. The alternate WCS convention is described in the standard paper by Greisen and Callebretta Representations of world coordinates in FITS (A&A 395, 1061–1075 (2002).) If a FITS file contains alternate WCS info, you can switch to an alternate using this routine or using the File->alternate wcs menu option.

The which argument can be one of the following:

- default: the default WCS from the original file
- [version]: the version letter of the alternate WCS, i.e., A-Z
- [wcsname]: the value of the WCSNAME header parameter associated with this WCS, if present

If no argument is supplied, the default WCS is set up.

##### Get the current WCS units

`unitsstr = JS9.GetWCSUnits()`

returns:

- unitstr: "pixels", "degrees" or "sexagesimal"

Get the current WCS units.

##### Set the current WCS units

`JS9.SetWCSUnits(unitsstr)`

where:

- unitstr: "pixels", "degrees" or "sexagesimal"

Set the current WCS units.

##### Get the current World Coordinate System

`sysstr = JS9.GetWCSSys()`

returns:

- sysstr: current World Coordinate System ("FK4", "FK5", "ICRS", "galactic", "ecliptic", "image", or "physical");

Get current WCS system.

##### Set the current World Coordinate System

`JS9.SetWCSSys(sysstr)`

where:

- sysstr: World Coordinate System ("FK4", "FK5", "ICRS", "galactic", "ecliptic", "image", or "physical")

Set current WCS system. The WCS systems are available only if WCS information is contained in the FITS header. Also note that "physical" coordinates are the coordinates tied to the original file. They are mainly used in X-ray astronomy where individually detected photon events are binned into an image, possibly using a blocking factor. For optical images, image and physical coordinate usually are identical.

##### Convert image pixel position to WCS position

`wcsobj = JS9.PixToWCS(x, y)`

where:

- x: x image coordinate (or object containing x and y properties)
- y: y image coordinate

returns:

- wcsobj: world coordinate system object

The returned WCS object contains the following properties:

- ra: right ascension in floating point degrees
- dec: declination in floating point degrees
- sys: current world coordinate system being used
- str: string of WCS in current system ("[ra] [dec] [sys]")

You can either supply the x and y image coordinates as two numeric arguments, or supply a single object containing numeric x and y properties.

##### Convert WCS position to image pixel position

`pixobj = JS9.WCSToPix(ra, dec)`

where:

- ra: right ascension in floating point degrees (or object containing ra and dec properties)
- dec: declination in floating point degrees

returns:

- pixobj: pixel object

The returned pixel object contains the following properties:

- x: x image coordinate
- y: y image coordinate
- str: string of pixel values ("[x]" "[y]")

You can either supply the RA and Dec as two numeric arguments, or supply a single object containing numeric ra and dec properties.

##### Display a text message

`JS9.DisplayMessage(which, text)`

where:

- which: "info" or "regions"
- text: text to display

The text string is displayed in the "info" area (usually occupied by the valpos display) or the "region" area (where regions are displayed.) The empty string will clear the previous message.

##### Display a WCS-based coordinate grid

`JS9.DisplayCoordGrid(mode, opts)`

where:

- mode: true (display) or false (hide)
- opts: optional object or JSON string containing grid parameters

A coordinate grid displays lines of constant RA and constant Dec, with the points of intersection labeled by their RA and Dec values. The labels are in sexagesimal notation if the WCS units are sexagesimal, otherwise they are in degrees. When using sexagesimal notation, labels will be shortened if possible, e.g., if the RA hours are the same in two successive labels but the minutes are different, only the minutes are shown in the second label.

If no arguments are supplied, the routine returns true if the coordinate grid is currently being displayed, false otherwise. A boolean first argument specifies whether to display the coordinate grid or not.

The optional second argument is an opts object (or a JSON-formatted string) containing properties to override the default JS9.Grid.opts properties. These properties include:

- strokeWidth: grid stroke width
- lineColor: color of RA and Dec grid lines
- raLines: approx. number of RA grid lines
- raAngle: rotation for RA label
- raSkip: number of RA lines to skip
- decLines: approx. number of Dec grid lines
- decAngle: rotation for Dec label
- decSkip: number of Dec lines to skip
- labelColor: color of text labels
- labelFontFamily: label font
- labelFontSize: label font size
- labelFontStyle: label font style
- labelFontWeight: label font weight
- labelRAOffx: x offset of RA labels
- labelRAOffy: y offset of RA labels
- labelDecOffx: x offset of Dec labels
- labelDecOffy: y offset of Dec labels
- degPrec: precision for degree labels
- sexaPrec: precision for sexagesimal labels
- reduceDims: reduce lines of smaller image dim?
- stride: fineness of grid lines
- margin: edge margin for displaying a line
- labelMargin: edge margin for displaying RA, Dec label
- cover: grid lines cover: display or image

The strokeWidth property determines the width of the grid lines. It also serves as a reminder that you can pass other standard shape properties in the opts object.

JS9's label placement algorithm puts labels close to the intersection of RA and Dec lines. A number of properties can be useful in cases where this simple algorithm is not sufficient: the raAngle and decAngle properties allow you to rotate the labels with respect to the grid lines. The four label[RA,Dec]Off[x,y] properties allow you to move the label with respect to the grid lines. The raSkip and decSkip properties allow you to skip labelling the first available lines within the display. It can be useful, for example, on a rotated image, when the labels are placed in a corner.

The degPrec and sexaPrec properties specify the precision for degree values and sexagesimal values, respectively. Higher precision will use more digits and take more space along each line.

A number of properties are (more or less) internal but might be of use: the reduceDims property will reduce the raLines and decLines properties by the ratio of image dimensions if one dimension is smaller than the other. This can prevent crowding in the smaller dimension. The stride property specifies the length of each line segment that together make up a grid line. A smaller stride might make the grid lines smoother in some cases, at the price of more processing time. The cover property determines whether the grid is drawn over the entire image or just the displayed part of the image. At the moment, drawing lines over the displayed part of the image seems to be sufficient.

Note that you can specify global site-wide values for all these parameters (overriding the JS9.Grid.opts defaults) by supplying them in a grid object within the globalOpts object in the js9prefs.js file.

Example: display a coordinate grid, specifying the line color:

        JS9.DisplayCoordGrid(true, {lineColor: "pink"});

##### Get background-subtracted counts in regions

`JS9.CountsInRegions(sregion, bregion, opts)`

where:

- sregion: any source region, or "$sregions" for displayed source regions
- bregion: any background region, or "$bregions" for displayed background regions
- opts: optional object or JSON string containing region parameters

The regcnts program (and its predecessor, funcnts) counts photons in specified source regions and optionally, in specified background regions. Displayed results include the bkgd-subtracted counts in each region, as well as the error on the counts, the area in each region, and the surface brightness (cnts/area**2) calculated for each region. Regcnts for desktop use is available on GitHub.

The regcnts program has been compiled into JS9 using Emscripten. Using this routine, it can be run on the FITS file stored in memory for the currently displayed image. The first two arguments specify the source region(s) and background region(s), respectively. You can pass a standard region specifier as the source or background region:

        JS9.CountsInRegions('ICRS; circle(23:23:18.76, +58:47:27.25, 31.8")');

If the string "$sregions" ("$bregions") is specified, the source (background) regions are taken from the currently displayed image. You also can specify a region selector using a regions selection string. For example:

        # all regions
        JS9.CountsInRegions('all');
        # selected regions
        JS9.CountsInRegions('selected');
        # regions tagged with the "foo" tag
        JS9.CountsInRegions('foo');

Note that if you pass a region selector and no regions are returned, the routine will throw an error. Also note that, in this context, text and cross regions not valid regions (and are ignored).

In keeping with how desktop regcnts works, if no argument or null or a null string is specified as the source region, the entire field is used as the source region. If no argument or null or a null string is explicitly specified as a background region, no regions are used for the background. In particular, if you pass only the source region argument, or pass only the source region and opts arguments, no background region is used. To recap:

        # use entire field, no background
        JS9.CountsInRegions([opts])
        JS9.CountsInRegions("field"||null||""[, opts])

        # use displayed source and displayed background
        JS9.CountsInRegions("$sregions", "$bregions"[, opts])

        # use displayed source, no background
        JS9.CountsInRegions("$sregions"[, opts])

        # use displayed source and specified background
        JS9.CountsInRegions("$sregions", bregions[, opts])

        # use specified source, no background
        JS9.CountsInRegions(sregions[, opts])

        # use specified source and specified background
        JS9.CountsInRegions(sregions, bregions[, opts])

        # use specified source and displayed background
        JS9.CountsInRegions(sregions, "$bregions"[, opts])

       # use entire field and specified background
        JS9.CountsInRegions("field"||null||"", bregions[, opts])

        # use entire field and displayed background
        JS9.CountsInRegions("field"||null||"", "$bregions"[, opts])

The third argument allows you to specify options to regcnts:

- cmdswitches: command line switches passed to regcnts
- dim: size of reduced image (def: max of JS9.globalOpts.image.[xdim,ydim])
- reduce: reduce image size? (def: true)
- lightwin: if true, results are displayed in a light window

The command line switches that can be specified in cmdswitches are detailed in the regcnts help page. Aside from switches which control important aspects of the analysis, the "-j" switch (which returns the output in JSON format) might be useful in the browser environment. Some examples:

        # display results in a light window
        JS9.CountsInRegions({lightwin: true})

        # return JSON using maximum precision in output
        JS9.CountsInRegions({cmdswitches: "-j -G"})

Results are also returned as a text string.

The regcnts code is memory (and cpu) intensive. In the desktop environment, this is not typically a problem, but the memory-constrained browser environment can present a challenge for large images and binary tables. To avoid running out of memory (and for large images, to speed up processing considerably), the JS9.CountsInRegions() routine will bin the image to reduce its size, unless the reduce option is explicitly set to false. The binned image size can be specified by the dim option, defaulting to the global value of the image dimension options. When a file is binned in this manner, the returned resolution value (e.g., arcsec/pixel) will reflect the applied binning. Note that the number of photons found inside a binned and unbinned region differ slightly, due to the difference in the pixel boundaries in the two cases.

The Counts in Regions option of the Analysis -> Client-side Analysis menu runs regcnts on the source and background regions of the currently displayed image. The results are displayed in a light window.

Finally, note that the main JS9 web site also offers regcnts as a server-based analysis program in the Analysis menu. The displayed source and background regions are passed to the server for processing. Because this version runs the desktop program, it runs on the original file and does no binning to reduce the image size (which, by the way, could lengthen the processing time.) But the server-side task also can be useful for large file support, which involves displaying a small representation file associated with a much larger parent file stored on the server. In this case, you often want to run the analysis on the larger (original) file.

##### Generate a radial profile plot

`JS9.RadialProfile(sregion, bregion, opts)`

where:

- sregion: annulus region, or "$sregions" to use displayed annulus
- bregion: any background region, or "$bregions" for displayed background regions
- opts: optional object or JSON string containing region and plot parameters

The JS9.RadialProfile() routine uses JS9.CountsInRegions() to produce a radial profile plot. The source region argument should be an annulus region (or, when using "$sregions", the displayed source region should be an annulus.) The background region can be any region(s) (except text or cross regions), the same as for the counts routine.

The third argument allows you to specify options to the counts routine, as well as the following options for the radial profile plot:

- color: color of the plot line (default: "green")
- errorbars: show error bars? (default: true)
- errorcolor: color of the error bars (default: "red")

Note that "-j" (JSON format) and "-r" (output radii) are always added to the cmdswitches property (and should not be overridden.) This means you can retrieve the JSON output without generating the plot simply by calling JS9.CountsInRegions() directly:

        JS9.CountsInRegions(sregions, bregions, {cmdswitches: "-j -r"})

The return value is the id of the light window containing the plot.

##### Create or modify a raw data layer

`JS9.RawDataLayer(opts, func)`

where:

- opts: layer name or opts object
- func: function used to create or modify raw data

Each image has raw data associated with it, i.e., the underlying astronomical image pixels that are scaled and displayed using the chosen scale and colormap. You can manipulate the raw data by creating a new raw data layer using JS9.RawDataLayer(), setting the image pixel values, and then making this layer the current one. The original raw data (with id "raw0") will be maintained in separate layer, so you can switch between layers (also using this routine.)

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:

- rawid: id of new raw data layer (default: "alt")
- oraw: id of raw data layer to pass to func or "current" (default: "raw0", i.e., the original data)
- from: descriptive string describing origin of this raw data (def: "func")

Alternative, you can pass the id of the raw data layer as a string and use the defaults for the other properties (which usually is sufficient.)

The pixel modifying function should have the following calling sequence:

        func(oraw, nraw, opts)

where:

- oraw: the raw data object specified by the from property above (def: original raw data "raw0");
- nraw: the raw data layer you are modifying
- opts: the original opts object along with any params you add to it

The function should return true is you want to switch to the new layer and display it, or false to discard the new layer (in case of an error.)

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():

- width: x dimension of image
- height: y dimension of image
- bitpix: FITS bits/pixel of each image element (8 for unsigned char, 16, 32 for signed integer, -32 or -64 for float)
- header: JavaScript object containing FITS header values
- data: buffer containing raw data values

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 data

To get the currently displayed layer, call the routine with no arguments:

        JS9.RawDataLayer()         # returns "clip"

##### Gaussian blur of raw data

`JS9.GaussBlurData(sigma, opts)`

where:

- sigma: sigma of Gaussian function
- opts: options object

This routine creates a new raw data layer called "gaussBlur" in which the image pixel values are blurred using a Gaussian function with the specified sigma. The routine uses the fast Gaussian blur algorithm (approximating a full Gaussian blur with three passes of a box blur) described here.

See JS9.RawDataLayer() for more information about raw data layers.

##### Perform image arithmetic on raw data

`JS9.ImarithData(op, arg1, opts)`

where:

- op: image operation: "add", "sub", "mul", "div", "min", "max", and "reset"
- arg1: image handle, image id or numeric value
- opts: options object

The JS9.ImarithData() routine performs basic arithmetic (addition, subtraction, multiplication, division, minimum, maximum, average) between the currently displayed image and either another image or a constant value. The first op argument is a string, as detailed above. The second arg1 argument can be a numeric value or an image id. In the former case, the constant value is applied to each pixel in the image. In the latter case, the operation is performed between the corresponding pixels in the two images. For example:

        JS9.ImarithData("max", "foo.fits");

will make a new data layer of the currently displayed image, where each pixel is the larger value from that image and the foo.fits image (which can be in any display.)

This routine creates a new raw data layer called "imarith" containing the results of the operation. Successive calls to this routine are cumulative, so that you can build up a more complex operation from simple ones. For example:

        # foo.fits is displayed in the "myJS9" display
        var myim = JS9.GetImage({display: "myJS9"});
        JS9.ImarithData("max", myim);
        JS9.ImarithData("add", 2.718);

will make a new data layer where each pixel is the larger value from the two images, after which an approximation of the irrational number e is added to each pixel.

The special reset operation deletes the "imarith" raw data layer, allowing you to start afresh.

The bitpix value of the new "imarith" layer is chosen as follows:

- for operations between two images, bitpix the "larger" of the two images (where float is "larger" than int.)
- for operations between an image and a constant, bitpix of -32 (single float) is chosen unless the image itself has bitpix of -64, in which case the double float bitpix is chosen.

You can override the choice of bitpix by passing a bitpix property in the optional opts object.

Finally, note that the two images must have the same dimensions. We might be able to remove this restriction in the future, although it is unclear how one lines up images of different dimensions.

See JS9.RawDataLayer() for more information about raw data layers.

##### Shift raw data

`JS9.ShiftData(x, y, opts)`

where:

- x: number of pixels to shift in the x (width) direction
- y: number of pixels to shift in the y (height) direction
- opts: options object

This routine creates a new raw data layer called "shift" in which the pixels are shifted from the original image array by the specified amount in x and/or y. The results of successive shifts are cumulative. The routine is used by the Harvard-Smithsonian Center for Astrophysics MicroObservatory project interactively to align images that are only slightly offset from one another.

See JS9.RawDataLayer() for more information about raw data layers.

##### Reproject an image using a specified WCS

`JS9.ReprojectData(wcsim, opts)`

where:

- wcsim: image containing the WCS used to perform the reprojection
- opts: options object for raw data layer

JS9.ReprojectData() creates a new raw data layer (with default id of "reproject") in which the pixels are reprojected using the WCS from another image. The mProjectPP program from the Montage software suite is used to perform the reprojection. Please read the documentation on mProjectPP from the Montage web site, which includes this explanation:

        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.

These Montage programs have been compiled into JS9 using Emscripten.

The wcsim argument is an image id, image filename, or image object pointing to the WCS image. This is the image whose WCS will be used for the reprojection. Alternatively, if the wcsim argument is set to "all", the WCS from the currently displayed image will be used to reproject all other images in the display.

The opts object can contain the following reproject-specific properties:

- rawid: the id of the raw data layer to create (default: "reproject")
- cmdswitches: a string containing mProjectPP command line switches

The cmdswitches will be prepended to the mProjectPP command line. For example:

     {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.hdr

See 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. It also (at least currently) requires that the full reprojected image be displayed (so that the reprojected image can be properly aligned with the WCS image used in making the reprojection.) We therefore restrict the WCS image size to be less than or equal to JS9.globalOpts.image.xdim by JS9.globalOpts.image.ydim. If the WCS image exceeds this size, an error is thrown.

See JS9.RawDataLayer() for more information about raw data layers.

##### Rotate an image around the WCS CRPIX point

`JS9.RotateData(angle, opts)`

where:

- angle: rotation angle in degrees
- opts: options object

The JS9.RotateData() routine uses JS9.ReprojectData() to rotate image data by the specified angle (in degrees.) If the string "northup" or "northisup" is specified, the rotation angle is set to 0. By default, the rotation is performed about the WCS CRPIX1, CRPIX2 point. To rotate about the center of the currently displayed image, pass the opts.center property with a value of "current" or (globally) set the JS9.globalOpts.rotationCenter property to "current".

Note that this rotation is not accumulative (as is the case with the JS9.SetRotate() and JS9.SetRot90() routines), so calling JS9.RotateData() with an angle of 30 degrees followed by 45 degrees will result in a 45 degree rotation, not a 75 degree rotation.

The optional opts object is passed directly to the JS9.ReprojectData() routine. See JS9.ReprojectData() above for more information.

##### Apply a filter to the RGB image

`JS9.FilterRGBImage(filter, args)`

where:

- filter: name of image filter to apply to the RGB data
- args: filter-specific arguments, where applicable

In JS9, you can change the raw data (and hence the displayed image) using routines such as JS9.GaussBlurData() or the more general JS9.RawDataLayer(). You also can apply image processing techniques directly to the displayed RGB image without changing the underlying raw data, using this routine. The web has an overwhelming amount of information about image processing. A good technical article concerning the use of image filters with Javascript and the HTML5 canvas is available at: http://www.html5rocks.com/en/tutorials/canvas/imagefilters/

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:

- luminance():convert to greyscale using the CIE luminance: 0.2126*r + 0.7152*g + 0.0722*b
- greyscale():convert to greyscale using the standard greyscale: 0.3*r + 0.59*g + 0.11*b
- greyscaleAvg():convert to greyscale using averaging: (r+g+b) / 3
- brighten(val): add constant value to each pixel to change the brightness: [r + val, g + val, b + val]
- noise(v1, v2): add random noise: pixel += Math.floor((Math.random()*(v2-v1)) - v2), defaults are v1=-30, v2=30
- duotone("r"|"g"|"b"): remove a color by setting it to the avg of the two others: r=(g+b)/2, default color is "r"
- invert(): the RGB channels of the image are inverted: [255-r, 255-g, 255-b, a]
- pixelate(size):make image look coarser by creating a square tiling effect of the specified size, default size is 2
- sepia(): image takes on shades of brown, like an antique photograph
- contrast(val): change the difference in brightness between the min and max intensity of a pixel, default val is 2
- threshold(thresh, low, high):create a two-color image in which pixels less bright than thresh are assigned the low value (default 0 for black), otherwise the high value (default: 255 for white)
- gamma(gcorr): apply the nonlinear gamma operation, used to code and decode luminance values in video or still image systems: out = pow(in, gcorr), default gcorr is 0.2
- posterize(): convert a smooth gradation of tone to regions of fewer tones, with abrupt changes between them
- scatter(): scatters the colors of a pixel in its neighborhood, akin to viewing through brittle cracked glass
- solarize(): which image is wholly or partially reversed in tone. Dark areas appear light or light areas appear dark.

The following image convolutions are available:

- convolve(weights, [opaque]) convolve the image using the weights array as a square convolution matrix. If opaque is true (default), the image will have an opaque alpha channel, otherwise the alpha is convolved as well.
- sobel(): use the Sobel operator to create an image that emphasizes the edges
- medianFilter(): noise reduction technique that replaces each pixel with the median of neighboring pixels
- gaussBlur5(): image pixel values are blurred using a 5x5 Gaussian
- edgeDetect(): detect edges using the kernel [ -1, -1, -1, -1, 8, -1, -1, -1, -1 ]
- sharpen(val): sharpen the image using the kernel [ 0, -3, 0, -3, val, -3, 0, -3, 0 ]
- blur(): blur the image using the kernel [ 1, 2, 1, 2, 1, 2, 1, 2, 1 ]
- emboss(val): produce embossing effect using the kernel [-18, -9, 9, -9, 100 - val, 9, 0, 9, 18 ]
- lighten(val): apply the kernel [ 0, 0, 0, 0, val, 0, 0, 0, 0 ], default val of 12/9 lightens the image
- darken(val): apply the kernel [ 0, 0, 0, 0, val, 0, 0, 0, 0], default val of 6/9 darkens the image

With no arguments, the routine returns an array of available filters:

        JS9.FilterRGBImage()
        ["convolve", "luminance", ..., "blur", "emboss", "lighten", "darken"]

##### Save an image session to a file

`JS9.SaveSession(session, opts)`

where:

- session: optional name of the file to create when saving this session
- opts: optional object or JSON string containing session parameters

This routine saves session information related to the currently displayed image or all images in the specified display. The first argument can be a filename or an options object. If a filename is specified, the second argument can be the options object.

The opts options object supports a mode property whose value can be "display" (save all images in the specified display) or "image" (save the currently displayed image. If this property is not specified, the default is to save all images in the display.

If no filename is specified, the default filename depends on the save mode. If mode is "display", the default filename takes the form js9-[date].ses, e.g., "js9-2018-01-09.ses". If mode is "image", the default filename is [im.id].ses, e.g., "casa.fits.ses".

Saved information (filename, scaling, colormap, contrast/bias, zoom, regions, catalogs, etc) is stored in a JSON-formatted text file. You can subsequently load this file into JS9 to restore the image session. Don't forget that the file is saved by the browser in whatever location you have set up for downloads.

The session file is a text file and can be edited, subject to the usual rules of JSON formatting. For example, you can change the colormap, scaling, etc. after the fact.

The session file contains a file property near the top that specifies the location of the image. A local file usually will contain an absolute path or a path relative to the web page being displayed. However, if the image was originally opened using drag-and-drop, no pathname information is available, in accordance with standard web security protocols. In this case, you must edit the session file to supply the path (either absolute or relative to the web page) before re-loading the session.

##### Load a previously saved image session from a file

`JS9.LoadSession(session)`

where:

- session: name of the session file to load

Restore an image session by loading a JSON-formatted session file. The image itself is retrieved and loaded, and all of the saved parameters and graphics (scale, colormap, regions, catalogs etc) are applied to the display.

The pathname of the session file should either be absolute or should be relative to the web page.

The session file contains a file property near the top that specifies the location of the image. For browser-based JS9, a local file usually will contain an absolute path or a path relative to the web page being displayed.

On the desktop, session files and the associated data files often are moved around or used with different web pages, breaking the connection between the web page and the image path. To deal with this problem, the JS9.desktoplOpts.sessionPath variable is provided:

- if set to true, the image path is relative to the location of the session file (this is the default)
- if set to false, the image path is relative to the web page value (as with browser-based JS9)

This means that if you store your session file relative to the contained image, you can move both files to any location on your disk.

If the image was originally opened using drag-and-drop, no pathname information is available, in accordance with standard web security protocols. In this case, you may have to edit the session file to supply the path (either absolute or relative) before re-loading the session.

Note that the raw data file itself is not saved (only its pathname), so you must have access to that file in order to restore a session. However, the data file need not be in the same location as it was originally: you can adjust the path of the data file by editing the file property as needed.

#### Working with Regions

Spatial regions of interest are a crucial part of astronomical data analysis, especially X-ray analysis. Programs having spatial region support can select parts of a FITS image or binary table using simple geometric shapes, so that only pixels found within these shapes are processed. See regions for a general discussion of spatial region filtering in astronomy, and regcnts for an example program using spatial regions.

JS9's support for spatial regions allows you to create and delete regions, load them from an external file, change characteristics such as size and color, use them as selection criteria in local analysis or pass them to remote analysis, and export them a file.

The regions layer in JS9 is a special case of the more generalized Shape layers, but it is automatically created by JS9 to support the options in the Regions menu, as well as local and server-side data analysis using regions. As such, the region routines are just a thin layer on top of the Shape routines, calling the equivalent Shape routine with "region" as the first argument.

##### Selecting Regions

One of the most important aspects of using regions is the ability to assign different characteristics to regions and then make selections based on these characteristics. The JS9.ChangeRegions(), JS9.GetRegions(), JS9.ListRegions(), JS9.RemoveRegions(), and JS9.SelectRegions() JS9.GroupRegions() calls all take a region selection specification as the first argument, which can be any of the following (in order of precedence):

- selected: the selected region (or all regions in selected group)
- all: all regions, but not including child text regions (default)
- All: all regions, including child text regions
- [id]: a integer region id (or an array of ids), as returned by JS9.AddRegions()
- [color]: all regions having the specified color (e.g., "red")
- [shape]: all regions having the specified shape (e.g., "circle")
- child: a child region (i.e. text child of another region)
- parent: a region that has a child (i.e. has a text child)
- [wcs]: regions whose initial wcs matches the specified wcs
- [tag]: all regions containing the specified tag (e.g., "source")
- /[regexp]/: all regions whose tags match the regexp (e.g. "/foo[1-4]/")
- dcoords: a region that preserves display coordinates
- nodcoords: a region that does not preserve display coordinates

Of these, all, selected, [color], [shape], and [tag] are probably the most often used. Selections make it possible to act on multiple regions at the same time. For example:

        # all currently selected regions
        JS9.ListRegions("selected");

        # all circles
        JS9.ChangeRegions("circle", {"color": "red"});

        # all red regions
        JS9.GetRegions("red");

        # all regions with the tag 'foo1'
        JS9.ChangeRegions("foo1", {"color": "red"});

        # all regions with a tag matching the regular expression foo.*
        JS9.ListRegions("/foo.*/");

        # region with id 7
        JS9.SelectRegions(7, {"color": "red"});

In addition, you can combine selections using the boolean operators, with the usual precedence and associativity rules holding sway:

      Operator                                Associativity
      --------                                -------------
      !  (bitwise not)                        right to left
      && (logical and)                        left to right
      || (logical or)                         left to right

For example:

        # circles or ellipses
        JS9.ChangeRegions("circle || ellipse", {"color": "red"});

        # circles or red regions
        JS9.ListRegions("circle || red");

        # circles having tag 'foo1'
        JS9.ChangeRegions("circle && foo1", {"color": "red"});

        # circles not having tag 'foo2'
        JS9.SelectRegions("circle && !foo2");

        # all regions except red ones
        JS9.ChangeRegions("!red", {"color": "cyan"});

        # not selected regions
        JS9.ChangeRegions("!selected", {"color": "cyan"});

        # circles having tag 'foo1' and ellipses having tag 'foo2'
        JS9.GetRegions("(circle && foo1) || (ellipse && foo2)");

When a region selection is made using the JS9.ChangeRegions() or JS9.SelectRegions() calls, the selection is saved so that you can use it as part of subsequent selection calls. You can specify use of the saved selection either in the opts object or directly in the selection string:

        # select circle regions and save selection filter
        JS9.SelectRegions("circle")

        # select saved regions, along with ellipses that have a "foo1" tag
        JS9.SelectRegions("ellipse && foo1", {"saved": true})

        # select saved regions, along with ellipses that have a "foo1" tag
        JS9.SelectRegions("ellipse && foo1", {"saved": "or"})

        # select saved regions, along with ellipses that have a "foo1" tag
        JS9.SelectRegions("saved || (ellipse && foo1)")

        # select saved regions if they are ellipses that have a "foo1" tag
        JS9.SelectRegions("ellipse && foo1", {"saved": "and"})

        # select saved regions if they are ellipses that have a "foo1" tag
        JS9.SelectRegions("saved && ellipse && foo1")

        # retrieve currently saved regions
        JS9.ListRegions('saved')

Calling JS9.SelectRegions("reset") will clear the saved selection.

##### Add one or more regions to the regions layer

`id = JS9.AddRegions(rarr, opts)`

where:

- rarr: a shape string, region object or an array of region objects
- opts: global values to apply to each created region

returns:

- id: id of last region created

The rarr argument can be a region shape ("annulus", "box", "circle", "cross", "ellipse", "point", "polygon", "text"), a single region object, or an array of region objects. Region objects contain one or more properties, of which the most important are:

- shape: "annulus", "box", "circle", "cross", "ellipse", "point", "polygon", "text" [REQUIRED]
- x: image x position
- y: image y position
- px: physical x position
- py: physical y position
- ra: RA in degrees
- dec: Dec in degrees
- wcs: sexagesimal WCS string with optional WCS system
- lcs: object containing logical x, y and sys (e.g., "physical")
- deltax: increment from current image x position
- deltay: increment from current image y position
- tags: comma-separated list of tag strings or array of tag strings
- radii: array of radii for annulus region
- width: width for box or cross region
- height: height for box or cross region
- radius: radius value for circle region
- r1: x radius for ellipse region (misnomer noted)
- r2: y radius for ellipse region (misnomer noted)
- pts: array of objects containing x and y positions for polygons
- points: array of objects containing x and y offsets from the center for polygons
- angle: angle in degrees for box, ellipse, cross regions
- color: region color (string name or #rrggbb syntax)
- strokeWidth: line (stroke) width of the region
- strokeDashArray: array specifying dash pattern, e.g, [3,1]
- text: text associated with text region or for a child region of this region
- data: this property can be an object, string, number, etc. and will be carried along with the region, and returned as a property by the JS9.GetRegions() call.

Other available properties include:

- changeable: if false, region cannot be moved, resized, rotated
- locked: 'opposite alias' of changeable
- movable: if false, region cannot be moved
- resizable: if false, region cannot be resized or rotated
- rotatable: if false, region cannot be rotated
- removable: if false, region cannot be removed
- selectable: if false, region can't be selected (no GUI-based changes)
- lockMovementX: if true, region cannot be moved in the x direction
- lockMovementY: if true, region cannot be moved in the y direction
- lockScalingX: if true, region cannot be resized in the x direction
- lockScalingY: if true, region cannot be resized in the y direction
- lockRotation: if true, region cannot be rotated
- fontFamily: font parameter for text region
- fontSize: font parameter for text region
- fontStyle: font parameter for text region
- fontWeight: font parameter for text region
- sticky: if true, region doesn't change during pan, zoom, rotate, flip
- preservedcoords: if true, the region is sticky, and display coordinates are preserved during save and copy operations (see below for more info)

Here are some examples of ways to create regions:

        # example 1: circular region in the center of the field
        JS9.AddRegions("circle");

        # example 2: red circular region in the center of the field
        JS9.AddRegions("circle", {color: "red"});

        # example 3: red circular region with dashed lines
        JS9.AddRegions("circle", {color: "red", strokeDashArray: [3,1]});

        # example 4: regions using an object in first arg
        JS9.AddRegions({shape: "circle", color: "red", strokeDashArray: [3,1]})

        # example 5: multiple regions using an array specification in first arg
        JS9.AddRegions([{shape: "circle", color: "red", strokeDashArray: [3,1]},
                        {shape: "box", color: "green", strokeDashArray: [6,1]}])

        # example 6: js9 region syntax: properties in the second arg object
        JS9.AddRegions('ellipse(23:23:22.179, +58:48:10.542, 40", 20", 60)', {text: "ellipse test", color: "violet", tags: "json tag, another tag", textOpts: {color: "yellow", fontSize: 16, fontStyle: "italic", fontWeight: "bold"}});

        # example 7: js9 region syntax: JSON properties in the first arg string
        JS9.AddRegions('ellipse(23:23:22.179, +58:48:10.542, 40", 20", 60) {"color": "violet", "text": "ellipse test", "textOpts": {"color": "yellow", "fontSize": 16, "fontStyle": "italic", "fontWeight": "bold"}} # json tag, another tag');

        # example 8: ds9 region syntax: comment properties in the first arg string
        JS9.AddRegions('box(23:23:35.486, +58:50:03.146, 40", 20", 30) # width=4 text={box test} dash=1 color=red rotate=0 tag="test tag"')

        # example 9: create a region at the specified RA and Dec using ICRS
        # Note that the WCS string is returned by the Edit menu's "copy wcs pos"
        # option (i.e., the "/" keystroke.)
        JS9.AddRegions("circle", {wcs: "23:23:28.895 +58:49:43.50 ICRS"});

        # example 10: create a region by supplying display (screen) coordinates
        image
        text(d250, d100, "Using Display Coordinates")

        # example 11: create a region by supplying display (screen) coordinates
        # preserve the display coordinate when saving, copying
        # and don't move the region when panning, zooming
        image
        text(d250, d100, "Using and Preserving Display Coordinates:") {"preservedcoords": true}

In sum, you can specify a region using:

- a shape in the first string arg, optional properties in the second object arg
- properties (including the shape) in the first object arg
- array of objects in the first arg
- full region syntax in the first string arg, optional properties in the second arg

Note the difference between examples 6 and 7: the former passes properties in an object (second argument), so the key names need not be quoted. The latter passes properties in a JSON string as part of the first string argument: here the key names must be quoted using double quotes, as per the JSON specification.

Examples 6 and 7 also show the text property, which allows you to associate a text string with a non-text region. JS9 will create a separate text region as a child of the original region. You can move this child text region around relative to the original region, change its angle, etc. The child will then maintain its new position relative to the original region as the latter is moved, resized, etc. You also can double-click on the text child to bring up its configuration dialog box and change its color, font, size, text string, etc.

Examples 10 and 11 show several features of regions that might be useful for marking images with text and shapes that are tied to the display rather than the image. When using the image coordinate system, you can prefix the image positions with 'd' or 'D' to indicate that they should be interpreted as display (also called "screen") coordinates instead of image coordinates. The origin of the display is in the upper left corner (image coordinates are in the lower left). By default, a region specified with display coordinates is no different from other regions: the region will change its screen position during zoom and pan operations to stay aligned on the image, and its position will be saved using the current coordinate system. That is, by default, display coordinate are only used in the initial placement of the region.

To preserve the region's display position during zoom and pan operations and while saving regions, set the preservedcoords property to true in the opts object. In this case, the region is no longer a canonical astronomical region of interest, but is more like a mark on the screen. By default, it will not be listed by the Regions list menu option, nor will it be saved by default (although you can set the save dcoords regions to true in the regions save dialog box, or set savedcoords to true in the opts property of the JS9.SaveRegions() routine.) It also will not be passed to back-end server analysis routines that specify $regions, $sregions, $bregions in their command line. However, it will be copied from one image to another when using the JS9.CopyRegions() routine. These behaviors are parameterized in the JS9.globalOpts object:

- regListDCoords: list preserved display coords? (def: false)
- regSaveDCoords: save preserved display coords? (def: false)
- regExpandDCoords: pass preserved display coords? to analysis (def: false)
- regCopyDCoords: copy preserved display coords? (def: true)

##### Get information about one or more regions

`rarr = JS9.GetRegions(regions, opts)`

where:

- regions: which regions to retrieve
- opts: optional object

returns:

- rarr: array of region objects (or text if opts.format is "text")

Get information about one or more regions. The first argument is the regions selection. If not specified, it defaults to "selected" if there are selected regions, otherwise "all".

Each returned region object contains the following properties:

- id: numeric region id (assigned by JS9 automatically)
- mode: "add", "remove", "select", "update"
- shape: region shape ("annulus", "box", "circle", "cross", "ellipse", "point", "polygon", "text")
- tags: comma delimited list of region tags (e.g., "source", "include")
- color: region color
- x,y: image coordinates of region
- radii: array of radii for annulus region
- width: width for box or cross region
- height: height for box or cross region
- radius: radius value for circle region
- r1: x radius for ellipse region (misnomer noted)
- r2: y radius for ellipse region (misnomer noted)
- pts: array of objects containing x and y positions, for polygons
- points: array of objects containing x and y offsets from the specified center, for polygons
- angle: angle in degrees for box, ellipse, cross regions
- ra: RA of center in degrees
- dec: Dec of center in degrees
- wcsstr: region string in WCS coordinates
- wcssys: WCS system (e.g., "FK5")
- imstr: region string in image or physical coordinates
- imsys: image system ("image" or "physical")
- lcs: object containing logical x, y and sys (e.g., "physical")
- parent: the id of the parent region, if this is a text child region
- child: the id of the child text region, if any
- data: data property passed in options object when this shape was created.

The x, y, radii, pts, radius, width, height, r1, r2 values are all returned in the image coordinate system. The lcs object will contain x and y in logical (i.e., physical) coordinates. Moreover, if the imsys value is not "image" (i.e., the JS9 coordinate system is not explicitly set to "image"), then the lcs object also will contain radii, pts, radius, width, height, r1, r2 in the logical coordinate system.

The image position x, y can be used to access the image data returned by the JS9.GetImageData() routine:

        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.

In opts format property is set to "text", the regions are returned as a string in standard regions format, using semi-colon delimiters:

        JS9.GetRegions("all", {format: "text"})
        ICRS; box(23:23:40.3, +58:47:04.05, 29.5\", 29.5\", 0.0) # background,include; ellipse(23:23:28.06, +58:48:40.5, 14.7\", 15.7\") # source,include

    By default, the region's json object and comments are passed based on
    the value of the globalOpts.regIncludeJSON
    and globalOpts.regIncludeComments properties, respectively.
    You can override this value by setting the includejson
    and includecomments properties in opts.

    You can pass wcssys and wcsunits in opts to return the wcs information in the desired format:

        JS9.GetRegions("all", {format: "text"})
        ICRS; circle(23:23:35.300,+58:50:03.600,14")

        JS9.GetRegions("all", {format: "text", wcsunits: "degrees"})
        ICRS; circle(350.897083,58.834333,0.003889)

        JS9.GetRegions("all", {format: "text", wcssys: "FK4", wcsunits: "degrees"})
        FK4; circle(350.330969,58.559785,0.003889)

        JS9.GetRegions("all", {format: "text", wcsunits: "pixels"})
        physical; circle(3893.94,4091.92,28.46)

If opts format property is set to "regions", the regions are returned as a new-line separated list, similar to the output of JS9.SaveRegions(). By default, this will include the wcs keyword:

        JS9.GetRegions("all", {format: "regions"})
        ICRS
        circle(23:23:27.909,+58:48:42.880,14")
        box(23:23:35.486,+58:50:03.146,40.001278,14",20.000000)

If opts format property is set to "csv", the regions are returned as a comma-separated value list, using new-line delimiters. By default, this will not include the wcs keyword:

        JS9.GetRegions("all", {format: "csv"})
        circle,23:23:27.909,+58:48:42.880,14"
        box,23:23:35.486,+58:50:03.146,40.001278,14",20.000000

##### List one or more regions

`rstr = JS9.ListRegions(regions, opts)`

where:

- regions: which regions to list
- opts: optional object

returns:

- rstr: region string

List (and return) the specified regions. By default, a light window is displayed listing all regions (i.e., as if the list option of the Regions menu had been selected.) You can also list "selected" regions or use any of the standard regions specifications (see introduction to the Regions routines above.)

The opts object supports the following properties:

- mode: display/return mode (1,2,3)
- wcssys: wcs system to use (ICRS, FK5, galactic, physical, etc.)
- wcsunits: units for wcs output (sexagesimal, degrees, pixels)
- includejson: include JSON object
- includecomments: include comments
- layer: which layer to display (default is "regions" layer)

The mode property accepts the following values:

- 1: no display, return full region string including json and comments
- 2: display and return shortened region string (no json or comments)
- 3: display and return full region string (including json and comments)

##### List groups

`gstr = JS9.ListGroups(group, opts)`

where:

- group: which group to list or "all"
- opts: optional options object

returns:

- gstr: group string

List the specified region/shape group(s) in the specified layer (default is "regions"). The first argument is the groupid of the group to list, or "all" to list all groups.

The optional opts object can contain the following properties:

- includeregions: display regions as well as the group name (default: true)
- layer: layer to list (default is "regions")

By default, the display will includes the name of the group and the regions in the group. To skip the display of regions, supply an opts object with the includeregions property set to false. For example:

        JS9.ListGroups("all", {"includeregions": false})
        grp1
        grp2
        grp3

        JS9.ListGroups("grp1")
        grp1:
        circle(3980.00,4120.00,20.00) # source,include,foo1
        ellipse(4090.00,4120.00,25.00,15.00,0.0000) # source,include,foo1

See JS9.GroupRegions() for more information about region groups.

##### Edit one or more selected regions

`JS9.EditRegions()`

Edit one or more selected regions using an Edit dialog box. If a single region has been selected by clicking that region, all of its properties can be edited via the displayed dialog box. If a group of regions has been selected using Meta-mousemove to highlight one or more regions, then properties such as color, stroke width, dash pattern, and tags can be edited for all of the selected regions using the displayed dialog box. In the latter case, use shift-click to add additional regions to the edit group.

##### Change one or more regions

`JS9.ChangeRegions(regions, opts)`

where:

- regions: which regions to change
- opts: object containing options to change in each region

Change one or more regions. The first argument is the regions selection. If not specified, it defaults to "selected" if there are selected regions, otherwise "all".

The opts object can contain the parameters described in the JS9.AddRegions() section. However, you cannot (yet) change the shape itself (e.g., from "box" to "circle".) See js9onchange.html for examples of how to use this routine.

By default, if you change the color of a region, the color of the text associated with that region also will be changed:

        # color of text associated with this region also will be changed to red
        JS9.ChangeRegions("circle", {"color": "red"});

You can turn off synchronization of text colors either by setting the JS9.globalOpts.regSyncTextColor site property to false or by setting the synctextcolor option to false in the opts object:

        # color of text associated with this region will not be changed to red
        JS9.ChangeRegions("circle", {"color":"red", "synctextcolor":false});

Note that you also can change the JS9.globalOpts.regSyncTextColor property via the Global tab of the Preferences plugin.

If you pass the empty string to color, strokeWidth, or strokeDashArray, the specified property will be reset as follows:

- color: reset based on source/bkgd include/exclude tags
- strokeWidth: reset to initial JS9.Fabric.opts.strokeWidth value
- strokeDashArray: reset to a solid line

For example:

        # change circles to be red with a dash pattern
        JS9.ChangeRegions("circle", {color:"red", strokeDashArray:[3,1]});

        # reset color and dash pattern
        JS9.ChangeRegions("circle", {color:"", strokeDashArray:""});

##### Copy one or more regions to another image

`JS9.CopyRegions(to, regions)`

where:

- to: image id to which to copy regions
- regions: which regions to copy

Copy regions to a different image. If to is "all", then the regions are copied to all images.

The first argument is the regions selection. If not specified, it defaults to "selected" if there are selected regions, otherwise "all".

##### Remove one or more regions from the region layer

`JS9.RemoveRegions(regions)`

where:

- regions: which regions to remove

The selected regions are removed. The first argument is the regions selection. If not specified, it defaults to "selected" if there are selected regions, otherwise "all".

If JS9.globalOpts.resetEmptyShapeId is set to true (default is false), the region id counter will be reset to 0 whenever all the regions are removed.

##### Unremove one or more previously removed regions

`JS9.UnremoveRegions()`

If you accidentally remove one or more regions, you can use restore them using this call. JS9 maintains a stack of removed regions (of size JS9.globalOpts.unremoveReg, current default is 100.) Each time one or more regions is removed, they are stored as a single entry on this stack. The UnremoveRegions call pops the last entry off the stack and calls AddRegions.

##### Save regions from the current image to a file

`JS9.SaveRegions(filename, which, layer)`

where:

- filename: output file name
- which: which regions to save (default is "all")
- layer: which layer to save (default is "regions")

Save the current regions for the displayed image as a JS9 regions text file. If filename is not specified, the file will be saved as "js9.reg". If the string "dialogbox" is passed in the filename and no other arguments are specified, the Save Regions dialogbox is displayed instead of actually saving regions to a file.

Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.

If the which argument is not specified, it defaults to "all". You can specify "selected" to return information about the selected regions, or a tag value to save regions having that tag.

If the layer argument is not specified, it defaults to "regions", i.e., the usual regions layer. You can specify a different layer, e.g., if you want to save a catalog layer as a region file (since JS9.SaveCatalog() will save the data in table format instead of as regions.)

The layer argument can also be an object or a JSON-formatted string containing these properties:

- layer: the name of the layer
- format: output format: reg, csv, or svg
- type: backward compatible alias for format (deprecated)
- wcssys: wcs system to use (ICRS, FK5, galactic, physical, etc.)
- wcsunits: units for wcs output (sexagesimal, degrees, pixels)
- includejson: for reg files, include JSON object in output
- includecomments: for reg files, include comments in output
- includewcs: for csv files, include wcs keyword(s) in output

If the format is svg, an SVG/XML file will be saved instead of the standard astronomical regions file. This SVG file can be imported into programs such as Photoshop for further processing.

If the format is csv, a text file will be saved with the regions output as comma separated values:

        JS9.SaveRegions("foo", "all", {"format":"csv", "wcsunits":"degrees"})

        circle,350.866288,58.811911,0.004099
        box,350.897858,58.834207,0.011111,0.005556,20.000000

Note that the region's wcs keyword is not passed by default in order to make processing easier. You can force its inclusion by setting the includewcs property to true.

If the output format is set to svg (or csv), the default filename will be "js9.svg" ("js9.csv") instead of "js9.reg". Similarly, if a filename is specified that ends in ".svg" (or ".csv"), the format will be set to svg (csv).

##### Change region tags for the specified image(s)

`JS9.ChangeRegionTags(which, addreg, removereg)`

where:

- which: which regions to process (default is "all")
- addreg: array or comma-delimited string listing regions to add
- removereg: array or comma-delimited string listing regions to remove

While region tags can be changed wholesale using the JS9.ChangeRegions() routine, this routine allows you to add and/or remove specific tags. The first argument specifies which regions to change. The second argument is a list of tags to add, while the third argument is a list of tags to remove. In each case, the tags argument can be an array of tag strings or a single string containing a comma-separated list of tags:

        JS9.ChangeRegionTags("selected", ["foo1", "foo2"], ["goo1", "goo2"]);
        JS9.ChangeRegionTags("selected", "foo1,foo2", "goo1,goo2");

Each of the above routines adds two "foo" tags and removes two "goo" tags from the selected region(s).

##### Gather Regions into a Temporary Selection

`JS9.SelectRegions(regions)`

where:

- regions: which regions to select

JS9 has a rich mouse-based interface for selecting regions: a single region is selected by clicking on it. A number of regions can be gathered into a temporary selection by pressing the left mouse button and dragging the mouse over the desired regions. To add to an already-existing selection, shift-click the mouse on a region.

A regions selection can be moved, resized, or retrieved as a single unit. The selection is destroyed when the mouse is clicked outside the selection, or when JS9.UnselectRegions() is called.

This routine allows you to create a selection programmatically by specifying which regions make up the selection. The first argument is the regions selection. If not specified, it defaults to "all" (since it doesn't make sense to default to the already-selected regions, does it?). The result of the call will be a selection of regions which can be moved as one unit.

For example:

        # select all circles
        JS9.SelectRegions("circle");

        # select all circles not having tag 'foo2'
        JS9.SelectRegions("circle && !foo2");

Regions in a selection are processed individually, i.e. a regions selection will match the regions inside a group. Thus for example, if you create a selection containing circles, changing the color using the "circle" specification will also affect the circles within the selection. You can, of course, process only the regions inside a selection using the selected specification.

To create more long-lived groups (i.e., which are not destroyed when you click the mouse outside the region), see JS9.GroupRegions().

##### Remove Regions From a Selection

`JS9.UnselectRegions(regions)`

where:

- regions: which regions to unselect

JS9 has a rich mouse-based interface for selecting regions: a single region is selected by clicking on it. A number of regions can be gathered into a group selection by pressing the left mouse button and dragging the mouse over the desired regions. To add to an already-existing selection, shift-click the mouse on a region.

This routine allows you to remove one or more regions from a region selection programmatically by specifying which regions to remove. The first argument is the regions selection. If not specified, or specified as "all" or "selected", the selection is undone. Otherwise, the result of the call will be a new selection, not containing the unselected regions, which can be moved as one unit.

For example:

        # select all circles and ellipses
        JS9.SelectRegions("circle || ellipse");

        # unselect circles not having tag 'foo2'
        JS9.UnselectRegions("circle && !foo2");

##### Gather Regions into a Long-lived Group

`JS9.GroupRegions(regions, opts)`

where:

- regions: which regions to group
- opts: optional object containing grouping options

returns:

- groupid: the group id associated with the newly created group

A region group can be moved and resized as a single unit. To first order, it is a long-lived form of a region selection. The latter gets dissolved when you click the mouse outside the selection, but a region group is dissolved only by calling JS9.UngroupRegions().

This routine allows you to create a group by specifying the regions which will compose it. The first argument is the regions selection. If not specified, it defaults to either "selected" or "all", depending on whether a region selection currently exits.

The optional opts argument contains the following properties:

- groupid: the group id to use, if possible (default: "group_[n]")
- select: if false, the group is not selected upon creation

By default, the groupid will be the string "group_" followed by an integer chosen so that the groupid is unique. You can supply your own groupid, but if it already is associated with an existing group, an integer value will be appended to make it unique. Also, by default the newly created group will be "selected". You can pass the select property with a value of false in order to avoid selecting the group (e.g., if you are creating a number of groups and don't want to see each of them selected in turn.)

The returned groupid string can be used to select and process all the regions in that group. Thus, for example, you can use the groupid to change the color of all grouped regions:

        # make a group from all circles having the tag foo1
        gid = JS9.GroupRegions("circle && foo1");

        # change color of all regions in the group
        JS9.ChangeRegions(gid, {"color":"red"});

Furthermore, when creating a regions file via JS9.SaveRegions(), the groupid will be stored in each grouped region's JSON object, and will be used to reconstitute the group when the file is reloaded.

Note however, that unlike the temporary region selections, regions in a group are not available individually, i.e., a regions selection using a non-groupid does not match regions inside a group. Thus, for example, if you have created a group of circles, changing the color using a "circle" specification does not affect circles within the group:

        # make a group from all circles having the tag foo1
        gid = JS9.GroupRegions("circle && foo1");

        # change color of circle regions, but NOT including those in any group
        JS9.ChangeRegions("circle", {"color":"cyan"});

        # change color of all regions in the group
        JS9.ChangeRegions(gid, {"color":"red"});

Furthermore, a given region can only be part of one group at a time. In the case where a region already is part of an existing group, the globalOpts.regGroupConflict property determines how that region is processed. The default is skip, meaning that the region is silently skipped over when creating the new group. The alternative is error, which will throw an error.

To create a more temporary selection, see JS9.SelectRegions().

##### Dissolve a Group of Regions

`JS9.UngroupRegions(groupid, opts)`

where:

- groupid: group id of the group to dissolve
- opts: optional object containing ungrouping options

This routine allows you to dissolve an existing group, so that the regions contained therein once again become separate. The first argument is the groupid, previously returned by the JS9.GroupRegions() call.

The optional opts argument contains the following properties:

- select: newly separate regions in the group are "selected"?

By default, the ungrouped regions unobtrusively take their place among other regions on the display. You can make them be selected by passing the select: true property in opts. Doing this, for example, would allow you to remove them easily with the Delete key.

For example:

        # group all circles and ellipses
        gid = JS9.GroupRegions("circle || ellipse");

        # ungroup so the regions are again separate
        JS9.UngroupRegions(gid)

        # change color of circle regions, including the newly ungrouped ones
        JS9.ChangeRegions("circle", {"color":"cyan"});

##### Toggle two region tags for the specified image(s)

`JS9.ToggleRegionTags(which, t1, t2)`

where:

- which: which regions to process (default is "all")
- t1: tag #1 to toggle
- t2: tag #2 to toggle

While region tags can be changed wholesale using the JS9.ChangeRegions() routine, this routine allows you to toggle between two tags, e.g., a source region and background region, or between include and exclude. For example:

        JS9.ToggleRegionTags("selected", "source", "background");

will change a background region into a source region or vice-versa, depending on the state of the region, while:

        JS9.ToggleRegionTags("selected", "include", "exclude");

will toggle between include and exclude.

##### Load regions from a file into the current image

`JS9.LoadRegions(filename, opts)`

where:

- filename: input file name or URL
- opts: global region options for all regions

Load the specified regions file into the displayed image. The filename, which must be specified, can be a local file (with absolute path or a path relative to the displayed web page) or a URL.

The opts property specifies global options that are applied to all regions in the file. They will be over-ridden by individual region properties attached to a given region. For example, if a region file named "foo.reg" contains the following regions:

        # Region file format: JS9 version 1.0
        image
        circle(512.0, 512.0, 40) {"color": "red"}
        box(512.0, 512.0, 40, 40)
        annulus(512.0, 512.0, 0.0, 3.0, 12.0, 18.0, 27.0)

then a command such as:

        JS9.LoadRegions("foo.reg", {color: "blue"});

will create a red circle, a blue box, and a blue annulus.

The opts object also can include an onload property containing a function to be called when the load is complete. The image handle is passed as an argument to this function.

If the same region file is loaded more than once, behavior is determined by the JS9.globalOpts.reloadRefreshReg property. If set to true (the default), all previous regions loaded from the file are removed (regardless of their current position, size, etc.) If set to false, the new regions are added to the previous ones. Site authors can change this property in js9prefs.js, while users can change this via the Global tab of the Preferences plugin.

#### Working with Shape Layers

JS9 supports individual layers for drawing 2D graphics. The ubiquitous 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.

One of the most important aspects of using shapes is the ability to assign different characteristics to shapes and then make selections based on these characteristics. The JS9.ChangeShapes(), JS9.GetShapes(), JS9.RemoveShapes(), and JS9.SelectShapes() calls all take a regions selection as the second argument, which functions identically to the way in which Regions selections are made.

##### Create a new shape layer

`lid = JS9.NewShapeLayer(layer, opts)`

where:

- layer: name of the layer to create
- opts: default options for this layer

returns:

- lid: layer id

This routine creates a new named shape layer. You can then, add, change, and remove shapes in this layer using the routines below. The catalogs displayed by the Catalog plugin are examples of separate shape layers.

The opts parameter allows you to specify default options for the new layer. Although this argument is optional, you generally will want to set default values for various properties utilized by your new shape layer. See JS9.Regions.opts in js9.js for example of the default options for the regions layer. This is a good set of options to pass if you want region-like behavior in your new layer.

The JS9.Catalogs.opts object is also supplied as a possible baseline object for new shape layers. It differs from the JS9.Regions.opts in a few important ways:

- it makes the new layer non-interactive: individual shapes cannot be moved, rotated, resized, or deleted, nor do they respond to events
- it sets the updateWCS property to false, so the relatively expensive operation of updating the WCS string is not performed when an object is modified
- it does not sort overlapping shapes so that the smallest is on top when a shape is moved
- it does not define regions-specific processing (e.g., double-click to edit a region parameters)

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 resizable as a group.

The second way is to supply one or more event callbacks as properties to the opts object:

- onmousedown: function(im, xreg, evt);
- onmouseup: function(im, xreg, evt);
- onmousemove: function(im, xreg, evt);
- onmouseover: function(im, xreg, evt);
- onmouseout: function(im, xreg, evt);

When the associated mouse event occurs on a shape, these functions will be called with the following arguments:

- im: the image handle for the currently displayed image
- xreg: the shape object, as described in JS9.GetShapes()
- evt: the original event object

For example, to define mouseover and mousedown callbacks:

        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):

- ongroupcreate: function(im, xreg, id);

The function will be called with the following arguments:

- id: group id
- im: the image handle for the currently displayed image
- xreg: an array of shape objects within the group

Note that an array of xreg objects is passed in this case instead of the single "current" object passed in the other event callbacks. For example:

        opts.ongroupcreate = function(id, im, xreg){
            var i, nshape, xcen, ycen;
            var xtot=0, ytot=0;
            nshape = xreg.length;
            console.log("group: %s", id);
            for(i=0; i<nshape; i++){
              xtot += xreg[i].x; ytot += xreg[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. As a convenience, $data can be used as a shorthand for $xreg.data.

##### Show or hide the specified shape layer

`JS9.ShowShapeLayer(layer, mode)`

where:

- layer: name of layer
- mode: true (show layer) or false (hide layer)

Shape layers can be hidden from display. This could be useful, for example, if you have several catalogs loaded into a display and want to view one at a time.

If mode is true, a previously hidden shape layer will be displayed. If mode is false, a displayed shape layer will be hidden. If the mode argument is not supplied, the current mode is returned.

##### Toggle display of the active shape layers

`JS9.ToggleShapeLayers()`

While JS9.ShowShapeLayer() allows you to display or hide a single shape layer, this routine will toggle display of all active layers in the current image. An active layer is one that has not been turned off using the Shape Layers plugin or JS9.ShowShapeLayer().

The routine remembers which layers were active at the moment when layers are hidden and restores only those layers in the next toggle. Thus, if you have two layers, "regions" and "catalog1", and the "catalog1" layer has previously been turned off, calling this routine repeatedly will turn on and off the "regions" layer only.

##### Make the specified shape layer the active layer

`JS9.ActiveShapeLayer(layer)`

where:

- layer: name of layer

returns:

- active: the active shape layer (if no args are specified)

For a given image, one shape layer at a time is active, responding to mouse and touch events. Ordinarily, a shape layer becomes the active layer when it is first created and shapes are added to it. Thus, the first time you create a region, the regions layer becomes active. If you then load a catalog into a catalog layer, that layer becomes active.

If no arguments are supplied, the JS9.ActiveShapeLayer() routine returns the currently active layer. Specify the name of a layer as the first argument to make it active. Note that the specified layer must be visible.

This routine forms the basis for the Shape Layer plugin, which provides a graphical way to make a layer active (by moving it to the top of the layer stack.)

##### Add one or more shapes to the specified layer

`JS9.AddShapes(layer, sarr, opts)`

where:

- layer: name of layer
- sarr: a shape string, shape object, or an array of shape objects
- opts: global values to apply to each created shape

returns:

- id: id of last shape created

The sarr argument can be a shape ("annulus", "box", "circle", "cross", "ellipse", "point", "polygon", "text"), a single shape object, or an array of shape objects. Shape objects contain one or more properties, of which the most important are:

- shape: "annulus", "box", "circle", "cross", "ellipse", "point", "polygon", "text" [REQUIRED]
- x: image x position
- y: image y position
- deltax: increment from current image x position
- deltay: increment from current image y position
- tags: comma-separated list of tag strings or array of tag strings
- radii: array of radii for annulus shape
- width: width for box or cross shape
- height: height for box or cross shape
- radius: radius value for circle shape
- r1: x radius for ellipse shape (misnomer noted)
- r2: y radius for ellipse shape (misnomer noted)
- pts: array of objects containing x and y positions, for polygons
- points: array of objects containing x and y offsets from the specified center, for polygons
- angle: angle in degrees for box, ellipse, cross shapes
- color: shape color (string name or #rrggbb syntax)
- text: text associated with text shape
- data: this property can be an object, string, number, etc. and will be carried along with the shape, and returned as a property by the JS9.GetShapes() call.

Other available properties include:

- changeable: if false, region cannot be moved, resized, rotated
- locked: 'opposite alias' of changeable
- movable: if false, region cannot be moved
- resizable: if false, region cannot be resized or rotated
- rotatable: if false, region cannot be rotated
- removable: if false, region cannot be removed
- zoomable: if false, region is not resized when image is zoomed
- selectable: if false, region can't be selected (no GUI-based changes)
- lockMovementX: if true, region cannot be moved in the x direction
- lockMovementY: if true, region cannot be moved in the y direction
- lockScalingX: if true, region cannot be resized in the x direction
- lockScalingY: if true, region cannot be resized in the y direction
- lockRotation: if true, region cannot be rotated
- fontFamily: font parameter for text region
- fontSize: font parameter for text region
- fontStyle: font parameter for text region
- fontWeight: font parameter for text region

##### Remove one or more shapes from the specified shape layer

`JS9.RemoveShapes(layer, shapes)`

where:

- layer: name of layer
- shapes: which shapes to remove

The selected shapes are removed from the specified layer. The second argument is the regions selection. If not specified, it defaults to "all".

If JS9.globalOpts.resetEmptyShapeId is set to true (default is false), the shape id counter will be reset to 0 whenever all the shapes are removed.

##### Get information about one or more shapes in the specified shape layer

`JS9.GetShapes(layer, shapes)`

where:

- layer: name of layer
- shapes: which shapes to retrieve

returns:

- sarr: array of shape objects

Each returned shape object contains the following properties:

- id: numeric region id (assigned by JS9 automatically)
- mode: "add", "remove", or "change"
- shape: region shape ("annulus", "box", "circle", "cross", "ellipse", "point", "polygon", "text")
- tags: comma delimited list of region tags (e.g., "source", "include")
- color: region color
- x,y: image coordinates of region
- size: object containing width and height for box, cross region
- radius: radius value for circle region
- radii: array of radii for annulus region
- eradius: object containing x and y radii for ellipses
- pts: array of objects containing x and y positions, for polygons
- angle: angle in degrees for box, ellipse, cross
- data: data property passed in options object when this shape was created.

##### Change one or more shapes in the specified layer

`JS9.ChangeShapes(layer, shapes, opts)`

where:

- layer: name of layer
- shapes: which shapes to change
- opts: object containing options to change in each shape

Change one or more shapes in the specified layer. The opts object can contain the parameters described in the JS9.AddShapes() section. However, you cannot (yet) change the shape itself (e.g., from "box" to "circle".)

The second argument is the regions selection. If not specified, it defaults to "all".

##### Copy a shape layer to another image

`JS9.CopyShapes(to, layer)`

where:

- to: image id to which to copy shapes
- layer: shape layer to copy

Copy the shapes in a shape layer to a different image. If to is "all", then the shapes are copied to all images.

All shapes in the shape layer are copied to the new image.

##### Group Shapes into a Selection

`JS9.SelectShapes(layer, shapes)`

where:

- layer: shape layer
- shapes: which shapes to select

JS9 has a rich mouse-based interface for selecting shapes: a single shape is selected by clicking on it. A number of shapes can be gathered into a group selection by pressing the left mouse button and dragging the mouse over the desired shapes. To add to an already-existing selection, shift-click the mouse on a shape.

A selected group of regions can be moved, resized, or retrieved as a single unit. The selected group is destroyed when the mouse is clicked outside the selection, or when JS9.UnselectShapes() is called.

This routine allows you to create a group selection programmatically by specifying which shapes make up the selection. The first argument is the shape layer. The second argument is the regions selection. If not specified, it defaults to "all" (since it doesn't make sense to default to the already-selected shapes, does it?). The result of the call will be a selected group which can be moved as one unit.

##### Remove Shapes From a Selection

`JS9.UnselectShapes(layer, shapes)`

where:

- layer: shape layer
- shapes: which shapes to unselect

JS9 has a rich mouse-based interface for selecting shapes: a single shape is selected by clicking on it. A number of shapes can be gathered into a selection by pressing the left mouse button and dragging the mouse over the desired shapes. To add to an already-existing selection, shift-click the mouse on a shape.

This routine allows you to remove one or more shapes from a group selection programmatically by specifying which shapes to remove. The first argument is the shape layer. The second argument is the regions selection. If not specified, or specified as "all" or "selected", the selection is undone. The result of the call will be a new selected group, not containing the unselected shapes, which can be moved as one unit.

##### Gather Shapes into a Long-lived Group

`JS9.GroupShapes(layer, shapes, opts)`

where:

- layer: shape layer
- shapes: which shapes to group
- opts: optional object containing grouping options

returns:

- groupid: the group id associated with the newly created group

A shape group can be moved and resized as a single unit. To first order, it is a long-lived form of a region selection. The latter gets dissolved when you click the mouse outside the selection, but a shape group is dissolved only by calling JS9.UngroupShapes().

This routine allows you to create a group by specifying the shapes which will compose it. The first argument is the shape layer. The second argument is the regions selection. If not specified, it defaults to either "selected" or "all", depending on whether a shape selection currently exits.

The optional opts argument contains the following properties:

- groupid: the group id to use, if possible (default: "group_[n]")
- select: if false, the group is not selected upon creation

By default, the groupid will be the string "group_" followed by an integer chosen so that the groupid is unique. You can supply your own groupid, but if it already is associated with an existing group, an integer value will be appended to make it unique. Also, by default the newly created group will be "selected". You can pass the select property with a value of false in order to avoid selecting the group (e.g., if you are creating a number of groups and don't want to see each of them selected in turn.)

The returned groupid string can be used to select and process all the shapes in that group. Thus, for example, you can use the groupid to change the color of all grouped shapes:

        # make a group from all circles having the tag foo1
        gid = JS9.GroupShapes("myregions", "circle && foo1");

        # change color of all shapes in the group
        JS9.ChangeShapes("myregions", gid, {"color":"red"});

Note however, that unlike the temporary shape selections, shapes in a group are not available individually, i.e., a shapes selection using a non-groupid does not match shapes inside a group. Thus, for example, if you have created a group of circles, changing the color using a "circle" specification does not affect circles within the group:

        # make a group from all circles having the tag foo1
        gid = JS9.GroupShapes("myregions", "circle && foo1");

        # change color of circle shapes, but NOT including those in any group
        JS9.ChangeShapes("myregions", "circle", {"color":"cyan"});

        # change color of all shapes in the group
        JS9.ChangeShapes("myregions", gid, {"color":"red"});

Furthermore, a given shape can only be part of one group at a time. In the case where a shape already is part of an existing group, the globalOpts.regGroupConflict property determines how that shape is processed. The default is skip, meaning that the shape is silently skipped over when creating the new group. The alternative is error, which will throw an error.

To create a more temporary selection, see JS9.SelectShapes().

##### Dissolve a Group of Shapes

`JS9.UngroupShapes(layer, groupid, opts)`

where:

- layer: shape layer
- groupid: group id of the group to dissolve
- opts: optional object containing ungrouping options

This routine allows you to dissolve an existing group, so that the shapes contained therein once again become separate. The first argument is the shape layer. The second argument is the groupid, previously returned by the JS9.GroupShapes() call.

The optional opts argument contains the following properties:

- select: newly separate shapes in the group are "selected"?

By default, the ungrouped shapes unobtrusively take their place among other shapes on the display. You can make them be selected by passing the select: true property in opts. Doing this, for example, would allow you to remove them easily with the Delete key.

For example:

        # group all circles and ellipses
        gid = JS9.GroupShapes("myregions", "circle || ellipse");

        # ungroup so the shapes are again separate
        JS9.UngroupShapes("myregions", gid)

        # change color of circle shapes, including the newly ungrouped ones
        JS9.ChangeShapes("myregions", "circle", {"color":"cyan"});

##### Load an astronomical catalog

`JS9.LoadCatalog(layer, table, opts)`

where:

- layer: name of shape layer into which to load the catalog
- table: string or blob containing the catalog table, or file name
- opts: catalog options

Astronomical catalogs are a special type of JS9 shape layer, in which the shapes have been generated from a tab-delimited text file of columns, including two columns that contain RA and Dec values. An astronomical catalog can have a pre-amble of comments, which, by default, have a '#' character in the first column.

Two examples of catalog files are shown below:

      ra        	dec        	magj	magh	magk
      -----------	------------	------	----	----
      23:22:56.003	58:44:45.429	15.612	15.103	14.9
      23:22:56.230	58:45:32.011	13.723	13.174	12.981
      23:22:56.319	58:45:08.954	14.212	13.119	12.723
      ...

      #
      #   VizieR Astronomical Server vizier.u-strasbg.fr
      # ...
      #Coosys	J2000:	eq_FK5 J2000
      # ...
      #Title: 2MASS All-Sky Catalog of Point Sources (Cutri+ 2003)
      # ...
      #Column	_RAJ2000	(A12)		[ucd=pos.eq.ra]
      #Column	_DEJ2000	(A12)		[ucd=pos.eq.dec]
      #Column	RAJ2000	(F10.6)		[ucd=pos.eq.ra;meta.main]
      #Column	DEJ2000	(F10.6)		[ucd=pos.eq.dec;meta.main]
      #Column	2MASS	(a17)		[ucd=meta.id;meta.main]
      # ...
      #Column	Aflg	(I1)		[ucd=meta.code]
      _RAJ2000	_DEJ2000	RAJ2000	DEJ2000	2MASS	Jmag	e_Jmag	Hmag	  e_Hmag	Kmag	e_Kmag	Qflg	Rflg	Bflg	Cflg	Xflg	Aflg
      ------------	------------	----------	----------	-----------------	------	------	------	------	------	------	---	---	---	---	-	-
      23 22 56.002	+58 44 45.43	350.733342	+58.745953	23225600+5844454 	15.612	 0.064	15.103	 0.078	14.900	 0.121	AAB	222	111	ccc	0	0
      23 22 59.647	+58 44 56.84	350.748531	+58.749123	23225964+5844568 	15.580	 0.063	14.922	 0.072	14.506	 0.079	AAA	222	111	c00	0	0
      23 22 56.981	+58 44 44.61	350.737422	+58.745724	23225698+5844446 	14.920	 0.049	14.292	 0.049	14.002	 0.055	AAA	222	111	ccc	0	0
      ...

Notice that both files have a tab-delimited header, followed by a tab-delimited line of dashes, followed by tab-delimited data rows. This file format is sometimes called "tsv" or "tab-separated values". A very useful astronomical package for manipulating tables is Starbase, written by John Roll.

The JS9.LoadCatalog() routine will read a file in this format, processing the data rows by converting the RA and Dec values into image position values that will be displayed as shapes in a new catalog layer.

The first argument to the JS9.LoadCatalog() routine is the name of the shape layer that will contain the objects in the catalog. Specifying the name of an existing layer is valid: previous shapes in that layer will be removed.

The second argument is either a blob or a string containing the table data described above. Blobs are the result of loading a local file into the browser (e.g., the load catalog menu option), while strings result from a remote XHR call (e.g., the Archives and Catalogs plugin.) Alternatively, the second string argument can be a file name or URL to load. File names are distinguished from strings containing a table in that the latter must contain at least one tab.

The third argument is an optional object used to specify parameters, including:

- xcol: name of the RA column in the table (default is a heuristic, see below)
- ycol: name of the Dec column in the table (default is a heuristic, see below)
- wcssys: WCS system (FK4, FK5, ICRS, galactic, ecliptic) (default is from globalOpts)
- shape: shape of catalog object (default is from globalOpts)
- color: color of catalog shapes (default is from globalOpts)
- width: width of box catalog shapes (default is from globalOpts)
- height: height of box catalog shapes (default is from globalOpts)
- radius: radius of circle catalog shapes (default is from globalOpts)
- r1: r1 of ellipse catalog shapes (default is from globalOpts)
- r2: r2 of ellipse catalog shapes (default is from globalOpts)
- save: save the catalog properties for each generated shape (default is from globalOpts)
- tooltip: format of tooltip string to display for each object (default is from globalOpts)
- skip: comment character in table file (default is from globalOpts)

Most of these properties have default values that are stored in the JS9.globalOpts.catalogs object: manipulate that object as needed. The values listed above also can be changed by users via the Catalog tab in the Preferences plugin.

The opts object also can include an onload property containing a function to be called when the load is complete. The image handle is passed as an argument to this function.

Note the second (Vizier) example table above does not actually have a columns called "RA" and "Dec". Instead, it has "_RAJ2000", "_DEJ2000", "RAJ2000", and "DEJ2000" columns. In order to pick RA and Dec column, a heuristic is used based on the values contained in the JS9.globalOpts.catalogs.ras and JS9.globalOpts.catalogs.decs arrays:

- the opts.xcol, if defined, specifies the RA column (similarly for opts.ycol and the Dec column)
- otherwise try to match exactly the catalog header against all the array elements in JS9.globalOpts.catalogs.ras to get the RA column (same for catalogs.decs)
- if no exact match, try a case-insensitive match of the catalog columns against a regular expression that begins with the first array element in JS9.globalOpts.catalogs.ras (e.g., "RA*")
- if no approximate match, try a case-insensitive match of the catalog columns against a regular expression containing the first array element in JS9.globalOpts.catalogs.ras (e.g., "*RA*")

The default global JS9.globalOpts.catalogs.ras contains:

      ras:  ["RA", "_RAJ2000", "RAJ2000"]
      decs: ["Dec", "_DEJ2000", "DEJ2000"]

These defaults make it easy to process simple catalogs and Vizier catalogs.

Once the RA and Dec columns are specified, the RA and Dec values from each row are converted into image positions, and JS9 shapes are generated to be displayed in the new catalog layer. The WCS system used to convert RA and Dec into image coordinates can be specified using the opts.wcssys or JS9.globalOpts.catalogs.wcssys properties.

The RA and Dec of the catalog object are always saved in the data object of each generated shape, for use in the tooltip string. In addition, if opts.save (or the default: JS9.globalOpts.catalogs.save) property is not false, all of the catalog object properties will also be save in the data object for use in the tooltip string, e.g.:

      opts.tooltip = "$xreg.data.ra $xreg.data.dec $xreg.data.Qflg $xreg.data.Rflg"

in the above VizieR example. Caveat: any "." (dot) in any catalog property name will be converted to "_" (underscore) automatically. For a more detailed discussion of tooltips, please see JS9.NewShapeLayer().

When catalog layer has been created, you can use the Shape Layers plugin to toggle its visibility and also to change its position in the layer stack.

##### Save an astronomical catalog to a file

`JS9.SaveCatalog(filename, which)`

where:

- filename: output file name
- which: layer containing catalog objects to save

Save the specified catalog-containing layer as a text file. If filename is not specified, the file will be saved as [layer].cat.

Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.

If the which argument is not specified, the catalog associated with the current active layer will be saved. In either case, the layer to save must actually be a catalog created from a tab-delimited file (or URL) of catalog objects (not, for example, the regions layer.)

#### Mouse/Touch Gestures

JS9 supports the following configurable mouse and touch actions:

- mouse movement with no buttons pressed
- mouse movement with one button pressed
- mouse movement with two buttons pressed
- touch with one finger
- touch with two fingers
- touch with three fingers

The initial actions are defined by the JS9.globalOpts.mouseActions and JS9.globalOpts.touchActions arrays. In addition, the JS9.globalOpts.mousetouchZoom property specifies whether a mouse wheel or touch/pinch will zoom the image. The default actions are:

- mouseActions: ["display value/position", "change contrast/bias", "pan the image"]
- touchActions: ["display value/position", "change contrast/bias", "pan the image"]
- mousetouchZoom: false

where the array elements map to an increasing numbers of buttons/fingers. You can change the default actions of the elements in either array in your js9prefs.js file. For example, to make pan and zoom the default one-touch and pinch actions respectively:

- touchActions: ["pan the image", "display value/position", "change contrast/bias"]
- mousetouchZoom: true

As usual, the defaults in js9prefs.js are used by all JS9 displays in a web page.

Users can change the action assignments using the MouseTouch plugin, which displays the current mapping between mouse/touch gesture and its action. Simply drag and drop an action to a different gesture in order to change the mapping. You also can toggle the scroll/pinch to zoom capability by clicking its button.

Web page developers can extend the available mouse and touch actions beyond the defaults contained in the Mouse Touch plugin. To add a new action, first write a function with the following calling sequence:

        gestureFunc(im, ipos, evt)

where:

- im: image handle
- ipos: image position object containing 1-indexed x and y image coordinate values
- evt: a JavaScript or jQuery event

Add this new function to the JS9.MouseTouchActions array, using a descriptive name as its array index, e.g.:

        JS9.MouseTouch.Actions["all contrast/bias"] = function(im, ipos, evt){
          var i, myim;
          for(i=0; i<JS9.displays.length; i++){
            myim = JS9.displays[i].image;
            if( myim ){
              JS9.MouseTouch.Actions["change contrast/bias"](myim, ipos, evt);
            }
          }
        };

At this point, the Mouse Touch Plugin will display the new function in its list of available actions. Users can move it into one of the defined gestures to activate it.

Of course, you can add the new action to the JS9.globalOpts.mouseActions and/or JS9.globalOpts.touchActions arrays to make it active immediately:

        JS9.globalOpts.mouseActions[1] = "all contrast/bias";
        JS9.globalOpts.touchActions[1] = "all contrast/bias";

Here, we have replaced the one-button mouse move and two-button touch move actions (whose defaults are to "change contrast/bias") with our new action.

#### Server-side Analysis

##### Get server-side analysis task definitions

`JS9.GetAnalysis()`

The JS9.GetAnalysis() routine returns an array of analysis task definitions, each containing the following information:

- name: a short identifier string (typically one word)
- title: a longer string that will be displayed in the Analysis menu
- files: a rule that will be matched against to determine whether this task is available for the current image
- purl: a URL pointing to a web page containing a user parameter form
- action: the command to execute on the server side
- rtype: a return type, which can be text, plot, fits, regions, catalog, alert, or none
- hidden: if true, the analysis task is not shown in the Analysis menu

Not every property listed above will be present in every task definition (e.g., purl is only present when there is a parameter form.) Also note that hidden tasks are not returned by this call.

##### Run a server-side analysis task

`JS9.RunAnalysis(name, parr, func)`

where:

- name: name of analysis tool
- parr: optional array of macro-expansion options for command line
- func: optional routine to call when analysis is completed on server

The JS9.RunAnalysis() routine is used to execute a server-side analysis task and return the results for further processing within the web page. The optional parr array of parameters is passed to the JS9 analysis macro expander so that values can be added to the command line. The array is in jQuery name/value serialized object format, which is described here:

        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:

- stdout: a string containing the standard output from the task
- stderr: a string containing the standard error from the task
- errcode: error code value from the task or 0
- aobj: the analysis object from the js9Analysis.json file, containing, among other things, the important rtype: "text" or "plot"

Typically, you would check stderr string first and issue an error message if there is an error. Otherwise, the stdout string can be processed based on the return type (rtype) property of the output (e.g., "text" or "plot".) For plotting, you can use flot functionality already loaded into JS9, or you can use your own chosen plotting package.

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.

Instead of passing a callback function each time, you can set the global property JS9.globalOpts.analysisFunc to a function having the same signature:

        func(stdout, stderr, errcode, aobj)

The specified function will be called for each execution of JS9.RunAnalysis

In addition, you can change the target of the analysis results display from a light window to your own div element by setting the global property JS9.globalOpts.analysisDiv to the id of your new target div. The div must have CSS height and width properties if you are going to plot results.

##### Run a server-side analysis task, utilizing parameters in a form

`JS9.SubmitAnalysis(el, name, func)`

where:

- el: form element (unused at present)
- name: name of analysis tool
- func: optional routine to call when analysis is completed on server

The JS9.SubmitAnalysis() routine is used to run an analysis task with input parameters from a form. Typically used as the Run button action in a form, it automatically serializes the form values and passes them to the JS9 analysis macro expander so that these values can be integrated into the analysis command line. See js9analysis.html for a simple example.

The func callback and global options are the same as for JS9.RunAnalysis() above.

#### Working with Displays

##### Display the Next (or Previous) Image

`JS9DisplayNextImage(n)`

where:

- n: number of images beyond (or prior to) the one currently displayed

The JS9.DisplayNextImage() routine displays the nth image in the display's image list beyond the currently displayed image. The default value for n is 1. You can supply a negative number to display an image prior to the current one in the display's image list.

##### Create a Mosaic Image

`JS9.CreateMosaic(which, opts)`

where:

- which: which images to use in the mosaic
- opts: mosaic options

The JS9.CreateMosaic() creates a mosaic image from the specified (previously-loaded) FITS images using the mProjectPP and mAdd programs from the Montage software suite. These Montage programs have been compiled into JS9 using Emscripten.

Because the browser environment is memory-limited, there are some restrictions on generating mosaics in JS9. The FITS files must be well-behaved, i.e., they must have WCS projections which can be approximated by tangent-plane projections (TAN, SIN, ZEA, STG, ARC.) This precludes creating mosaics from images covering large portions of the sky. For large sky areas, please use Montage itself on your desktop to create a mosaic. A simplified js9mosaic script is included in the JS9 distribution or, for more control, use the Montage programs directly. Of course, in either case, you must install Montage.

The which parameter determine which images are used in the mosaic:

- "current" or null: the current image in this display
- "all": all images in this display
- im: the image id or image handle of an image from any display
- [im1, im2, ...]: an array of image ids or handles from any display

In general, use "current" (or null) if you have loaded a multi-extension FITS mosaic (e.g., a CFHT FITS file) into JS9. Use "all" if you have loaded several FITS files into JS9 and want to create a mosaic.

In order to keep the size of the resulting mosaic within memory limits, JS9 reduces the size of each image before adding them all together The options parameter determines how the reduction is performed:

- dim: size of mosaic (def: max of JS9.globalOpts.image.[xdim,ydim])
- reduce: image size reduction technique: "js9" (def) or "shrink"
- verbose: if true, processing output is sent to the javascript console

The "dim" parameter is a target size: the larger of the resulting mosaic dimensions will be approximately this value, depending on how Montage processes the images. The "reduce" technique either runs internal JS9 image sectioning code (to produce smaller internal images, each of which are reprojected and added together) or runs the Montage mShrinkHdr code (which reprojects the full images into smaller files.) The former seems to be faster than the latter in most cases. The "verbose" parameter will display output on the JavaScript console to let you know that the CreateMosaic() call is running properly.

The resulting mosaic will be loaded into the specified JS9 display as a separate image. Because the mosaic is separate from the original image(s), you can view each of the latter individually (or view each image extension of a single image using the Extensions plugin.) Internal analysis can be performed on the mosaic (e.g., ImExam functions) but, of course, no external analysis tasks will be available.

##### Lookup a JS9 display

`dobj = JS9.LookupDisplay(dname, mustExist)`

where:

- dname: name of JS9 display to look up
- mustExist: whether to throw error if a dname display does not exist

returns:

- dobj: the JS9 display object

The JS9.LookupDisplay() routine returns the display object associated with the specified dname parameter. If no dname is specified, the first available display is returned.

If dname is specified but does not exist, an error is thrown unless the mustExist parameter is explicitly set to false (i.e., the default is that the id must exist.)

##### Resize the JS9 Display

`JS9.ResizeDisplay(dname, width, height, opts)`

where:

- dname: optional name of JS9 display to resize
- width: new width of the display in HTML pixels (or "full" or "reset")
- height: new height of the display in HTML pixels
- opts: optional object containing resize parameters

You can resize the JS9 display by supplying new width and height parameters. The div on the web page will be resized and the image will be re-centered in the new display. If the display size has been increased, more of the image will be displayed as needed (up to the new size of the display.) For example, if the original display was 512x512 and you increase it to 1024x1024, a 1024x1024 image will now be displayed in its entirety.

If the first argument is full, the display is resized to match the browser window.innerWidth and window.innerHeight variables, which are the width and height (in pixels) of the browser window viewport. You can then scroll the window so that the image fills the entire browser window. Alternatively, if the first argument is reset, the display is resized to match its original size.

The opts object can contain the following properties:

- resizeMenubar: change the width of the menubar as well

The default for resizeMenubar is true, so you only need to pass this property if you do not want to perform the resize.

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.

You can supply a display name as the first argument, or the display object:

        JS9.ResizeDisplay("myJS9", 350, 400);

or:

        JS9.ResizeDisplay(350, 400, {display: "myJS9"});

##### Move an image to a new JS9 display

`JS9.MoveToDisplay(dname)`

where:

- dname: name of JS9 display to which the image will be moved

The JS9.MoveToDisplay() routine moves the current image to the specified display:

        JS9.MoveToDisplay("myJS9", {display: "JS9"});

will move the current image displayed in the "JS9" display window to the "myJS9" window.

Note that the new JS9 display must already exist. New displays can be created with the JS9.LoadWindow() public access routine or the File:new JS9 light window menu option.

##### Gather other images to this JS9 Display

`JS9.GatherDisplay(dname, opts)`

where:

- dname: name of JS9 display to which the images will be gathered
- opts: optional object

This routine move all images in other displays to this display. You can supply a display name or the display object:

        JS9.GatherDisplay("myJS9");

or:

        JS9.GatherDisplay({display: "myJS9"});

You can supply an opts object containing the properties:

- images: array of image handles (or indexes into JS9.images array) to gather

##### Separate images in this JS9 Display into new displays

`JS9.SeparateDisplay(dname, opts)`

where:

- dname: name of JS9 display from which the images will be separated
- opts: optional object for layout properties

This routine moves each image in the specified display to a new display. You can supply a display name or the display object:

        JS9.SeparateDisplay("myJS9");

or:

        JS9.SeparateDisplay({display: "myJS9"});

You also can supply an opts object containing the properties:

- images: array of image handles (or indexes into JS9.images array) to separate
- layout: can be "horizontal", "vertical", "auto" (default: "auto")
- leftMargin: margin in pixels between horizontally separated images
- topMargin: margin in pixels between vertically separated images
- idbase: base string for ids of separated displays

By default, the new displays are all placed in light windows, whose positions can be adjusted on the screen as needed. The "horizontal" layout will generate a single row of images. The "vertical" layout will generate a single column of images. The "auto" option will layout the images in one or more rows. Each row will contain one or more images such that at least one-half of the right-most image is visible in the browser without the need for horizontal scrolling.

Note that you can supply the opts object without supplying the display parameter, e.g:

        JS9.SeparateDisplay({layout: "horizontal"});

will separate images from the default "JS9" display in a horizontal layout.

By default, the ids of the successive JS9 displays will consist of the original display id, followed by the string "_sep", followed by an increasing integer (not necessarily starting at 1.) If you pass the idbase property in the opts object, the id of each successive display will be the specified base id followed by an increasing integer that does start from 1. In the latter case, it is your responsibility to ensure that the new ids to not conflict with existing ids.

Instead of light windows to hold the new displays, you can also use the CSS Grid Layout to automatically position the new displays in ordinary div elements. To do this, the layout is set to "auto" and the initial display (along with its menubar, colorbar, statusbar) is wrapped in two divs:

- an outer div of class JS9GridContainer
- an inner div of class JS9GridItem

If a browser supports CSS Grid Layout (most do as of 2017), a grid layout will be used. Otherwise, light windows will be used. For example:

        <div class="JS9GridContainer">
        <div class="JS9GridItem">
            <div class="JS9Menubar" id="JS9Menubar"></div>
            <div class="JS9" id="JS9"></div>
            <div class="JS9Statusbar"></div>
        </div>
        </div>

The outer JS9GridContainer div is associated with the CSS Grid container (i.e. its display property is set to grid.) The inner JS9GridItem div delineates the contents of the "item" that will added to the container when the displays are separated.

You can tailor the layout by adding Grid Layout CSS directives to JS9GridContainer. In particular, style elements such as grid-template-columns and grid-gap are applied to this div:

          div.JS9GridContainer {
    	  grid-template-columns: repeat(3, 1fr);
    	  grid-gap: 10px;
          }

See CSS Grid Layout for more information about CSS Grids.

##### Scroll the JS9 display to the center of the viewport

`JS9.CenterDisplay(dname)`

where:

- dname: name of JS9 display to center

This routine scrolls this display to the center of the viewport. You can supply a display name or the display object:

        JS9.CenterDisplay("myJS9");

or:

        JS9.CenterDisplay({display: "myJS9"});

##### Rename the id of a JS9 display

`JS9.RenameDisplay(oid, nid)`

Calling sequences:

        JS9.RenameDisplay(nid)        # change default id (usually "JS9") to nid
        JS9.RenameDisplay(oid, nid)   # change oid to nid

where:

- oid: old name of JS9 display
- nid: new name of JS9 display

This routine is used by the Desktop version of JS9 to implement the --title (and --renameid) switch(es), which change the id of the JS9 display(s) to the specified id(s). Once an id has been renamed, external communication (via the js9 script or pyjs9) should target the new id instead of the original id.

If also can be used in the query part of a URL when loading a web page in order to rename a display, e.g.:

      https://js9.si.edu?renamedisplay=myJS9

will rename the default display. In cases where multiple displays are defined on a page:

      https://js9.si.edu/js9/tests/js9debug.html?renamedisplay=myJS9:yourJS9

will rename the myJS9 display (but not the JS9 display).

The original id is still available internally, so Javascript public API calls (but not external scripts) on the web page itself can target either the original or the new id using the {display: "id"} syntax.

##### Close all images in a display

`JS9.CloseDisplay(dname, regexp)`

where:

- dname: name of JS9 display whose images will be closed
- regexp: optional regular expression to specify which images to close

By default, his routine closes all images in the specified display. You can supply a display name as the first argument or the display object:

        JS9.CloseDisplay("myJS9");

or:

        JS9.CloseDisplay({display: "myJS9"});

If a regular expression is specified as second argument, only images matching that regular expression will be closed. For example:

      JS9.CloseDisplay("JS9", ".*mask.fits.gz");

will close all mask files. As a convenience, you can omit the display argument and specify the template as the first argument:

      JS9.CloseDisplay(".*mask.fits.gz");

##### Close all images in a display and remove the display

`JS9.RemoveDisplay(dname)`

where:

- dname: name of JS9 display to remove

This routine will close all images in the specified display and then remove the display. It is available for displays contained in light windows and for displays contained in JS9 Grid Containers. When removing the display inside a light window, the light window is immediately closed without a confirmation dialog box (unlike a light window being closed via its close button.) For a display inside a JS9 Grid Container, the display is removed from the DOM, so that it no longer is part of the grid layout. Note, however, that you cannot remove all displays from a grid container: at least one display must be left in the container.

#### Miscellaneous

##### Print an image

`JS9.Print(opts)`

where:

- opts: options for print

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.

##### Print the desktop window (desktop app only)

`JS9.WindowPrint(opts)`

where:

- opts: options for print

The JS9 desktop application that utilizes Electron.js has the ability to print the whole application window. When executed, the system print dialog box is displayed (unless the silent the option is passed in opts) and the window will be printed according to your print configuration.

The first argument allows you to specify the following options:

- silent: don't ask user for print settings (def: false)
- printBackground: prints the background color and image of the web page (def: true)
- deviceName: set the printer device name to use (def: "")

##### Save the desktop window to a PDF file (desktop app only)

`JS9.WindowToPDF(filename, opts)`

where:

- filename: PDF file name
- opts: options for save

The JS9 desktop application that utilizes Electron.js has the ability to save the whole application window to a PDF file. The first argument specifies the name of the PDF file.

The second argument allows you to specify the following options:

- marginsType: the type of margins to use: 0 for default margin, 1 for no margin, and 2 for minimum margin
- pageSize: page size of the generated PDF: A3, A4, A5, Legal, Letter, Tabloid (NB: might not work with all printers)
- printBackground: prints the background color and image of the web page (def: true)
- printSelectionOnly: whether to print selection only (NB: This seems to crash the application!)
- landscape: true for landscape, false for portrait

##### Set the save directory for downloads (desktop app only)

`JS9.SaveDir(dirname)`

where:

- dirname: directory name for downloads

The JS9 desktop application that utilizes Electron.js has the ability to specify a directory into which files will be saved (e.g., by routines such JS9.SavePNG()) without using a dialog box. This is especially useful in scripts.

The savedir directory can be specified on the desktop command line using the --savedir switch:

        js9 -a --savedir $HOME/tmp ~/data/casa.fits

But you can use this routine to set or change the save directory at any time:

        js9 SaveDir "$HOME/tmp"

Future downloads for this desktop session will then be saved (without use of a dialog box) to the specified directory.

It's worth remembering that relative paths are taken relative to the directory in which the JS9 app was started, not the current directory in which you are running the js9 SaveDir command. To avoid confusion, it is recommended that you supply a full path.

##### Quit the JS9 app (desktop app only)

`JS9.Quit()`

For the Desktop app only, this command will quit the app.

##### Save image as a FITS file

`JS9.SaveFITS(filename, opts)`

where:

- filename: output file name
- opts: optional opts or "display"

Save the currently displayed image as a FITS file. If filename is not specified, the file will be saved as "js9.fits".

If a second argument is supplied, it can be the string "display" or an object containing the property "source". If "display" or opts.source is "display" is passed, the currently displayed image section is saved. Otherwise, the full image (or extracted image section, if appropriate) is saved.

Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.

##### Save image as a PNG file

`JS9.SavePNG(filename, opts)`

where:

- filename: output file name
- opts: optional save parameters

Save the currently displayed image as a PNG file. If filename is not specified, the file will be saved as "js9.png". The image is saved along with the graphical overlays (regions, etc..)

The opts object can specify the following properties:

- layers: save graphical layers (e.g., regions) (default is true)
- source: "image" or "display" (default is "display")

By default, SavePNG() will save all of the 2D graphics in the shape layers (regions, catalogs, etc.) as well as the image. Set the layers property to false to save only the image.

Also by default, SavePNG() will save the RGB pixels from the display. This means, for example, that a blended set of images will save the blended pixels. If you want to save the RGB pixels from one of the images in a blended image, you can specify the source property to the image. For example, in the js9blend.html demo, you can save the RGB pixels of the Chandra image by specifying use of the "image" source and specifying the image's id in the display parameter:

        JS9.SavePNG("chandra.png", {source:"image"}, {display:"chandra.fits"});

Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.

##### Save image as a JPEG file

`JS9.SaveJPEG(filename, opts)`

where:

- filename: output file name
- opts: optional save parameters or a number between 0 and 1 indicating image quality

Save the currently displayed image as a JPEG file. If filename is not specified, the file will be saved as "js9.jpeg". The image is saved along with the graphical overlays (regions, etc..)

The opts object can specify the following properties:

- layers: save graphical layers (e.g., regions) (default is true)
- source: "image" or "display" (default is "display")
- quality: JPEG encoder quality

By default, SaveJPEG() will save all of the 2D graphics in the shape layers (regions, catalogs, etc.) as well as the image. Set the layers property to false to save only the image.

Also by default, SaveJPEG() will save the RGB pixels from the display. This means, for example, that a blended set of images will save the blended pixels. If you want to save the RGB pixels from one of the images in a blended image, you can specify the source property to the image. For example, in the js9blend.html demo, you can save the RGB pixels of the Chandra image by specifying use of the "image" source and specifying the image's id in the display parameter:

        JS9.SaveJPEG("chandra.png", {source:"image"}, {display:"chandra.fits"});

If encoder quality parameter is not specified, a suitable default is used. On FireFox (at least), this default values is 0.95 (I think.)

Don't forget that the file is saved by the browser, in whatever location you have set up for downloads.

##### Upload currently displayed FITS file to proxy server

`JS9.UploadFITSFile()`

Upload the currently displayed FITS file to the proxy server, so that back-end analysis can be performed. This routine requires that a Node.js-based JS9 helper is running and that the helper has enabled the loadProxy property and set up a workDir directory in which to store the FITS file.

##### Get FITS header as a string

`JS9.GetFITSHeader(nlflag)`

where:

- nlflag: true if newlines should added to each card

Return the FITS header as a string. By default, the returned string contains the 80-character FITS cards all concatenated together. If nlflag is true, each card will have a new-line appended.

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:

- name: name of a help file or url of a web site to display

The help file names are the property names in JS9.helpOpts (e.g., "user" for the user page, "install" for the install page, etc.) Alternatively, you can specify an arbitrary URL to display (just because.)

##### Display plugin in a light window

`JS9.DisplayPlugin(name)`

where:

- name: name of the plugin

Toggle the light-window display of the named plugin, as is done by the View and Analysis menus. That is, if the plugin is not visible, make it visible. If the plugin is visible, hide it.

You can supply the full class and plugin name or just the name, using exact case or lower case, e.g.:

- JS9Panner or panner
- JS9Magnifier or magnifier
- JS9Info or info
- JS9Console or console
- DataSourcesArchivesCatalogs or archivescatalogs
- FitsBinning or binning
- ImExamEncEnergy or encenergy
- ImExamPxTabl or pxtabl
- ImExamRadialProj or radialproj
- ImExamHistogram or histogram
- ImExamRegionStats or regionstats
- ImExamXProj or xproj
- ImExamYProj or yproj
- ImExam3dPlot or 3dplot
- ImExamContours or contours

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.

##### Display content in a light window

`JS9.LightWindow(id, type, content, title, opts)`

where:

- id: unique id for light window div(default: "lightWindow" + uniqueID)
- type: content type: "inline", "div", "ajax", "iframe" (default: "inline")
- content: content of the light window (default: none)
- title: title (default: "JS9 light window")
- opts: configuration string (default: "width=830px,height=400px,center=1,resize=1,scrolling=1")

Display arbitrary content inside a light window. There are any number of light window routines available on the Net. JS9 uses light window routines developed by Dynamic Drive (http://www.dynamicdrive.com). Their extensive documentation can be found here.

The content shown inside the window depends on the content parameter:

- iframe: the URL of the page to display (ie: "http://www.google.com")
- inline: the HTML to display (back-slashing any special JavaScript characters, such as apostrophes)
- ajax: the relative path to the external page to display, relative to the current page (ie: "../external.htm")
- div: define a DIV element on the page with a unique ID attribute (probably hidden using style="display:none") and the use the DIV's id as the content value

JS9 typically uses the inline option. Note that web sites often do not allow themselves to be embedded in an iframe, so this is an unreliable option.

The opts parameter specifies options for the light window, such as its size. This parameter consists of a string with comma-separated keywords, e.g.:

        "width=830px,height=400px,center=1,resize=1,scrolling=1"

The opts keywords, defined in the Dynamic Drive documentation, are: width, height, left, top, center, resize, and scrolling. The JS9.lightOpts.dhtml object defines oft-used lightwin configurations, and the JS9.lightOpts.dhtml.textWin property is used as the default for this call. You can utilize these properties in your own call to JS9.LightWindow() or make up your own configuration string.

As an extension to the Dynamic Drive light window support, JS9 adds the ability to double-click the title bar in order to close the window.

##### 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 toolbar values from the Toolbar plugin

`val = JS9.GetToolbar(type)`

where:

- type: type of information to retrieve

returns:

- val: array of tool objects (or an argument-dependent return)

The JS9.GetToolbar() routine returns global information about the Toolbar plugin. If the first argument is "showTooltips", the returned value specifies whether tooltips are currently displayed. Otherwise an array of tool objects is returned, one for each of the defined tools in the toolbar.

##### Set toolbar values for the Toolbar plugin

`JS9.SetToolbar(arg1, arg2)`

where:

- arg1: a type-dependent id or value to set
- arg2: a type-dependent value to set

The JS9.SetToolbar() routine sets global information about the Toolbar plugin. The following values can be specified as the first argument:

- init: the text "init" triggers a re-initialization of all display Toolbar plugins, which is useful if you have changed the JS9.globalOpts.toolBar array to specify a new set of top-level tools.
- showTooltips: the text "showTooltips" uses the value of the boolean arg2 to specify whether tooltips are displayed as the mouse hovers over a tool.
- [text]: other text is assumed to be a JSON-formatted text containing either a new tool to add to the toolbar, or an array of tools.
- [object]: an object is assumed to be new tool to add to the toolbar
- [array]: an array is assumed to be an array of new tools to add to the toolbar

New tools can be added to the toolbar at any time using this routine. The text properties associated with a tool object are:

- name: name of the tool
- tip: a tooltip to display when the mouse hovers over the tool
- image: url (relative to the install directory) containing a PNG image file to display as the tool icon
- cmd: name of the JS9 public routine to execute when the tool is clicked
- args: array of arguments to pass to the JS9 public routine

Only the name and cmd properties are required. If no image is specified, a button labeled by the name value will be used.

Examples of tool objects:

      {
        "name": "linear",
        "tip": "linear scale",
        "image": "images/toolbar/dax_images/lin.png",
        "cmd": "SetScale",
        "args": ["linear"]
      },
      {
        "name": "histeq",
        "tip": "histogram equalization",
        "cmd": "SetScale",
        "args": ["histeq"]
      },
      {
        "name": "annulus",
        "tip": "annulus region",
        "image": "images/toolbar/dax_images/annulus.png",
        "cmd": "AddRegions",
        "args": ["annulus"]
      },
      {
        "name": "remove",
        "tip": "remove selected region",
        "image": "images/toolbar/dax_images/erase.png",
        "cmd": "RemoveRegions",
        "args": ["selected"]
      },
      {
        "name": "zoom1",
        "tip": "zoom 1",
        "image": "images/toolbar/dax_images/mag_one.png",
        "cmd": "SetZoom",
        "args": [1]
      },
      {
        "name": "magnifier",
        "tip": "toggle magnifier display",
        "image": "images/toolbar/dax_images/mag.png",
        "cmd": "DisplayPlugin",
        "args": ["JS9Magnifier"]
      }

Each time a tool is added to the list of available tools, the active Toolbar plugins will be re-initialized to display that tool. By default, the new tool not be added to the top-level list: you must also edit the JS9.globalOpts.toolBar array to add the name of the tool. If this is done after you add the tool, remember to re-initialize active toolbars by calling:

        JS9.SetToolbar("init");

##### Get location of JS9 installation directory

`rpath = JS9.InstallDir(file)`

where:

- file: file or directory to convert

returns:

- rpath: path of the file relative to the JS9 install directory

Sometimes a plugin needs to load an auxiliary file inside the plugins sub-directory. The web page loading the plugin has an arbitrary location relative to the JS9 install directory, so this routine returns a relative path to the js9 install directory.

##### Send a message to a back-end server

`JS9.Send(msg, obj, cb)`

where:

- msg: name of the msg, as defined in the back-end server
- obj: object containing msg parameters
- cb: callback to call when back-end server returns its results

JS9 sends various internal messages to the back-end server using either socket.io protocol (in the Node.js implementation) or CGI. For example, when a remote analysis call is made, JS9 sends a message to the back-end server detailing the task to call, parameters to pass, etc. Results are then returned to JS9 for display. JS9 also sends messages to the back-end server when a new image is displayed.

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:

- id1, id2, ...: optional name(s) of new JS9 display div(s)

You can add new JS9 displays and/or plugins dynamically. To do this, you create the new divs, add them to the web page, and then call this routine to incorporate them into JS9.

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

You can use JS9.LoadWindow() to load images into a light-weight or completely new window. To do this with your own routine, you should call JS9.AddDivs() after the window has been created. You can use the jQuery arrive wrapper that implements support for the MutationObserver:

        // once the window exists containing the div id, we can finish the set up
        $("#window").arrive("#"+id, {onceOnly: true}, function(){
            finishUp();
        });
        // (make-believe) create light win routine, where id is the window div id
        myCreateLightWindow(id, html, title, opts);

##### Instantiate plugins on this web page

`JS9.InstantiatePlugins()`

Normally, JS9 will instantiate all of its plugins automatically once the page is loaded and ready: internally, jQuery $(document).ready() calls JS9.init(). However, module loaders such as Require.js can load scripts asynchronously and cause jQuery $(document).ready() to fire before all JS9 scripts are available. The JS9.RegisterPlugin() routine should deal properly with this situation. But just in case ... the JS9.InstantiatePlugins() will perform the plugin instantiation explicitly.

In you find you need to call this routine in order make your in-page plugins display properly, please let us know the circumstances.

#### Prototype Routines (not ready for prime time)

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.

#### API Change History

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.

##### 20220408: Change the calling sequence to global ongroupcreate callback

The global JS9.Regions.opts.ongroupcreate callback has the calling sequence:

    ongroupcreate: ongroupcreate(id, im, xreg);

    where:

     id: group id
     im: the image handle for the currently displayed image
     xreg: an array of shape objects within the group

The old calling sequence did not pass the group id, but instead passed the event which triggered the group creation in the last argument ... which doesn't make sense for an API call.

##### 20200815: ChangeRegions, CopyRegions, GetRegions, RemoveRegions, SelectRegions, : default region changed

If the regions argument is not specified, it now defaults to "selected" if there are selected regions, otherwise "all". Previously it only default to "all". You can revert to the previous behavior by changing the JS9.globalOpts.regWhichDefault from "auto" to "all". (Note: unless you are writing a GUI, you almost certainly should be specifying the regions explicitly for these calls).

##### 20200720: ChangeRegions: dx, dy properties renamed to deltax, deltay

The dx, dy properties of JS9.ChangeRegions allowed you to specify a delta to add to the current image position. For consistency, these properties were renamed to deltax, deltay respectively.

##### 20200623: SetFlip and SetRot90 no longer manipulate the image data

The original implementation of JS9.SetFlip and JS9.SetRot90 manipulated the underlying image data, changing the WCS as needed. This behavior was inconsistent with other routines: e.g. image processing routines only change the displayed data, while explicit raw data routines such as JS9.ReprojectData change the underlying image in accordance with the rules for manipulating raw data. We therefore re-implemented these routines (and added JS9.SetRotate) so that they change the orientation of the canvas, rather than the underlying image data. This implies that the WCS headers are no longer changed by flipping and rotating.

##### 20200207: remove DisplaySection +N and -N binning options

The DisplaySection() routine originally supported "+N" and "-N" binning options to change the current bin by "N". With the addition of support for fractional binning, these two constructs conflict with the use of negative bin values to indicate 1/abs(N) binning.

##### 20200114: Remove experimental LoadAuxFile routine

Regions can be loaded using JS9.LoadRegions. Masks are now supported by loading a mask image and calling JS9.MaskImage.

##### 20180322: DisplaySection now uses current values for unspecified properties

Prior to JS9 version 2.1, JS9.DisplaySection() always used the center of the file, along with dimensions and binning specified by the JS9.globalOpts.table and JS9.globalOpts.image objects, if these properties were not explicitly specified. This was just wrong: it meant that you could not set up a section and then repeated change the filter or position without re-specifying the current section parameters. We therefore changed the default behavior so that unspecified properties take on the current values. To use the original defaults, simply specify 0 for xcen and ycen, and use the globalOpts values for dimensions and binning.

##### 20151218: OpenFileMenu and OpenRegionsMenu don't require a display argument

The routines JS9.OpenFileMenu() and JS9.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 (JS9.SetZoom(), JS9.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 JS9.RunAnalysis() (and its derivative function, JS9.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.

##### Last updated: June 10, 2021