Tutorial/Scripting
This tutorial is incomplete |
Knotter has a script engine that can be used to automate tasks and provide new tools. This tutorial shows how to execute simple scripts and to create a plugin.
Contents
Introduction
To execute simple code snippets you can use the script console, which can be toggled via View → Dialogs → Script Console. From there, you can type your line at the bottom and hit enter to execute it.
The scripting language used by Knotter is ECMAScript. This section gives a minimal introduction to the language, if you are already familiar with the language you can skip it.
Hello World
Let's start with a classical example, the Hello World program:
print("Hello World")
Output:
Hello World
Here print
is one of the built-in functions; Template:"Hello World" is a string literal, passed as an argument to that function.
The print
function writes its arguments to the script console. If multiple arguments are passed, each one is written, separated by a space character.
print("Hello", 'World')
Output:
Hello World
Variables and values
Expressions can yield a value, for example 5+3
results in 8
.
It's often useful to assign a name to a value to be able to retrieve it quickly later on. To do this we can use variables. A value can be copied to a variable using an assignment expression:
a = 2 + 3
Output:
5
Here the expression 2+3
is evaluated and the result (5
) is copied to the variable a
. Any previous value of Template:A is discarded. It is a good practice to declare variables with var
before using them.
var a = 2+3
var b = 7
var c = a+b
print("a + b =", c)
b = 3
a = b
print ("a =",a)
print ("b =",b)
print ("c =",c)
Output:
a + b = 12 3 3 a = 3 b = 3 c = 12
Objects
Objects are values that can contain variables and functions.
knotter.version
Output:
0.9.3
In the above example knotter
is one of the built-in global objects. version
is one of its properties.
Interactions with Knotter
Interacting with the user
The object window.dialog
can be used to show dialogs and get input from the user.
var number = window.dialog.get_number("Select a number")
if ( number > 4 ) window.dialog.information("That's a large number")
The first line will show a dialog asking for a number.
If the user has chosen a value greater than four, an information dialog is displayed.
Interacting with the knot
The object document
represent the current document, document.graph
contains the nodes and edges contained by the graph and can modify it.
for ( var i = 0; i < 4; i++ ) document.graph.add_node(i*16,0);
The script above will add a line of four nodes at a distance of 16 pixels from one another.
Writing a plugin
The list of directories in which you can place a plugin can be found Help → About → Plugins. You can create subdirectories to keep all the code for your plugin separated from the others.
Metadata
A plugin is defined by a file called plugin_name.json, name there is not important and can be anything. This file uses the JSON format to describe the properties of the plugin.
{
"name" : "Segmented line",
"description" : "Add a line of nodes",
"script" : "line.js"
}
Script
Each plugin must have a script file, with the same name as defined in the JSON file. As of version 0.9.3 you have to restart Knotter when you want that changes to the plugin code get applied.
For our plugin we want to ask the user to select the number of nodes and then create a line with that many nodes.
// Ask the user for a number. Default value is 4 and minimum is 1
var length = window.dialog.get_integer("Number of segments","Segmented line", 4, 1 );
for ( var i = 0; i < length; i++ )
{
// Create a new node
document.graph.add_node(i*document.grid.size,0);
}
This will add the nodes as requested, using the grid size to space them.
This is fine but we also want to connect them.
// Ask the user for a number. Default value is 4 and minimum is 1
var length = window.dialog.get_integer("Number of segments","Segmented line", 4, 1 );
for ( var i = 0; i < length; i++ )
{
// Create a new node
var current_node = document.graph.add_node(i*document.grid.size,0);
// From the second iteration connect to the previous node
if ( i > 0 )
{
var previous_node = document.graph.node_at((i-1)*document.grid.size,0);
document.graph.connect(current_node,previous_node);
}
}
Now there is a problem: the plugin makes several changes to the document and the user will have to undo each step. This can be solved by wrapping get code in a macro.
All commands executed inside a macro can then be undone/redone in a single step.
// Ask the user for a number. Default value is 4 and minimum is 1
var length = window.dialog.get_integer("Number of segments","Segmented line", 4, 1 );
// Place all the edits to the document in a macro called "Segmented line"
document.begin_macro("Segmented line");
for ( var i = 0; i < length; i++ )
{
// Create a new node
var current_node = document.graph.add_node(i*document.grid.size,0);
// From the second iteration connect to the previous node
if ( i > 0 )
{
var previous_node = document.graph.node_at((i-1)*document.grid.size,0);
document.graph.connect(current_node,previous_node);
}
}
// End the macro
document.end_macro();
Now the plugin will create a macro even if the user clicked "Cancel" on the dialog.
To fix this we add a condition to execute the code only if the user really wants to add the line
// Ask the user for a number. Default value is 4 and minimum is 1
var length = window.dialog.get_integer("Number of segments","Segmented line", 4, 1 );
// If the user canceled the dialog length is set to NaN
if ( !isNaN(length) )
{
// Place all the edits to the document in a macro called "Segmented line"
document.begin_macro("Segmented line");
for ( var i = 0; i < length; i++ )
{
// Create a new node
var current_node = document.graph.add_node(i*document.grid.size,0);
// From the second iteration connect to the previous node
if ( i > 0 )
{
var previous_node = document.graph.node_at((i-1)*document.grid.size,0);
document.graph.connect(current_node,previous_node);
}
}
// End the macro
document.end_macro();
}