Script Node Authoring Interface
ECMAScript has many advantages:
- Scripts can be included in source form, inline rather than in a separate URL.
- All X3D data types are supported directly. Some, like the vector types have built in methods (such as cross product and normalize) to simplify working with them.
- Receiving input events is handled with separate functions to ease development and to speed processing.
- Sending output events is done with simple assignment.
- Constructors are available for most data types to ease creation and conversion of data.
Objects and Variables
Data in ECMAScript is represented as objects. The object types correspond to the X3D field types. A variable contains an instance of an object, and can be predefined (appearing in the Script node) or defined locally.
Values, Names and Literals
A ECMAScript variable holds an instance of an object. If a name is defined as a field or output field of the Script node containing the script then there is a variable with that same name available globally to the script. The type of this variable is always the type of the field or output field. Assignment to this variable converts the expression to its type or generates a run-time error if a conversion is not possible.
The names specified in the declaration of a function (the data value and the timestamp) are local to the function in which they are declared. It is a run-time error to assign to these variables.
Local variables can be created simply by assigning to a name that does not yet exist. Assigning to such a variable causes it take the type of the expression, so these local variables always have the type of the last assignment. Local variables are scoped by the block in which they were first introduced. Once that block is exited, the variable ceases to exist. Variables corresponding to outputOnly fields or initializeOnly fields of the Script node are global in scope.
Variable names must start with the a lowercase character ('a' through 'z'), an uppercase character ('A' through 'Z'), or an underscore ('_'). Subsequent characters can be any of these or a digit ('0' through '9'). Variable names are case sensitive.
Numeric, boolean, and string literals are allowed. Numeric literals can be integers in decimal (417), hex (0x5C), or octal (0177) notation. They can also be floating point numbers in fixed (1.76) or exponential (2.7e-12) notation. All numeric literals are of the number type. Boolean literals can be 'true' or 'false' and have the boolean type. String literals can be any sequence of UTF8 characters enclosed in single quotes ('), and have the type String. Special (non-printable) characters can be included in a string using the following escape sequences:
|\'||single quote (apostrophe)|
Here are some examples:
Objects and Fields
For each field and outputOnly fields in the Script node containing the script there is a corresponding global variable with the same name. Field variables are persistant; they keep their last stored value across function calls. Local variables, on the other hand, are destroyed on exit from the block in which they were defined. Local variables defined in the outermost block of a function are destroyed when the function exits so they do not persist across function calls.
OutputOnly fields are very similar to field variables in that their values persist across function calls. But when an assignment is made to an outputOnly fields an event is generated.
Every object has a set of properties and methods. Properties are names on the object that can be selected (using the '.' operator) then used in an expression or as the target of an expression. Methods are names on the object that can be called (using the function call operator) to perform some operation on the object. For example:
The value a.r selects the property which corresponds to the red component of the color. The value a .setHSV () selects the method which sets the color in HSV space.
For each object type there is a corresponding constructor. Constructors typically take a flexible set of parameters to allow construction of objects with any initial value. MF objects are essentially arrays so they always take 0 or more parameters of the corresponding SF object type. A value of a given data type is created using the new keyword with the data type name. For instance:
Combining objects of different types in a single expression or assignment statement will often perform implicit type conversion. Rules for this conversion are described in the following table:
|Number and boolean types||
Most SF objects in ECMAScript have a corresponding MF object. An MFObject is essentially an array of objects, with each element of the array having the type of the corresponding SF object. All MF objects have a length property which returns or sets the number of elements in the MF object. Array indexes start at 0. If vecArray is an MFVec3f object then vecArray is the first SFVec3f object in the array.
Dereferencing an MF object creates a new object of the corresponding SF object type with the contents of the dereferenced element. Assigning an SF object to a dereferenced MF object (which must be of the corresponding type) copies the contents of the SF object into the dereferenced element.
Supported Protocol in the Script Node's url Field
The url field of the Script node may contain a URL that references ECMAScript code:
The ecmascript: protocol allows the script to be placed inline as follows:
The url field may contain multiple URL's and thus reference a remote file or in-line code:
The file extension for ECMAScript source code is .js.
The MIME type for ECMAScript source code is defined as follows:
InputOnly Field Handling
Events sent to the Script node are passed to the corresponding ECMAScript function in the script. It is necessary to specify the script in the url field of the Script node. The function's name is the same as the inputOnly field and is passed two arguments, the event value and its timestamp. If there isn't a corresponding ECMAScript function in the script, the browser's behavior is undefined.
For example, the following Script node has one inputOnly field whose name is
In the above example, when the start inputOnly field is sent the start () function is executed.
Parameter Passing and the InputOnly Field Function
When a Script node receives an inputOnly field, a corresponding method in the file specified in the url field of the Script node is called, which has two arguments. The value of the inputOnly field is passed as the first argument and timestamp of the inputOnly field is passed as the second argument. The type of the value is the same as the type of the inputOnly field and the type of the timestamp is SFTime.
initialize () Method
Authors may define a function named initialize which is called when the corresponding Script node has been loaded and before any events are processed. This can be used to prepare for processing before events are received, such as constructing geometry or initializing external mechanisms.
The initialize function takes no parameters. Events generated from it are given the timestamp of when the Script node was loaded.
prepareEvents () Method
Authors may define a prepareEvents () method that is called only once per frame. prepareEvents () is called before any ROUTE processing and allows a Script to collect any asynchronously generated data, such as input from a network queue or the results of calling field listeners, and generate events to be handled by the browser's normal event processing sequence as if it were a built-in sensor node.
eventsProcessed () Method
Authors may define a function named eventsProcessed which will be called after some set of events has been received. Some implementations will call this function after the return from each inputOnly field function, while others will call it only after processing a number of inputOnly field functions. In the latter case an author can improve performance by placing lengthy processing algorithms which do not need to be executed for every event received into the
The author needs to compute a complex inverse kinematics operation at each time step of an animation sequence. The sequence is single-stepped using a TouchSensor and button geometry. Normally the author would have an inputOnly field function execute whenever the button is pressed. This function would increment the time step then run the inverse kinematics algorithm. But this would execute the complex algorithm at every button press and the user could easily get ahead of the algorithm by clicking on the button rapidly. To solve this the inputOnly field function can be changed to simply increment the time step and the IK algorithm can be moved to an eventsProcessed function. In an efficient implementation the clicks would be queued. When the user clicks quickly the time step would be incremented once for each button click but the complex algorithm will be executed only once. This way the animation sequence will keep up with the user.
The eventsProcessed function takes no parameters. Events generated from it are given the timestamp of the last event processed.
shutdown () Method
Authors may define a function named shutdown which is called when the corresponding Script node is deleted or the world containing the Script node is unloaded or replaced by another world. This can be used to send events informing external mechanisms that the Script node is being deleted so they can clean up files, etc.
The shutdown function takes no parameters. Events generated from it are given the timestamp of when the Script node was deleted.
The initializeOnly fields, inputOnly fields, outputOnly fields, and inputOutput fields of a Script node are accessible from its ECMAScript functions. As in all other nodes the fields are accessible only within the Script. The Script's inputOnly fields can be routed to and its outputOnly fields can be routed from. Another Script node with a pointer to this node can access its inputOnly fields and outputOnly fields just like any other node.
Accessing InitializeOnly and OutputOnly Fields of the Script
Fields defined in the Script node are available to the script by using its name. It's value can be read or written. This value is persistent across function calls. outputOnly fields defined in the script node can also be read. The value is the last value sent.
Accessing InitializeOnly Fields and OutputOnly Fields of Other Nodes
The script can access any inputOutput field, inputOnly fields or outputOnly fields of any node to which it has a pointer:
This sends a set_translation inputOnly field to the Transform node. An inputOnly field on a passed node can appear only on the left side of the assignment. An outputOnly fields or inputOutput field in the passed node can appear only on the right side, which reads the last value sent out. Fields in the passed node cannot be accessed, but inputOutput fields can either send an event to the »set_...« inputOnly field, or read the current value of the »..._changed« outputOnly fields. This follows the routing model of the rest of X3D.
Sending OutputOnly Fields
Assigning to an outputOnly fields or inputOutput field sends that event at the completion of the currently executing function. This implies that assigning to the outputOnly field or inputOutput field multiple times during one execution of the function still only sends one event and that event is the last value assigned.