Stellarium  24.4
RemoteControl plugin web interface

The RemoteControl plugin, by default, provides a HTML web interface through the same integrated HTTP server that serves the RemoteControl API. All content found in the data/webroot folder is served. Note that the /api/ path is reserved for the HTTP API, and therefore can not be used as a folder. The index.html file is mapped to the root, so you can access it using http://localhost:8090 with the default port setting of 8090. A slightly modified alternative interface (mainly larger buttons for now) for 7" tablets and other touch devices is available at http://localhost:8090/tablet7in.html.

A reasonably modern browser is required to access the interface. Some features of HTML5 and CSS3 are used.

The interface heavily relies on jQuery for easier JavaScript coding. The code is structured into modules, and loaded using require.js, which automatically resolves dependencies and load order.

File and directory structure

Note that not all files are listed here, only those of special interest.

Editing the interface

With knowledge of HTML, CSS and JavaScript (the latter not required for basic modifications), the interface can be customized.

Basic extension

When using the standard JavaScript provided, they allow to use pre-defined CSS "marker" classes which do not style the element per-se (i.e. have no entries in the .css files), but allow you to add functionality to HTML elements without editing the JavaScript code. Some of these classes also allow you to add further attributes to the element (usually HTML5 data attributes) to further customize their behaviour.

UI control classes

Some classes allow generating UI controls that are similar to what you expect for desktop apps. These use jQuery UI with some modifications.

spinner

