The Virtual Reality Modeling Language

Appendix D. JavaScript Scripting Reference

Version 2.0, ISO/IEC WD 14772

August 4, 1996

This appendix describes the use of JavaScript with the Script node. See "Concepts - Scripting" for a general overview of scripting in VRML, and see "Nodes Reference - Script" for a description of the Script node.

D.1 Language

D.2 Supported Protocol in the Script node's url field

D.2.1 File Extension

D.2.2 MIME Type

D.3 EventIn Handling

D.3.1 Parameter passing and the EventIn Function

D.3.2 eventsProcessed() Method

D.3.3 initialize() Method

D.3.3 shutdown() Method

D.4 Accessing Fields and Events

D.4.1 Accessing Fields and EventOuts of the Script

D.4.2 Accessing Fields and EventOuts of Other Nodes

D.4.3 Sending EventOuts

D.5 JavaScript Objects

D.5.1 Browser Object

D.5.2 Mapping between JavaScript Types and VRML Types

D.6 Example

D.1 Language

Netscape JavaScript was created by Netscape Communications Corporation (http://home.netscape.com). JavaScript is a programmable API that allows cross-platform scripting of events, objects, and actions. A full description of JavaScript can be found at: http://home.netscape.com/comprod/products/navigator/version_2.0/script/script_info/. This appendix describes the use of JavaScript as the scripting language of a Script node.

D.2 Supported Protocol in the Script Node's url Field

The url field of the Script node may contain a URL that references JavaScript code:

 Script {  url "http://foo.com/myScript.js"  }

The javascript: protocol allows the script to be placed inline as follows:

    Script {  url "javascript: function foo() { ... }"   }

The url field may contain multiple URLs and thus reference a remote file or in-line code:

    Script { 
        url [ "http://foo.com/myScript.js",
              "javascript: function foo() { ... }" ]
    }

D.2.1 File Extension

The file extension for JavaScript source code is .js.

D.2.2 MIME Type

The MIME type for JavaScript source code is defined as follows:

        application/x-javascript

D.3 EventIn Handling

Events sent to the Script node are passed to the corresponding JavaScript 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 eventIn and is passed two arguments, the event value and its timestamp (See "Parameter passing and the EventIn function"). If there isn't a corresponding JavaScript function in the script, the browser's behavior is undefined.

For example, the following Script node has one eventIn field whose name is start:

    Script { 
        eventIn SFBool start
        url "javascript: function start(value, timestamp) { ... }"
    }

In the above example, when the start eventIn is sent the start() function is executed.

D.3.1 Parameter Passing and the EventIn Function

When a Script node receives an eventIn, a corresponding method in the file specified in url field of the Script node is called, which has two arguments. The value of the eventIn is passed as the first argument and timestamp of the eventIn is passed as the second argument. The type of the value is the same as the type of the EventIn and the type of the timestamp is SFTime. See "Mapping between JavaScript types and VRML types" for a description of how VRML types appear in JavaScript.

D.3.2 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 EventIn function, while others will call it only after processing a number of EventIn functions. In the latter case an author can improve performance by placing lengthy processing algorithms which do not need to execute for every event received into the eventsProcessed function.

Example:
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 EventIn 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 EventIn 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.

D.3.3 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 construct geometry or initialize external mechanisms.

The initialize function takes no parameters. Events generated from it are given the timestamp of when the Script node was loaded.

D.3.3 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.

D.4 Accessing Fields

The fields, eventIns and eventOuts of a Script node are accessible from its JavaScript functions. As in all other nodes the fields are accessible only within the Script. The Script's eventIns can be routed to and its eventOuts can be routed from. Another Script node with a pointer to this node can access its eventIns and eventOuts just like any other node.

D.4.1 Accessing Fields and EventOuts 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. EventOuts defined in the script node can also be read. The value is the last value sent.

D.4.2 Accessing Fields and EventOuts of Other Nodes

The script can access any exposedField, eventIn or eventOut of any node to which it has a pointer:

    DEF SomeNode Transform { }
    Script {
        field SFNode node USE SomeNode
        eventIn SFVec3f pos
        directOutput TRUE
        url "... 
            function pos(value) { 
                node.set_translation = value; 
            }"
    }

This sends a set_translation eventIn to the Transform node. An eventIn on a passed node can appear only on the left side of the assignment. An eventOut 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 exposedFields can either send an event to the "set_..." eventIn, or read the current value of the "..._changed" eventOut. This follows the routing model of the rest of VRML.

D.4.3 Sending EventOuts

Assigning to an eventOut sends that event at the completion of the currently executing function. This implies that assigning to the eventOut multiple times during one execution of the function still only sends one event and that event is the last value assigned.

D.5 JavaScript Objects

D.5.1 Browser Object

This section lists the functions available in the browser object, which allows scripts to get and set browser information. Return values and parameters are shown typed using VRML data types for clarity. For descriptions of the methods, see the Browser Interface topic of the Scripting section of the spec.

Return value

Method Name

SFString getName()
SFString getVersion()
SFFloat getCurrentSpeed()
SFFloat getCurrentFrameRate()
SFString getWorldURL()
void replaceWorld(MFNode nodes)
SFNode createVrmlFromString(SFString vrmlSyntax)
SFNode createVrmlFromURL(MFString url, Node node, SFString event)
void addRoute(SFNode fromNode, SFString fromEventOut,                   SFNode toNode, SFString toEventIn)
void deleteRoute(SFNode fromNode, SFString fromEventOut,                       SFNode toNode, SFString toEventIn)
void loadURL(MFString url, MFString parameter)
void setDescription(SFString description)

D.5.2 Mapping between JavaScript types and VRML types

JavaScript has few native types. It has strings, booleans, a numeric type and objects. Objects have members which can be any of the three simple types, a function, or another object. VRML types are mapped into JavaScript by considering MF field types as objects containing one member for each value in the MF field. These are accessed using array dereferencing operations. For instance getting the third member of an MFFloat field named foo in JavaScript is done like this:

    bar = foo[3];

After this operation bar contains a single numeric value. Note that array indexing in JavaScript starts at index 1.

Simple SF field type map directly into JavaScript. SFString becomes a JavaScript string, SFBool becomes a boolean, and SFInt32 and SFFloat become the numeric type. SF fields with more than one numeric value are considered as objects containing the numeric values of the field. For instance an SFVec3f is an object containing 3 numeric values, accessed using array dereferencing. To access the y component of an SFVec3f named foo do this:

    bar = foo[2];

After this operation bar contains the y component of vector foo.

Accessing an MF field containing a vector is done using double array dereferencing. If foo is now an MFVec3f, accessing the y component of the third value is done like this:

    bar = foo[3][1];

Assigning a JavaScript value to a VRML type (such as when sending an eventOut), performs the appropriate type conversion. Assigning a one dimensional array to an SFField with vector contents (SFVec2f, SFVec3f, SFRotation or SFColor) assigns one element to each component of the vector. If too many elements is passed the trailing values are ignored. If too few are passed the vector is padded with 0's. Assigning a numeric value to an SFInt32 truncates the value.

Assigning a simple value to an MFField converts the single value to a multi-value field with one entry. Assigning an array to an SFField places the first array element into the field. Assigning a one dimensional array to an MFField with vector quantities first translates the array into the the vector quantity then assigns this as a single value to the MFField. For instance if foo is a 4 element array and it is assigned to an MFVec2f, the first 2 elements are converted to an SFVec2f, the last 2 elements are discarded, then the SFVec2f is converted to an MFVec2f with one entry.

Assigning a string value to any numeric type (anything but SFString/MFString) attempts to convert the number to a float then does the assignment. If it does not convert a 0 is assigned. Assigning to an SFTime interprets the value as a double.

Assigning to an SFImage interprets the value as a numeric vector with at least 3 values. The first 2 are the x,y dimensions of the image in pixels, the third value is the number of components in the image (1 for monochrome, 3 for rgb, etc.) and the remaining values are pixel colors as described in " Fields and Events - SFImage".

D.6 Example

Here's an example of a Script node which determines whether a given color contains a lot of red. The Script node exposes a color field, an eventIn, and an eventOut:

Script {
    field    SFColor currentColor 0 0 0
    eventIn  SFColor colorIn
    eventOut SFBool  isRed

    url "javascript: function colorIn(newColor, ts) {
            // This method is called when a colorIn event is received
            currentColor = newColor;
        }

        function eventsProcessed() {
            if (currentColor[0] >= 0.5)
                // if red is at or above 50%
                isRed = true;
        }"
}

For details on when the methods defined in ExampleScript are called - see the "Concepts - Execution Model".

Browser class example

 Contact rikk@best.com , cmarrin@sgi.com, or gavin@acm.org with questions or comments.
This URL: http://vrml.sgi.com/moving-worlds/spec/part1/javascript.html.