by Ryan Webber
Why Use Javascript?
Javascript in Isadora is a powerful method of processing data, based on the V8 javascript engine created by Google. It allows you to work with both text and numeric data in a wide variety of ways, and in a completely different manner than the patching environment. For example a text string can be converted to uppercase with a single line of code “str.toUpperCase()”.
There are several places online where you can learn more about Javascript:
- To learn more about Javascript, the most complete resource is likely the Javascript Language Reference reference at developer.mozilla.com
- For some excellent Javascript Tutorials, take a look at w3schools.com.
- Finally, a good Javascript reference for day-to-day use can be found at devdocs.io.
Using the Javascript Actor
A new Javascript actor was added to Isadora 2.0. (Note: it will only appear if you have purchased the 2.0 upgrade.) When you add a fresh Javascript actor to a patch, it comes with a very basic starter script that takes one numeric input and adds one to it as the output.
Double click the actor to open the script editor.
Lets look at this starter script:
function main() { return arguments[0] + 1; }
There are 4 very important things happening in this simple script.
- The main() function is defined. Isadora requires that a function named ‘main’ be declared in the script. This function will be called when an input value is updated.
- Input is retrieved from the arguments array. In this case, the first (and only) input value is received from arguments[0], which will be set to the value given by 'input 1' of the Javascript actor whenever that input changes. More information on the arguments array can be found at developer.mozilla.com.
- One or more operations are executed. Generally, you are going to want to do something with data while scripting in Javascript. In this case, we add 1 to argument[0].
- Output is returned from the script. The return statement tells the script to return a value to the Javascript actor so it can send it to one or more of its outputs. An array can be returned by the return statement to allow multiple outputs from the Javascript actor. More information on the return command can be found at developer.mozilla.com.
Note: On the net, you will often see ‘array’ and ‘list’ used to mean the same thing when talking about JavaScript variables. According to Mozilla, the correct term is array.
Extend the script - two inputs and two outputs
function main() { return [arguments[0] + 1, arguments[1] + 10]; }
You can see here that we have extended the previous starter function to now reference arguments[0] and arguments[1] which correspond to the 'input 1' and 'input 2' of the Javascript actor. I add 1 to argument[0], and 10 to argument[1], and return those two values as an array by enclosing the two values in square brackets ('[' and ']') and separating the values with a comma.
(You can learn more about Javascript arrays a developer.mozilla.com.)
Below, we have reformatted the code, and made some comments, to make it a little easier to read.
function main() { var x = arguments[0]; // from Javascript actor 'input 1' var y = arguments[1]; // from Javascript actor 'input 2' x = x + 1; // set x to its own value + 'an offset amount' y = y + 10; // set y to its own value + 'an offset amount' return [x, y]; // return an array with two values }
The first two statements define the x and y variables and set them to the values coming from the Javascript actor's 'input 1' and 'input 2' inputs.
- Set the variables x and y to the respective input values.
- Perform a mathematical calculation by adding 1 to x and assigning the result to x. A similar calculation is applied to y.
- Return the x and y variables as an array by enclosing the two values in square brackets and separating them with a comma.
This function does the same work as the earlier function; we've just written a bit more verbosely to ensure the functionality is clear.
Adjust the Javascript Actor's Outputs
Since we just modified the code to use two inputs and two outputs, we need to adjust the Javascript actor in your Isadora patch to match.
First, set the ‘inputs’ input of the Javascript actor to '2'. After you do this, you will see that the Javascript actor now has both 'input 1' and 'input 2'. Again, these two inputs values are passed to arguments[0] and arguments[1] when main() is executed. That's how you are able to get the input values for X and Y in the script.
Second, set the ‘outputs’ input of the Javascript actor to '2' so that both output values will be available separately. After you do this, you will see that the Javascript actor now has two outputs: 'output 1' and 'output 2'. When the main() function returns a Javascript array with two values, the first one will be sent to 'output 1' and the second one will be sent to 'output 2.'
Adding a Second Function
Working from the same starter function, we can move the data manipulation outside of the main() function by creating a new function that will do the actual calculation. This ability to use multiple functions will allow you to add useful and widely available JavaScript scripts/functions within your patch. We are going to simply pass our variables to a new ‘square’ function that will multiply the variable by itself.
Here it is:
function main() { var x = arguments[0]; // from Javascript actor 'input 1' var y = arguments[1]; // from Javascript actor 'input 2' var data = [square(x),square(y)]; // set data to an array that is // the square of the two numbers return data; // return the array } function square(n) { n = n*n; // multiply the number by itself return n; // return the result }
The result is almost the same as the last main function, except now instead of having two separate lines that added our input values, we now set the variable 'data' to an array with the result of the two calls to the square() function. For each call to square(), we pass in a value and the function provides a number as a result. By enclosing the two function calls in square brackets and separating them with a comma, we end up with an array containing two numbers.
If for example x=3 and y=4, then the variable 'data' would be set to the Javascript array [square(3), square(4)] which ends up being an array with two numbers: [9,16].
The array inside ‘data’ is returned to Isadora's Javascript actor, and the two values it contains will be passed to the actor's 'output 1' and 'output 2' outputs.
Setting the Data Type of a Javascript Output
It is important to remember that Isadora’s patching environment doesn't know anything about the inner workings of your JavaScript code. The Javascript actor simply passes the input data into the Javascript code via the arguments[] array, executes main(), and sends value returned by main() to the Javascript actor's outputs.
In Isadora, input and output ports are shown with a small circle near the input or output name. Typically this circle is either pale grey (non selected actor) or blue (selected actor).
But, these ports also come in another variety, indicated by a pale or bright green circle. Green ports are mutable, meaning that, when you connect them, the data type they send or receive "mutates" to match the data type of whatever input or output you have just connected.
All of the inputs and outputs that communicate with your JavaScript code are mutable, which is indicated by the green color of the input or output port. This helps us set the connections to the correct data type for the code to use.
The default output type for the Javascript actors is a floating-point number. If you are only inputting and outputting numbers, then there isn't much to worry about. But what if you want to output text? The mutable output comes to the rescue here.
For example, if you add a ‘Trigger Text’ actor to your patch now, and connect your 'output 1' to the 'text' input of the actor, that output will mutate so that it now sends a text string for use with the Trigger Text actor.
Isadora is very good at conversion. It will convert a number to a string, and it will convert a string that looks like a number to a number. What it will not do is convert a string that contains a non-numerical character to a numerical value. Instead, you get an error code.
If you connect a mutable connection to a connection of a type you did not intend, simply delete all connections to the mutable connector and reconnect it to the correct type. It will happily mutate again.
Make the Second Output a Text String
function main() { var x = arguments[0]; // from Javascript actor 'input 1' var y = arguments[1]; // from Javascript actor 'input 2' var sq2string = Math.round(square(x)); // round square(x) to nearest integer // convert the value of the number sq2string to // a string using the toString() function and then // concatenate the string ' string' to the end sq2string = sq2string.toString() + ' string'; var data = [sq2string,square(y)]; // set the output array return data; // return the output }
We made a few changes here. Let us walk through it quickly.
- We defined a new variable called sq2string that is assigned the value of Math.round(square(x)). (If a decimal portion of a floating-point number is greater than 0.5, Math.round() will round it up to the next integer; otherwise, it rounds down to the next lowest integer.)
- In the next line, we convert the numeric value of sq2string to a string using the toString() function. Then we use the plus operator ('+') to concatenate the value on the left side (the result of toString()) and a constant string variable on the right (' string'). If you were to use the plus operator with two numbers, it would simply add them. But if one of the operands is a string, the plus operator means "append the first string to the end of the second string."
- We then set the variable 'data' to the text string inside of 'sq2string' and the numeric variable by the square(y) function.
- Finally, we return the contents of 'data', which is the array we created in step 3.
So, we can expect that 'output 1' from our Javascript actor will now be a string, and 'output 2' will remain a numeric value.
Please test this script in Isadora, and play around with connecting the outputs to different input types. It is very important in Isadora to have a strong understanding of how to work with mutable connections.
Input works very much the same way. We are not going to add text-based inputs, but I suggest you give it a try.
Debugging with the Print Function
A debugging feature is added to the Javascript actor that can allow you to ‘peak’ inside the code.
The print function is a simple way to debug your code. By adding a print() function call at any point within your code, you can output information to the Monitor window. (Choose Windows > Show Monitor to open the window). If we change the previous main() function to include a print call as follows, we will be able to see the value of sq2string before converting it to a string.
function main() { var x = arguments[0]; // from Javascript actor 'input 1' var y = arguments[1]; // from Javascript actor 'input 2' var sq2string = Math.round(square(x)); // round square(x) to nearest integer print(sq2string); // print the value of sq2string to the Monitor print('\n'); // print a newline to go to the next line // convert the value of the number sq2string to // a string using the toString() function and then // concatenate the string ' string' to the end sq2string = sq2string.toString() + ' string'; var data = [sq2string,square(y)]; // set the output array return data; // return the output }
Note: One little extra thrown in there to help with formatting. The print('\n') line adds a new line, otherwise, all the values will be printed without spaces on a single line.
Conclusion
That's it. You should now have a basic understanding of how to work with Javascript in Isadora.
Start Playing around! The Javascript actor adds a new dimension of programming power to Isadora.