If added to an HTML input element, it sets the control up as a numerical Spinner widget (using jQuery UI: https://api.jqueryui.com/spinner/). It supports the following optional parameters:

  • data-min - Defines the minimum value of the spinner
  • data-max - Defines the maximum value of the spinner
  • data-step - Defines the desired step size of the spinner, default is 1. May be different from the number format.
  • data-numberformat - Defines how the number is formatted, using globalize.js 0.1.1 syntax

The element will emit the custom spinuserinput event whenever the value changes (either through the buttons or direct keyboard input). An example, showing how a spinner is created and handled:

//make a spinner from -50 to 50, always showing 2 decimal points and stepping 0.1 per click
<input id="myspinner" class="spinner" data-min="-50" data-max="50" data-step="0.1" data-numberformat="n2"/>
//input handling in javascript
$("#myspinner").on("spinuserinput", function(evt,ui) {
//print the new value
console.log(ui.value);
});

slider

If added to an HTML div element, it sets the control up as a numerical slider widget (using jQuery UI: https://api.jqueryui.com/slider/). It supports the following optional parameters:

  • data-min - Defines the minimum value of the slider
  • data-max - Defines the maximum value of the slider
  • data-step - Defines the desired step size of the slider, default is 1. May be different from the number format.

The element will emit the slide event when the slider is moved.

//make a slider from -50 to 50, stepsize 0.1
<div id="myslider" class="slider" data-min="-50" data-max="50" data-step="0.1"/>
//input handling in javascript
$("#myslider").on("slide", function(evt,ui) {
//print the new value
console.log(ui.value);
});

jquerybutton

If added to an HTML button element, it converts it to a jQuery UI button. This is mainly a cosmetic operation.

selectmenu

If added to an HTML select element, it creates a jQuery UI selectmenu from it. This allows simple popup selection menus (like a QComboBox).

Special behaviour classes

These classes allow automatic connection to StelProperty and StelAction elements defined in Stellarium, allowing particularly easy extension of the web interface.

stelproperty (Connection to StelProperty)

Allows direct connection of an element to a StelProperty, meaning the element is automatically updated whenever the value in Stellarium changes — regardless of the source of the change: it can come from the main GUI, scripting, or even other RemoteControl web interface instances! Together with the UI control classes listed above, this allows closely and easily recreating standard Stellarium interface elements. This is supported for:

  • input elements with the spinner class (for numerical properties)
    The StelProperty to use is identified by the standard input attribute name. Updates the value property of the input when the StelProperty changes, and reacts to spinuserinput events to update the property
  • input elements of type checkbox (<input type="checkbox"> (for boolean properties)
    The StelProperty to use is identified by the standard input attribute name. Uses the checked property and the click event.
  • div elements with the slider class (for numerical properties)
    The StelProperty to use is identified by the custom attribute data-prop. Connects to the slider widget property value.
  • select elements (also supports the optional selectmenu class)
    The StelProperty to use is identified by the standard select attribute name. Sets the option that has the same value as the StelProperty value. Useful for single selection out of a list of possibilities.
  • span elements, for read-only property display with optional number format
    The StelProperty to use is identified by the custom attribute data-prop. The value is displayed using the element's text content. The optional data-numberformat attribute is used for the number format using globalize.js 0.1.1 syntax
  • button or input[type="button"] elements, for write-only setting of a StelProperty to a pre-defined value when clicked
    The StelProperty to use is identified by the standard attribute name, and the value to set it to is defined by the attribute value.

An example, setting up a spinner for the MilkyWay.intensity StelProperty:

<!-- this is all that is required, the rest is done automatically -->
<input class="spinner stelproperty" name="MilkyWay.intensity" data-min="0" data-max="10" data-step="0.1" data-numberformat="n2"/>

Many more examples can be found by studying the index.html code.

stelaction (Connection to StelAction)

When this class is added to button elements or input elements of type="button" or type="checkbox", this connects the control to a StelAction. The action is identified by the name attribute. If the action is a boolean action (i.e. StelAction::isCheckable is true), checkboxes show the current state of the action, and buttons get the active CSS class assigned if the action is currently true.

Examples:

<!-- This is how the main bottom button bar is defined -->
<ul class="ui-corner-all ui-widget-content button32list margin-vertical">
<li><button class="stelaction icon32 btConstellationLines" name="actionShow_Constellation_Lines"></button></li>
<li><button class="stelaction icon32 btConstellationLabels" name="actionShow_Constellation_Labels"></button></li>
<li><button class="stelaction icon32 btConstellationArt" name="actionShow_Constellation_Art"></button></li>
<li><button class="stelaction icon32 btEquatorialGrid" name="actionShow_Equatorial_Grid"></button></li>
<li><button class="stelaction icon32 btAzimuthalGrid" name="actionShow_Azimuthal_Grid"></button></li>
<li><button class="stelaction icon32 btGround" name="actionShow_Ground"></button></li>
<li><button class="stelaction icon32 btCardinalPoints" name="actionShow_Cardinal_Points"></button></li>
<li><button class="stelaction icon32 btAtmosphere" name="actionShow_Atmosphere"></button></li>
<li><button class="stelaction icon32 btNebula" name="actionShow_Nebulas"></button></li>
<li><button class="stelaction icon32 btPlanets" name="actionShow_Planets_Labels"></button></li>
<li><button class="stelaction icon32 btEquatorialMount" name="actionSwitch_Equatorial_Mount"></button></li>
<li><button class="stelaction icon32 btGotoSelectedObject" name="actionSet_Tracking"></button></li>
<li><button class="stelaction icon32 btNightView" name="actionShow_Night_Mode"></button></li>
<li><button class="stelaction icon32 btFullScreen" name="actionSet_Full_Screen_Global"></button></li>
</ul>
<!-- This is how to set up checkboxes -->
<label><input type="checkbox" class="stelaction" name="actionShow_Planets" /><?= tr("Show Solar System objects")?></label>
<label><input type="checkbox" class="stelaction" name="actionShow_Planets_Hints" /><?= tr("Show planet markers")?></label>
<label><input type="checkbox" class="stelaction" name="actionShow_Planets_Orbits" /><?= tr("Show planet orbits")?></label>

stelssc (Direct script execution)

This class allows you to define buttons that directly execute Stellarium Scripting Engine code. Supported for button and input elements of type button. The code to execute should be stored inside the element's value property. If the custom attribute data-useincludes attribute is added (with any value), the default include folder is added for optional includes, but this is not recommended unless necessary.

An example:

<!-- some buttons which move the view to predefined angles -->
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 0., 3.)">0&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 30., 3.)">30&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 60., 3.)">60&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 90., 3.)">90&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 120., 3.)">120&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 150., 3.)">150&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 180., 3.)">180&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 210., 3.)">210&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 240., 3.)">240&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 270., 3.)">270&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 300., 3.)">300&deg;</button>
<button type="button" class="stelssc" value="core.moveToAltAzi(0., 330., 3.)">330&deg;</button>
Warning
The stelssc approach has some disadvantages, so try to use it only when necessary:
  • causes a larger overhead for Stellarium internally than other methods provided by the web interface
  • Stellarium must have been built with ENABLE_SCRIPTING defined (default)
  • the scripts can't be executed if another script is currently running, an error message will be shown in this case
    • this also includes the user clicking too fast on any stelssc buttons!

stelplugin (Plugin-specific sections)

With the CSS class stelplugin, one can create special HTML sections that are only shown when a specified plugin is currently loaded by Stellarium. If the plugin is not loaded, the whole element and all it's children are removed from the DOM. This class can be added to any element. The plugin which is required is defined by the data-plugin attribute, which should be set to the plugin ID.

The optional data-pluginjs attribute can be used to define an additional JavaScript module that is only loaded when the plugin is loaded. This can be used to implement additional behaviour through JS, if required. It is recommended to put these modules into the webroot/js/plugins folder.

An example, defining the plugin panel for the ArchaeoLines Plug-in :

<div id="vo_archaeolines" class="smallblock stelplugin" data-plugin="ArchaeoLines" data-pluginjs="plugins/archaeolines">
<h3><label><input type="checkbox" class="stelaction valign-middle" name="actionShow_Archaeo_Lines"/><?= tr("ArchaeoLines")?></label></h3>
<div class="inline-block blocklabel">
<label><input type="checkbox" class="stelaction" name="actionAL_showEquinoxLine"/><?= tr("Equinox")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showSolsticeLines"/><?= tr("Solstices")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showCrossquarterLines"/><?= tr("Crossquarters")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showMajorStandstillLines"/><?= tr("Major Standstill")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showMinorStandstillLines"/><?= tr("Minor Standstill")?></label>
</div>
<div class="inline-block blocklabel">
<label><input type="checkbox" class="stelaction" name="actionAL_showZenithPassageLine"/><?= tr("Zenith Passage")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showNadirPassageLine"/><?= tr("Nadir Passage")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showSelectedObjectLine"/><?= tr("Selected Object")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showCurrentSunLine"/><?= tr("Current Sun")?></label>
<label><input type="checkbox" class="stelaction" name="actionAL_showCurrentMoonLine"/><?= tr("Current Moon")?></label>
</div>
<label class="display-block" for="select_ArchaeoLines_enumShowCurrentPlanet"><?= tr("Current Planet:")?></label>
<select id="select_ArchaeoLines_enumShowCurrentPlanet" class="selectmenu stelproperty display-block" name="ArchaeoLines.enumShowCurrentPlanet">
<option value="10"><?= tr("None")?></option>
<option value="11"><?= tr("Mercury")?></option>
<option value="12"><?= tr("Venus")?></option>
<option value="13"><?= tr("Mars")?></option>
<option value="14"><?= tr("Jupiter")?></option>
<option value="15"><?= tr("Saturn")?></option>
</select>
</div>
//the contents of plugins/archaeolines.js
define(["jquery"],function($){
"use strict";
//this is just an example how to use additional dynamically loaded plugin files
console.log("Hello, this is a asynchronously loaded plugin javascript file!");
});

Translation information

The interface can be translated using methods similar to the main program. All strings in the HTML markup that should be translated can be written between pseudo-PHP style tags and the tr function to achieve the same effect as the q_() macro in C++, like so:

<label><input type="checkbox" class="stelaction" name="actionShow_Planets" /><?= tr("Show Solar System objects")?></label>

All files which are listed in the webroot/translate_files file will be parsed, and all <?= tr("----")?> tags will be replaced using the StelTranslator for the current application language.

If you require translated strings through JavaScript, you should use the tr method of the api/remotecontrol module, which also works similar to the q_() macro. There is a special procedure for the JavaScript strings: the target RemoteControl-update-translationdata should be run whenever new JavaScript strings have been added. This updates the file webroot/js/translationdata.js with all current tr() strings. Python is required to be installed for this operation.

Like the main program, the strings can be extracted from the HTML/JS code using gettext/xgettext. There are CMake targets for this like for the C++ code (generate-pot-stellarium-remotecontrol, update-po-stellarium-remotecontrol, etc.) and they are also executed with the combined targets (generate-pot, update-po etc.).

JavaScript module reference

All interface code is developed using require.js modules. This allows defining the dependencies of each module, as well as easier maintainability. Each module should be defined in its own .js file. The module ID corresponds to the .js file name without the file extension.

In short, to define a module, wrap it in a define call, and optionally add dependencies. A basic example (for more ways to do it see the require.js doc):

//myawesomemodule.js
//the IDs of the dependencies are listed in an array as first parameter
//the second parameter is usually a function which takes the actual instances of the dependencies as a parameter,
// in the same order as they are in the array!
define(["jquery", "api/remotecontrol"], function($,rc) {
"use strict"; //it is recommended to use strict mode for each module
//do something as soon as this module is loaded
console.log("my awesome module is being loaded!");
//do something when the DOM is ready (because that is not guaranteed while the module is first bein loaded!)
$(function(){
console.log("the document is ready, you can access the elements now!");
//access an element and modify it
$("#myelement").text("hey, this is awesome");
});
//react to the serverDataReceived event of the remotecontrol module
$(rc).on("serverDataReceived", function(evt,data) {
console.log("Stellarium just sent us new data!");
console.log("The current jDay is " + data.time);
});
//provide some public methods that other modules may call
return {
myAwesomeMethod: function() {
console.log("Hello there!");
}
};
});
//another module (in another file) can now reference our module as dependency to load it and use its methods
define(["jquery", "myawesomemodule"],function($, awesome) {
awesome.myAwesomeMethod(); //prints "Hello there!"
});

The UI modules can depend on the API modules and other UI modules. The API modules can depend on other API modules. Circular dependencies should of course be avoided.

api/remotecontrol

This is the main API module, with no further dependencies on other API modules.

Its main function is that it provides automatic status updates by periodically polling (by default each second) the status operation of the MainService. Whenever this poll succeeds, the serverDataReceived custom event is emitted, with the JSON response of the server as data parameter. Other API modules should use this event, and process the data in which they are interested. It also keeps track of StelAction and StelProperty changes, and emits stelActionsChanged and/or stelPropertiesChanged, if necessary. Note that it does not process them further, this is the job of the api/actions and api/properties modules, respectively. When the connection to the server is lost (i.e. the polling returned an error), the serverDataError event is sent.

The other main function is that it provides the postCmd method, which is a simple wrapper around an AJAX POST call that is intended to be used by other modules to send commands to the server. It also includes the tr method used for translating JS strings.

Finally, this module also processes the plugin-specific sections on load.

api/actions

Processes StelAction related events. Whenever it detects that boolean StelAction was changed, it emits two events:

  • A generic event stelActionChanged with the actionId as a parameter. This can be used when interested in ALL action changes (like for a action list)
  • A specialied event stelActionChanged:<actionId> with the actionId as part of the event name. This can be used when listening for a specific action only.

On the first load of the interface, it loads a list of all actions (using the ActionService list operation) and emits the actionListLoaded event when this data is available.

To execute/toggle an action, it provides the public executeAction method, which just requires the action ID as parameter. To find out whether an action is currently checked, use the isChecked method.

api/flags

This is a utility module, which can be used to implement checkboxes for enum flag types, where each checkbox sets a specific bit of a single value. The module should be constructed with new, the constructor takes the parent element of a list of checkboxes (input of type checkbox) and a method which is called back when the internal value changes (i.e. the user clicks a checkbox). It provides the setValue method to set the current value and check the correct checkboxes. The bit value of each input should be specified as its value property, in hexadecimal string format (for example 0x0004)

api/location

Module which connects to the LocationService and the LocationSearchService. It emits the following events whenever the specified field changed: planetChanged,nameChanged, countryChanged, altitudeChanged, latitudeChanged, longitudeChanged, positionChanged (emitted when either lat or lon changed)

It also has set methods for these fields. Furthermore, it provides performLocationSearch, which searches the predefined locations for a specific search string, and performNearbySearch, which searches predefined locations near a given lat/lon on the current planet. These methods take a callback parameter to notify the caller of the results. The setLocationById method can then be used to set the location to a result of these 2 methods.

It also provides a loadCountryList and a loadPlanetList which load the specified lists and return the results with a callback.

api/properties

Processes StelProperty related things. Like the api/actions module, it emits 2 events when it detects a StelProperty changed:

  • A generic event stelPropertyChanged with the propertyId as a parameter. This can be used when interested in ALL property changes (like for a list)
  • A specialied event stelPropertyChanged:<propertyId> with the propertyId as part of the event name. This can be used when listening for a specific property only.

It provides getStelProp and setStelProp methods which retrieve and set the value of a StelProperty, and also a setStelPropQueued convenience method to batch multiple fast interface changes (e.g. through a slider or spinner) into a single setStelProp call which is only executed after a small time has passed with no changes.

It also emits the propertyListLoaded event when it first loads the full list of StelProperties with their type information.

api/scripts

This module handles script execution (i.e. connection to the ScriptService). It provides the following methods:

  • loadScriptList - loads the list of all scripts, takes a callback to return this data
  • runScript - runs the specified script id
  • runDirectScript - directly runs the given script code
  • stopScript - stops a currently running script

It also emits the activeScriptChanged event whenever it detects that the current script has changed or started/stopped

api/search

Implements object search functionality, connecting to the ObjectService and the SimbadService. The following methods are provided:

  • loadObjectTypes - loads the list of object types, takes a callback
  • loadObjectList - loads the list of objects of a specified type, can return english or localized names
  • selectObjectByName - selects the object that matches the specified name
  • focusPosition - focuses the given coordinate (array of 3 numbers) in the J2000 frame
  • performSearch - performs an object lookup in Stellarium's internal catalog and Simbad. In addition to the search string, 2 callbacks must be given as parameters: one for the catalog results, and one for the simbad results. If a search is currently running, it is aborted (meaning the callbacks won't be called for the old searches), allowing this method to be repeatedly called while the user is typing. The Simbad search is only started after a small interval without typing, to reduce the overhead of the external web requests.

While a search is running, it emits simbadStateChange events to notify the UI of the current state of the lookup.

api/time

Contains time-related functions and conversions, similar to what StelCore does. This module keeps it's own sense of Stellariums current time, to provide an updated interface even between the status polls of the api/remotecontrol module.

It provides following methods:

  • getCurrentTime - calculates the best guess to the current Stellarium simulation time. This depends on the information received with the last status poll, the time since the last data was received and the time the last time change was performed
  • isRealTimeSpeed - true if the simulation time currently flows at the same rate as the real time (1 sec per sec).
  • jdayToDate - converts a jDay (single number) to Day/Month/Year format, this returns a JS object with day, month, year fields instead of a JS Date object because of its limitations.
  • jdayToDate - returns the time component of the given jDay, as a JS object with hour, minute, second fields
  • dateTimeToJd - converts a time given in Y/M/D-H/MIN/S format to a jDay
  • dateTimeForRollover - like StelUtils::changeDateTimeForRollover
  • isTimeUpdatePending - if true, there is a time change which has not yet been sent to the server
  • increaseTimeRate - increases the Stellarium simulation time rate (like StelCore::increaseTimeSpeed)
  • decreaseTimeRate - decreases the Stellarium simulation time rate (like StelCore::decreaseTimeSpeed)
  • isRewind - returns true if the time currently flows backwards (at least at -0.99 sec / sec)
  • isFastForward - returns true if time currently is flowing faster than real time
  • isTimeNow - returns true if the current simulation time is very close to the actual system time
  • isTimeStopped - returns true if the simulation time rate is zero
  • togglePlayPause - toggles between timerates 0 and 1 sec/sec
  • setDateNow - sets the simulation time to the current system time
  • setJDay - sets the time to the specified JDay
  • setTimeFromTimeObj - sets the time from a "time object", containing both date and time in the following format
    {
    date : {
    year, month, day
    },
    time : {
    hour, minute, second
    }
    }
  • getTimeData - returns the current time data, containing the last response from the server (including timezone info, etc) The event timeDataUpdated is sent whenever this changes.

api/updatequeue

This implements a simple update queue class that updates the server after a specified interval if the user does nothing else inbetween. This is used to limit the rate at which updates are sent to the server. The UpdateQueue constructor takes an url and a callback for the result, and when the interface needs to send an update, enqueue can be called with the data to send.

api/viewcontrol

Implements the FOV access and viewport movement methods. Use setFOV to set the FOV, the fovChanged event is sent whenever the FOV changes. There are moveRight, moveUp, moveUpRight etc. methods that allow the user to move the viewport. To stop the movement, use stopMovement.

api/viewoptions

Implements the loading of the projection, landscape and skyculture lists.

ui/mainui

This is the main module of the interface. It lists all the other UI modules as a dependency. It starts of the update look of the rcApiRemotecontrol module, handles the automatic generation of the special controls and connection of StelProperty controls, and performs smooth animation of the time controls. It also keeps track of the current interface tab the user is on, and restores it when the page is reloaded.

ui/actions

Implements the action list and the StelAction buttons and checkboxes.

ui/combobox

Implements a custom combobox control, on top of the jQuery UI autocomplete control. This is used for example in the location controls.

ui/jqueryuifixes

Includes some fixes to the standard jQuery UI control classes, especially for the spinner, to provide a unified change event, prevent non-numeric input and better touch support. This module is automatically loaded whenever other modules load the "jquery-ui" module.

ui/location

Implements the location controls, such as the map which can be clicked and the comboboxes for the current location.

ui/scripts

Implements the script list and shows the active script.

ui/search

Implements the object search panel and the quick select buttons.

ui/time

Implements the time controls, the updateTimeDisplay method is called repeatedly as an animation by the ui/mainui module.

ui/viewcontrol

Implements the FOV slider and the "virtual joystick" for the viewport movement.

ui/viewoptions

Implements the projection, landscape and skyculture lists, and some minor things related to other view options.