Showing preview only (4,699K chars total). Download the full file or copy to clipboard to get everything.
Repository: jagenjo/litegraph.js
Branch: master
Commit: 0555a2f2a3df
Files: 106
Total size: 4.5 MB
Directory structure:
gitextract_a35_aqba/
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmrc
├── .prettierrc
├── .vscode/
│ └── extensions.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build/
│ ├── litegraph.core.js
│ ├── litegraph.js
│ └── litegraph_mini.js
├── csharp/
│ ├── LiteGraph.cs
│ ├── LiteGraphNodes.cs
│ ├── LiteGraphTest.cs
│ ├── SimpleJSON.cs
│ ├── graph.JSON
│ └── readme.md
├── css/
│ ├── litegraph-editor.css
│ └── litegraph.css
├── doc/
│ ├── api.js
│ ├── assets/
│ │ ├── css/
│ │ │ └── main.css
│ │ ├── index.html
│ │ ├── js/
│ │ │ ├── api-filter.js
│ │ │ ├── api-list.js
│ │ │ ├── api-search.js
│ │ │ ├── apidocs.js
│ │ │ └── yui-prettify.js
│ │ └── vendor/
│ │ └── prettify/
│ │ ├── CHANGES.html
│ │ ├── COPYING
│ │ ├── README.html
│ │ ├── prettify-min.css
│ │ └── prettify-min.js
│ ├── classes/
│ │ ├── ContextMenu.html
│ │ ├── LGraph.html
│ │ ├── LGraphCanvas.html
│ │ ├── LGraphNode.html
│ │ ├── LiteGraph.html
│ │ └── index.html
│ ├── data.json
│ ├── elements/
│ │ └── index.html
│ ├── files/
│ │ ├── .._src_litegraph.js.html
│ │ └── index.html
│ ├── index.html
│ └── modules/
│ └── index.html
├── editor/
│ ├── demodata/
│ │ └── video.webm
│ ├── editor_mobile.html
│ ├── examples/
│ │ ├── audio.json
│ │ ├── audio_delay.json
│ │ ├── audio_reverb.json
│ │ ├── benchmark.json
│ │ ├── copypaste.json
│ │ ├── features.json
│ │ ├── midi_generation.json
│ │ └── subgraph.json
│ ├── index.html
│ ├── js/
│ │ ├── code.js
│ │ ├── defaults.js
│ │ ├── defaults_mobile.js
│ │ ├── demos.js
│ │ └── libs/
│ │ ├── audiosynth.js
│ │ ├── gl-matrix-min.js
│ │ ├── litegl.js
│ │ └── midi-parser.js
│ └── style.css
├── external/
│ ├── Basica.otf
│ ├── Criticized.otf
│ ├── DS-Digital.otf
│ └── beat.otf
├── gruntfile.js
├── guides/
│ └── README.md
├── index.html
├── jest.config.js
├── package.json
├── src/
│ ├── litegraph-editor.js
│ ├── litegraph.d.ts
│ ├── litegraph.js
│ ├── litegraph.test.js
│ └── nodes/
│ ├── audio.js
│ ├── base.js
│ ├── events.js
│ ├── geometry.js
│ ├── glfx.js
│ ├── glshaders.js
│ ├── gltextures.js
│ ├── graphics.js
│ ├── input.js
│ ├── interface.js
│ ├── logic.js
│ ├── math.js
│ ├── math3d.js
│ ├── midi.js
│ ├── network.js
│ ├── others.js
│ └── strings.js
├── style.css
└── utils/
├── build.sh
├── builder.py
├── deploy_files.txt
├── deploy_files_core.txt
├── deploy_files_mini.txt
├── generate_doc.sh
├── pack.sh
├── server.js
├── temp.js
└── test.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
/build
================================================
FILE: .eslintrc.js
================================================
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true,
"jest/globals": true
},
"extends": "eslint:recommended",
"overrides": [
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["jest"],
"globals": {
"gl": true,
"GL": true,
"LS": true,
"Uint8Array": true,
"Uint32Array": true,
"Float32Array": true,
"LGraphCanvas": true,
"LGraph": true,
"LGraphNode": true,
"LiteGraph": true,
"LGraphTexture": true,
"Mesh": true,
"Shader": true,
"enableWebGLCanvas": true,
"vec2": true,
"vec3": true,
"vec4": true,
"DEG2RAD": true,
"isPowerOfTwo": true,
"cloneCanvas": true,
"createCanvas": true,
"hex2num": true,
"colorToString": true,
"showElement": true,
"quat": true,
"AudioSynth": true,
"SillyClient": true
},
"rules": {
"no-console": "off",
"no-empty": "warn",
"no-redeclare": "warn",
"no-inner-declarations": "warn",
"no-constant-condition": "warn",
"no-unused-vars": "warn",
"no-mixed-spaces-and-tabs": "warn",
"no-unreachable": "warn",
"curly": ["warn", "all"]
}
}
================================================
FILE: .gitignore
================================================
node_modules/
node_modules/*
npm-debug.log
temp/
temp/*
coverage/
# Editors
/.vscode/*
!/.vscode/extensions.json
*.bak
.project
================================================
FILE: .npmrc
================================================
package-lock=false
================================================
FILE: .prettierrc
================================================
{
"singleQuote": false,
"semi": true,
"tabWidth": 4
}
================================================
FILE: .vscode/extensions.json
================================================
{
// See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}
================================================
FILE: CONTRIBUTING.md
================================================
# Contribution Rules
There are some simple rules that everyone should follow:
### Do not commit files from build folder
> I usually have horrible merge conflicts when I upload the build version that take me too much time to solve, but I want to keep the build version in the repo, so I guess it would be better if only one of us does the built, which would be me.
> https://github.com/jagenjo/litegraph.js/pull/155#issuecomment-656602861
Those files will be updated by owner.
================================================
FILE: LICENSE
================================================
Copyright (C) 2013 by Javi Agenjo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# litegraph.js
A library in Javascript to create graphs in the browser similar to Unreal Blueprints. Nodes can be programmed easily and it includes an editor to construct and tests the graphs.
It can be integrated easily in any existing web applications and graphs can be run without the need of the editor.
Try it in the [demo site](https://tamats.com/projects/litegraph/editor).

## Features
- Renders on Canvas2D (zoom in/out and panning, easy to render complex interfaces, can be used inside a WebGLTexture)
- Easy to use editor (searchbox, keyboard shortcuts, multiple selection, context menu, ...)
- Optimized to support hundreds of nodes per graph (on editor but also on execution)
- Customizable theme (colors, shapes, background)
- Callbacks to personalize every action/drawing/event of nodes
- Subgraphs (nodes that contain graphs themselves)
- Live mode system (hides the graph but calls nodes to render whatever they want, useful to create UIs)
- Graphs can be executed in NodeJS
- Highly customizable nodes (color, shape, slots vertical or horizontal, widgets, custom rendering)
- Easy to integrate in any JS application (one single file, no dependencies)
- Typescript support
## Nodes provided
Although it is easy to create new node types, LiteGraph comes with some default nodes that could be useful for many cases:
- Interface (Widgets)
- Math (trigonometry, math operations)
- Audio (AudioAPI and MIDI)
- 3D Graphics (Postprocessing in WebGL)
- Input (read Gamepad)
## Installation
You can install it using npm
```
npm install litegraph.js
```
Or downloading the ```build/litegraph.js``` and ```css/litegraph.css``` version from this repository.
## First project ##
```html
<html>
<head>
<link rel="stylesheet" type="text/css" href="litegraph.css">
<script type="text/javascript" src="litegraph.js"></script>
</head>
<body style='width:100%; height:100%'>
<canvas id='mycanvas' width='1024' height='720' style='border: 1px solid'></canvas>
<script>
var graph = new LGraph();
var canvas = new LGraphCanvas("#mycanvas", graph);
var node_const = LiteGraph.createNode("basic/const");
node_const.pos = [200,200];
graph.add(node_const);
node_const.setValue(4.5);
var node_watch = LiteGraph.createNode("basic/watch");
node_watch.pos = [700,200];
graph.add(node_watch);
node_const.connect(0, node_watch, 0 );
graph.start()
</script>
</body>
</html>
```
## How to code a new Node type
Here is an example of how to build a node that sums two inputs:
```javascript
//node constructor class
function MyAddNode()
{
this.addInput("A","number");
this.addInput("B","number");
this.addOutput("A+B","number");
this.properties = { precision: 1 };
}
//name to show
MyAddNode.title = "Sum";
//function to call when the node is executed
MyAddNode.prototype.onExecute = function()
{
var A = this.getInputData(0);
if( A === undefined )
A = 0;
var B = this.getInputData(1);
if( B === undefined )
B = 0;
this.setOutputData( 0, A + B );
}
//register in the system
LiteGraph.registerNodeType("basic/sum", MyAddNode );
```
or you can wrap an existing function:
```js
function sum(a,b)
{
return a+b;
}
LiteGraph.wrapFunctionAsNode("math/sum",sum, ["Number","Number"],"Number");
```
## Server side
It also works server-side using NodeJS although some nodes do not work in server (audio, graphics, input, etc).
```js
var LiteGraph = require("./litegraph.js").LiteGraph;
var graph = new LiteGraph.LGraph();
var node_time = LiteGraph.createNode("basic/time");
graph.add(node_time);
var node_console = LiteGraph.createNode("basic/console");
node_console.mode = LiteGraph.ALWAYS;
graph.add(node_console);
node_time.connect( 0, node_console, 1 );
graph.start()
```
## Projects using it
### [comfyUI](https://github.com/comfyanonymous/ComfyUI)

### [webglstudio.org](http://webglstudio.org)

### [MOI Elephant](http://moiscript.weebly.com/elephant-systegraveme-nodal.html)

### Mynodes

## Utils
-----
It includes several commands in the utils folder to generate doc, check errors and build minifyed version.
## Demo
-----
The demo includes some examples of graphs. In order to try them you can visit [demo site](http://tamats.com/projects/litegraph/editor) or install it on your local computer, to do so you need `git`, `node` and `npm`. Given those dependencies are installed, run the following commands to try it out:
```sh
$ git clone https://github.com/jagenjo/litegraph.js.git
$ cd litegraph.js
$ npm install
$ node utils/server.js
Example app listening on port 80!
```
Open your browser and point it to http://localhost:8000/. You can select a demo from the dropdown at the top of the page.
## Feedback
--------
You can write any feedback to javi.agenjo@gmail.com
## Contributors
- atlasan
- kriffe
- rappestad
- InventivetalentDev
- NateScarlet
- coderofsalvation
- ilyabesk
- gausszhou
================================================
FILE: build/litegraph.core.js
================================================
//packer version
(function(global) {
// *************************************************************
// LiteGraph CLASS *******
// *************************************************************
/**
* The Global Scope. It contains all the registered node classes.
*
* @class LiteGraph
* @constructor
*/
var LiteGraph = (global.LiteGraph = {
VERSION: 0.4,
CANVAS_GRID_SIZE: 10,
NODE_TITLE_HEIGHT: 30,
NODE_TITLE_TEXT_Y: 20,
NODE_SLOT_HEIGHT: 20,
NODE_WIDGET_HEIGHT: 20,
NODE_WIDTH: 140,
NODE_MIN_WIDTH: 50,
NODE_COLLAPSED_RADIUS: 10,
NODE_COLLAPSED_WIDTH: 80,
NODE_TITLE_COLOR: "#999",
NODE_SELECTED_TITLE_COLOR: "#FFF",
NODE_TEXT_SIZE: 14,
NODE_TEXT_COLOR: "#AAA",
NODE_SUBTEXT_SIZE: 12,
NODE_DEFAULT_COLOR: "#333",
NODE_DEFAULT_BGCOLOR: "#353535",
NODE_DEFAULT_BOXCOLOR: "#666",
NODE_DEFAULT_SHAPE: "box",
NODE_BOX_OUTLINE_COLOR: "#FFF",
DEFAULT_SHADOW_COLOR: "rgba(0,0,0,0.5)",
DEFAULT_GROUP_FONT: 24,
WIDGET_BGCOLOR: "#222",
WIDGET_OUTLINE_COLOR: "#666",
WIDGET_TEXT_COLOR: "#DDD",
WIDGET_SECONDARY_TEXT_COLOR: "#999",
LINK_COLOR: "#9A9",
EVENT_LINK_COLOR: "#A86",
CONNECTING_LINK_COLOR: "#AFA",
MAX_NUMBER_OF_NODES: 1000, //avoid infinite loops
DEFAULT_POSITION: [100, 100], //default node position
VALID_SHAPES: ["default", "box", "round", "card"], //,"circle"
//shapes are used for nodes but also for slots
BOX_SHAPE: 1,
ROUND_SHAPE: 2,
CIRCLE_SHAPE: 3,
CARD_SHAPE: 4,
ARROW_SHAPE: 5,
GRID_SHAPE: 6, // intended for slot arrays
//enums
INPUT: 1,
OUTPUT: 2,
EVENT: -1, //for outputs
ACTION: -1, //for inputs
NODE_MODES: ["Always", "On Event", "Never", "On Trigger"], // helper, will add "On Request" and more in the future
NODE_MODES_COLORS:["#666","#422","#333","#224","#626"], // use with node_box_coloured_by_mode
ALWAYS: 0,
ON_EVENT: 1,
NEVER: 2,
ON_TRIGGER: 3,
UP: 1,
DOWN: 2,
LEFT: 3,
RIGHT: 4,
CENTER: 5,
LINK_RENDER_MODES: ["Straight", "Linear", "Spline"], // helper
STRAIGHT_LINK: 0,
LINEAR_LINK: 1,
SPLINE_LINK: 2,
NORMAL_TITLE: 0,
NO_TITLE: 1,
TRANSPARENT_TITLE: 2,
AUTOHIDE_TITLE: 3,
VERTICAL_LAYOUT: "vertical", // arrange nodes vertically
proxy: null, //used to redirect calls
node_images_path: "",
debug: false,
catch_exceptions: true,
throw_errors: true,
allow_scripts: false, //if set to true some nodes like Formula would be allowed to evaluate code that comes from unsafe sources (like node configuration), which could lead to exploits
use_deferred_actions: true, //executes actions during the graph execution flow
registered_node_types: {}, //nodetypes by string
node_types_by_file_extension: {}, //used for dropping files in the canvas
Nodes: {}, //node types by classname
Globals: {}, //used to store vars between graphs
searchbox_extras: {}, //used to add extra features to the search box
auto_sort_node_types: false, // [true!] If set to true, will automatically sort node types / categories in the context menus
node_box_coloured_when_on: false, // [true!] this make the nodes box (top left circle) coloured when triggered (execute/action), visual feedback
node_box_coloured_by_mode: false, // [true!] nodebox based on node mode, visual feedback
dialog_close_on_mouse_leave: true, // [false on mobile] better true if not touch device, TODO add an helper/listener to close if false
dialog_close_on_mouse_leave_delay: 500,
shift_click_do_break_link_from: false, // [false!] prefer false if results too easy to break links - implement with ALT or TODO custom keys
click_do_break_link_to: false, // [false!]prefer false, way too easy to break links
search_hide_on_mouse_leave: true, // [false on mobile] better true if not touch device, TODO add an helper/listener to close if false
search_filter_enabled: false, // [true!] enable filtering slots type in the search widget, !requires auto_load_slot_types or manual set registered_slot_[in/out]_types and slot_types_[in/out]
search_show_all_on_open: true, // [true!] opens the results list when opening the search widget
auto_load_slot_types: false, // [if want false, use true, run, get vars values to be statically set, than disable] nodes types and nodeclass association with node types need to be calculated, if dont want this, calculate once and set registered_slot_[in/out]_types and slot_types_[in/out]
// set these values if not using auto_load_slot_types
registered_slot_in_types: {}, // slot types for nodeclass
registered_slot_out_types: {}, // slot types for nodeclass
slot_types_in: [], // slot types IN
slot_types_out: [], // slot types OUT
slot_types_default_in: [], // specify for each IN slot type a(/many) default node(s), use single string, array, or object (with node, title, parameters, ..) like for search
slot_types_default_out: [], // specify for each OUT slot type a(/many) default node(s), use single string, array, or object (with node, title, parameters, ..) like for search
alt_drag_do_clone_nodes: false, // [true!] very handy, ALT click to clone and drag the new node
do_add_triggers_slots: false, // [true!] will create and connect event slots when using action/events connections, !WILL CHANGE node mode when using onTrigger (enable mode colors), onExecuted does not need this
allow_multi_output_for_events: true, // [false!] being events, it is strongly reccomended to use them sequentially, one by one
middle_click_slot_add_default_node: false, //[true!] allows to create and connect a ndoe clicking with the third button (wheel)
release_link_on_empty_shows_menu: false, //[true!] dragging a link to empty space will open a menu, add from list, search or defaults
pointerevents_method: "mouse", // "mouse"|"pointer" use mouse for retrocompatibility issues? (none found @ now)
// TODO implement pointercancel, gotpointercapture, lostpointercapture, (pointerover, pointerout if necessary)
ctrl_shift_v_paste_connect_unselected_outputs: false, //[true!] allows ctrl + shift + v to paste nodes with the outputs of the unselected nodes connected with the inputs of the newly pasted nodes
// if true, all newly created nodes/links will use string UUIDs for their id fields instead of integers.
// use this if you must have node IDs that are unique across all graphs and subgraphs.
use_uuids: false,
/**
* Register a node class so it can be listed when the user wants to create a new one
* @method registerNodeType
* @param {String} type name of the node and path
* @param {Class} base_class class containing the structure of a node
*/
registerNodeType: function(type, base_class) {
if (!base_class.prototype) {
throw "Cannot register a simple object, it must be a class with a prototype";
}
base_class.type = type;
if (LiteGraph.debug) {
console.log("Node registered: " + type);
}
const classname = base_class.name;
const pos = type.lastIndexOf("/");
base_class.category = type.substring(0, pos);
if (!base_class.title) {
base_class.title = classname;
}
//extend class
for (var i in LGraphNode.prototype) {
if (!base_class.prototype[i]) {
base_class.prototype[i] = LGraphNode.prototype[i];
}
}
const prev = this.registered_node_types[type];
if(prev) {
console.log("replacing node type: " + type);
}
if( !Object.prototype.hasOwnProperty.call( base_class.prototype, "shape") ) {
Object.defineProperty(base_class.prototype, "shape", {
set: function(v) {
switch (v) {
case "default":
delete this._shape;
break;
case "box":
this._shape = LiteGraph.BOX_SHAPE;
break;
case "round":
this._shape = LiteGraph.ROUND_SHAPE;
break;
case "circle":
this._shape = LiteGraph.CIRCLE_SHAPE;
break;
case "card":
this._shape = LiteGraph.CARD_SHAPE;
break;
default:
this._shape = v;
}
},
get: function() {
return this._shape;
},
enumerable: true,
configurable: true
});
//used to know which nodes to create when dragging files to the canvas
if (base_class.supported_extensions) {
for (let i in base_class.supported_extensions) {
const ext = base_class.supported_extensions[i];
if(ext && ext.constructor === String) {
this.node_types_by_file_extension[ ext.toLowerCase() ] = base_class;
}
}
}
}
this.registered_node_types[type] = base_class;
if (base_class.constructor.name) {
this.Nodes[classname] = base_class;
}
if (LiteGraph.onNodeTypeRegistered) {
LiteGraph.onNodeTypeRegistered(type, base_class);
}
if (prev && LiteGraph.onNodeTypeReplaced) {
LiteGraph.onNodeTypeReplaced(type, base_class, prev);
}
//warnings
if (base_class.prototype.onPropertyChange) {
console.warn(
"LiteGraph node class " +
type +
" has onPropertyChange method, it must be called onPropertyChanged with d at the end"
);
}
// TODO one would want to know input and ouput :: this would allow through registerNodeAndSlotType to get all the slots types
if (this.auto_load_slot_types) {
new base_class(base_class.title || "tmpnode");
}
},
/**
* removes a node type from the system
* @method unregisterNodeType
* @param {String|Object} type name of the node or the node constructor itself
*/
unregisterNodeType: function(type) {
const base_class =
type.constructor === String
? this.registered_node_types[type]
: type;
if (!base_class) {
throw "node type not found: " + type;
}
delete this.registered_node_types[base_class.type];
if (base_class.constructor.name) {
delete this.Nodes[base_class.constructor.name];
}
},
/**
* Save a slot type and his node
* @method registerSlotType
* @param {String|Object} type name of the node or the node constructor itself
* @param {String} slot_type name of the slot type (variable type), eg. string, number, array, boolean, ..
*/
registerNodeAndSlotType: function(type, slot_type, out){
out = out || false;
const base_class =
type.constructor === String &&
this.registered_node_types[type] !== "anonymous"
? this.registered_node_types[type]
: type;
const class_type = base_class.constructor.type;
let allTypes = [];
if (typeof slot_type === "string") {
allTypes = slot_type.split(",");
} else if (slot_type == this.EVENT || slot_type == this.ACTION) {
allTypes = ["_event_"];
} else {
allTypes = ["*"];
}
for (let i = 0; i < allTypes.length; ++i) {
let slotType = allTypes[i];
if (slotType === "") {
slotType = "*";
}
const registerTo = out
? "registered_slot_out_types"
: "registered_slot_in_types";
if (this[registerTo][slotType] === undefined) {
this[registerTo][slotType] = { nodes: [] };
}
if (!this[registerTo][slotType].nodes.includes(class_type)) {
this[registerTo][slotType].nodes.push(class_type);
}
// check if is a new type
if (!out) {
if (!this.slot_types_in.includes(slotType.toLowerCase())) {
this.slot_types_in.push(slotType.toLowerCase());
this.slot_types_in.sort();
}
} else {
if (!this.slot_types_out.includes(slotType.toLowerCase())) {
this.slot_types_out.push(slotType.toLowerCase());
this.slot_types_out.sort();
}
}
}
},
/**
* Create a new nodetype by passing an object with some properties
* like onCreate, inputs:Array, outputs:Array, properties, onExecute
* @method buildNodeClassFromObject
* @param {String} name node name with namespace (p.e.: 'math/sum')
* @param {Object} object methods expected onCreate, inputs, outputs, properties, onExecute
*/
buildNodeClassFromObject: function(
name,
object
) {
var ctor_code = "";
if(object.inputs)
for(var i=0; i < object.inputs.length; ++i)
{
var _name = object.inputs[i][0];
var _type = object.inputs[i][1];
if(_type && _type.constructor === String)
_type = '"'+_type+'"';
ctor_code += "this.addInput('"+_name+"',"+_type+");\n";
}
if(object.outputs)
for(var i=0; i < object.outputs.length; ++i)
{
var _name = object.outputs[i][0];
var _type = object.outputs[i][1];
if(_type && _type.constructor === String)
_type = '"'+_type+'"';
ctor_code += "this.addOutput('"+_name+"',"+_type+");\n";
}
if(object.properties)
for(var i in object.properties)
{
var prop = object.properties[i];
if(prop && prop.constructor === String)
prop = '"'+prop+'"';
ctor_code += "this.addProperty('"+i+"',"+prop+");\n";
}
ctor_code += "if(this.onCreate)this.onCreate()";
var classobj = Function(ctor_code);
for(var i in object)
if(i!="inputs" && i!="outputs" && i!="properties")
classobj.prototype[i] = object[i];
classobj.title = object.title || name.split("/").pop();
classobj.desc = object.desc || "Generated from object";
this.registerNodeType(name, classobj);
return classobj;
},
/**
* Create a new nodetype by passing a function, it wraps it with a proper class and generates inputs according to the parameters of the function.
* Useful to wrap simple methods that do not require properties, and that only process some input to generate an output.
* @method wrapFunctionAsNode
* @param {String} name node name with namespace (p.e.: 'math/sum')
* @param {Function} func
* @param {Array} param_types [optional] an array containing the type of every parameter, otherwise parameters will accept any type
* @param {String} return_type [optional] string with the return type, otherwise it will be generic
* @param {Object} properties [optional] properties to be configurable
*/
wrapFunctionAsNode: function(
name,
func,
param_types,
return_type,
properties
) {
var params = Array(func.length);
var code = "";
if(param_types !== null) //null means no inputs
{
var names = LiteGraph.getParameterNames(func);
for (var i = 0; i < names.length; ++i) {
var type = 0;
if(param_types)
{
//type = param_types[i] != null ? "'" + param_types[i] + "'" : "0";
if( param_types[i] != null && param_types[i].constructor === String )
type = "'" + param_types[i] + "'" ;
else if( param_types[i] != null )
type = param_types[i];
}
code +=
"this.addInput('" +
names[i] +
"'," +
type +
");\n";
}
}
if(return_type !== null) //null means no output
code +=
"this.addOutput('out'," +
(return_type != null ? (return_type.constructor === String ? "'" + return_type + "'" : return_type) : 0) +
");\n";
if (properties) {
code +=
"this.properties = " + JSON.stringify(properties) + ";\n";
}
var classobj = Function(code);
classobj.title = name.split("/").pop();
classobj.desc = "Generated from " + func.name;
classobj.prototype.onExecute = function onExecute() {
for (var i = 0; i < params.length; ++i) {
params[i] = this.getInputData(i);
}
var r = func.apply(this, params);
this.setOutputData(0, r);
};
this.registerNodeType(name, classobj);
return classobj;
},
/**
* Removes all previously registered node's types
*/
clearRegisteredTypes: function() {
this.registered_node_types = {};
this.node_types_by_file_extension = {};
this.Nodes = {};
this.searchbox_extras = {};
},
/**
* Adds this method to all nodetypes, existing and to be created
* (You can add it to LGraphNode.prototype but then existing node types wont have it)
* @method addNodeMethod
* @param {Function} func
*/
addNodeMethod: function(name, func) {
LGraphNode.prototype[name] = func;
for (var i in this.registered_node_types) {
var type = this.registered_node_types[i];
if (type.prototype[name]) {
type.prototype["_" + name] = type.prototype[name];
} //keep old in case of replacing
type.prototype[name] = func;
}
},
/**
* Create a node of a given type with a name. The node is not attached to any graph yet.
* @method createNode
* @param {String} type full name of the node class. p.e. "math/sin"
* @param {String} name a name to distinguish from other nodes
* @param {Object} options to set options
*/
createNode: function(type, title, options) {
var base_class = this.registered_node_types[type];
if (!base_class) {
if (LiteGraph.debug) {
console.log(
'GraphNode type "' + type + '" not registered.'
);
}
return null;
}
var prototype = base_class.prototype || base_class;
title = title || base_class.title || type;
var node = null;
if (LiteGraph.catch_exceptions) {
try {
node = new base_class(title);
} catch (err) {
console.error(err);
return null;
}
} else {
node = new base_class(title);
}
node.type = type;
if (!node.title && title) {
node.title = title;
}
if (!node.properties) {
node.properties = {};
}
if (!node.properties_info) {
node.properties_info = [];
}
if (!node.flags) {
node.flags = {};
}
if (!node.size) {
node.size = node.computeSize();
//call onresize?
}
if (!node.pos) {
node.pos = LiteGraph.DEFAULT_POSITION.concat();
}
if (!node.mode) {
node.mode = LiteGraph.ALWAYS;
}
//extra options
if (options) {
for (var i in options) {
node[i] = options[i];
}
}
// callback
if ( node.onNodeCreated ) {
node.onNodeCreated();
}
return node;
},
/**
* Returns a registered node type with a given name
* @method getNodeType
* @param {String} type full name of the node class. p.e. "math/sin"
* @return {Class} the node class
*/
getNodeType: function(type) {
return this.registered_node_types[type];
},
/**
* Returns a list of node types matching one category
* @method getNodeType
* @param {String} category category name
* @return {Array} array with all the node classes
*/
getNodeTypesInCategory: function(category, filter) {
var r = [];
for (var i in this.registered_node_types) {
var type = this.registered_node_types[i];
if (type.filter != filter) {
continue;
}
if (category == "") {
if (type.category == null) {
r.push(type);
}
} else if (type.category == category) {
r.push(type);
}
}
if (this.auto_sort_node_types) {
r.sort(function(a,b){return a.title.localeCompare(b.title)});
}
return r;
},
/**
* Returns a list with all the node type categories
* @method getNodeTypesCategories
* @param {String} filter only nodes with ctor.filter equal can be shown
* @return {Array} array with all the names of the categories
*/
getNodeTypesCategories: function( filter ) {
var categories = { "": 1 };
for (var i in this.registered_node_types) {
var type = this.registered_node_types[i];
if ( type.category && !type.skip_list )
{
if(type.filter != filter)
continue;
categories[type.category] = 1;
}
}
var result = [];
for (var i in categories) {
result.push(i);
}
return this.auto_sort_node_types ? result.sort() : result;
},
//debug purposes: reloads all the js scripts that matches a wildcard
reloadNodes: function(folder_wildcard) {
var tmp = document.getElementsByTagName("script");
//weird, this array changes by its own, so we use a copy
var script_files = [];
for (var i=0; i < tmp.length; i++) {
script_files.push(tmp[i]);
}
var docHeadObj = document.getElementsByTagName("head")[0];
folder_wildcard = document.location.href + folder_wildcard;
for (var i=0; i < script_files.length; i++) {
var src = script_files[i].src;
if (
!src ||
src.substr(0, folder_wildcard.length) != folder_wildcard
) {
continue;
}
try {
if (LiteGraph.debug) {
console.log("Reloading: " + src);
}
var dynamicScript = document.createElement("script");
dynamicScript.type = "text/javascript";
dynamicScript.src = src;
docHeadObj.appendChild(dynamicScript);
docHeadObj.removeChild(script_files[i]);
} catch (err) {
if (LiteGraph.throw_errors) {
throw err;
}
if (LiteGraph.debug) {
console.log("Error while reloading " + src);
}
}
}
if (LiteGraph.debug) {
console.log("Nodes reloaded");
}
},
//separated just to improve if it doesn't work
cloneObject: function(obj, target) {
if (obj == null) {
return null;
}
var r = JSON.parse(JSON.stringify(obj));
if (!target) {
return r;
}
for (var i in r) {
target[i] = r[i];
}
return target;
},
/*
* https://gist.github.com/jed/982883?permalink_comment_id=852670#gistcomment-852670
*/
uuidv4: function() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16));
},
/**
* Returns if the types of two slots are compatible (taking into account wildcards, etc)
* @method isValidConnection
* @param {String} type_a
* @param {String} type_b
* @return {Boolean} true if they can be connected
*/
isValidConnection: function(type_a, type_b) {
if (type_a=="" || type_a==="*") type_a = 0;
if (type_b=="" || type_b==="*") type_b = 0;
if (
!type_a //generic output
|| !type_b // generic input
|| type_a == type_b //same type (is valid for triggers)
|| (type_a == LiteGraph.EVENT && type_b == LiteGraph.ACTION)
) {
return true;
}
// Enforce string type to handle toLowerCase call (-1 number not ok)
type_a = String(type_a);
type_b = String(type_b);
type_a = type_a.toLowerCase();
type_b = type_b.toLowerCase();
// For nodes supporting multiple connection types
if (type_a.indexOf(",") == -1 && type_b.indexOf(",") == -1) {
return type_a == type_b;
}
// Check all permutations to see if one is valid
var supported_types_a = type_a.split(",");
var supported_types_b = type_b.split(",");
for (var i = 0; i < supported_types_a.length; ++i) {
for (var j = 0; j < supported_types_b.length; ++j) {
if(this.isValidConnection(supported_types_a[i],supported_types_b[j])){
//if (supported_types_a[i] == supported_types_b[j]) {
return true;
}
}
}
return false;
},
/**
* Register a string in the search box so when the user types it it will recommend this node
* @method registerSearchboxExtra
* @param {String} node_type the node recommended
* @param {String} description text to show next to it
* @param {Object} data it could contain info of how the node should be configured
* @return {Boolean} true if they can be connected
*/
registerSearchboxExtra: function(node_type, description, data) {
this.searchbox_extras[description.toLowerCase()] = {
type: node_type,
desc: description,
data: data
};
},
/**
* Wrapper to load files (from url using fetch or from file using FileReader)
* @method fetchFile
* @param {String|File|Blob} url the url of the file (or the file itself)
* @param {String} type an string to know how to fetch it: "text","arraybuffer","json","blob"
* @param {Function} on_complete callback(data)
* @param {Function} on_error in case of an error
* @return {FileReader|Promise} returns the object used to
*/
fetchFile: function( url, type, on_complete, on_error ) {
var that = this;
if(!url)
return null;
type = type || "text";
if( url.constructor === String )
{
if (url.substr(0, 4) == "http" && LiteGraph.proxy) {
url = LiteGraph.proxy + url.substr(url.indexOf(":") + 3);
}
return fetch(url)
.then(function(response) {
if(!response.ok)
throw new Error("File not found"); //it will be catch below
if(type == "arraybuffer")
return response.arrayBuffer();
else if(type == "text" || type == "string")
return response.text();
else if(type == "json")
return response.json();
else if(type == "blob")
return response.blob();
})
.then(function(data) {
if(on_complete)
on_complete(data);
})
.catch(function(error) {
console.error("error fetching file:",url);
if(on_error)
on_error(error);
});
}
else if( url.constructor === File || url.constructor === Blob)
{
var reader = new FileReader();
reader.onload = function(e)
{
var v = e.target.result;
if( type == "json" )
v = JSON.parse(v);
if(on_complete)
on_complete(v);
}
if(type == "arraybuffer")
return reader.readAsArrayBuffer(url);
else if(type == "text" || type == "json")
return reader.readAsText(url);
else if(type == "blob")
return reader.readAsBinaryString(url);
}
return null;
}
});
//timer that works everywhere
if (typeof performance != "undefined") {
LiteGraph.getTime = performance.now.bind(performance);
} else if (typeof Date != "undefined" && Date.now) {
LiteGraph.getTime = Date.now.bind(Date);
} else if (typeof process != "undefined") {
LiteGraph.getTime = function() {
var t = process.hrtime();
return t[0] * 0.001 + t[1] * 1e-6;
};
} else {
LiteGraph.getTime = function getTime() {
return new Date().getTime();
};
}
//*********************************************************************************
// LGraph CLASS
//*********************************************************************************
/**
* LGraph is the class that contain a full graph. We instantiate one and add nodes to it, and then we can run the execution loop.
* supported callbacks:
+ onNodeAdded: when a new node is added to the graph
+ onNodeRemoved: when a node inside this graph is removed
+ onNodeConnectionChange: some connection has changed in the graph (connected or disconnected)
*
* @class LGraph
* @constructor
* @param {Object} o data from previous serialization [optional]
*/
function LGraph(o) {
if (LiteGraph.debug) {
console.log("Graph created");
}
this.list_of_graphcanvas = null;
this.clear();
if (o) {
this.configure(o);
}
}
global.LGraph = LiteGraph.LGraph = LGraph;
//default supported types
LGraph.supported_types = ["number", "string", "boolean"];
//used to know which types of connections support this graph (some graphs do not allow certain types)
LGraph.prototype.getSupportedTypes = function() {
return this.supported_types || LGraph.supported_types;
};
LGraph.STATUS_STOPPED = 1;
LGraph.STATUS_RUNNING = 2;
/**
* Removes all nodes from this graph
* @method clear
*/
LGraph.prototype.clear = function() {
this.stop();
this.status = LGraph.STATUS_STOPPED;
this.last_node_id = 0;
this.last_link_id = 0;
this._version = -1; //used to detect changes
//safe clear
if (this._nodes) {
for (var i = 0; i < this._nodes.length; ++i) {
var node = this._nodes[i];
if (node.onRemoved) {
node.onRemoved();
}
}
}
//nodes
this._nodes = [];
this._nodes_by_id = {};
this._nodes_in_order = []; //nodes sorted in execution order
this._nodes_executable = null; //nodes that contain onExecute sorted in execution order
//other scene stuff
this._groups = [];
//links
this.links = {}; //container with all the links
//iterations
this.iteration = 0;
//custom data
this.config = {};
this.vars = {};
this.extra = {}; //to store custom data
//timing
this.globaltime = 0;
this.runningtime = 0;
this.fixedtime = 0;
this.fixedtime_lapse = 0.01;
this.elapsed_time = 0.01;
this.last_update_time = 0;
this.starttime = 0;
this.catch_errors = true;
this.nodes_executing = [];
this.nodes_actioning = [];
this.nodes_executedAction = [];
//subgraph_data
this.inputs = {};
this.outputs = {};
//notify canvas to redraw
this.change();
this.sendActionToCanvas("clear");
};
/**
* Attach Canvas to this graph
* @method attachCanvas
* @param {GraphCanvas} graph_canvas
*/
LGraph.prototype.attachCanvas = function(graphcanvas) {
if (graphcanvas.constructor != LGraphCanvas) {
throw "attachCanvas expects a LGraphCanvas instance";
}
if (graphcanvas.graph && graphcanvas.graph != this) {
graphcanvas.graph.detachCanvas(graphcanvas);
}
graphcanvas.graph = this;
if (!this.list_of_graphcanvas) {
this.list_of_graphcanvas = [];
}
this.list_of_graphcanvas.push(graphcanvas);
};
/**
* Detach Canvas from this graph
* @method detachCanvas
* @param {GraphCanvas} graph_canvas
*/
LGraph.prototype.detachCanvas = function(graphcanvas) {
if (!this.list_of_graphcanvas) {
return;
}
var pos = this.list_of_graphcanvas.indexOf(graphcanvas);
if (pos == -1) {
return;
}
graphcanvas.graph = null;
this.list_of_graphcanvas.splice(pos, 1);
};
/**
* Starts running this graph every interval milliseconds.
* @method start
* @param {number} interval amount of milliseconds between executions, if 0 then it renders to the monitor refresh rate
*/
LGraph.prototype.start = function(interval) {
if (this.status == LGraph.STATUS_RUNNING) {
return;
}
this.status = LGraph.STATUS_RUNNING;
if (this.onPlayEvent) {
this.onPlayEvent();
}
this.sendEventToAllNodes("onStart");
//launch
this.starttime = LiteGraph.getTime();
this.last_update_time = this.starttime;
interval = interval || 0;
var that = this;
//execute once per frame
if ( interval == 0 && typeof window != "undefined" && window.requestAnimationFrame ) {
function on_frame() {
if (that.execution_timer_id != -1) {
return;
}
window.requestAnimationFrame(on_frame);
if(that.onBeforeStep)
that.onBeforeStep();
that.runStep(1, !that.catch_errors);
if(that.onAfterStep)
that.onAfterStep();
}
this.execution_timer_id = -1;
on_frame();
} else { //execute every 'interval' ms
this.execution_timer_id = setInterval(function() {
//execute
if(that.onBeforeStep)
that.onBeforeStep();
that.runStep(1, !that.catch_errors);
if(that.onAfterStep)
that.onAfterStep();
}, interval);
}
};
/**
* Stops the execution loop of the graph
* @method stop execution
*/
LGraph.prototype.stop = function() {
if (this.status == LGraph.STATUS_STOPPED) {
return;
}
this.status = LGraph.STATUS_STOPPED;
if (this.onStopEvent) {
this.onStopEvent();
}
if (this.execution_timer_id != null) {
if (this.execution_timer_id != -1) {
clearInterval(this.execution_timer_id);
}
this.execution_timer_id = null;
}
this.sendEventToAllNodes("onStop");
};
/**
* Run N steps (cycles) of the graph
* @method runStep
* @param {number} num number of steps to run, default is 1
* @param {Boolean} do_not_catch_errors [optional] if you want to try/catch errors
* @param {number} limit max number of nodes to execute (used to execute from start to a node)
*/
LGraph.prototype.runStep = function(num, do_not_catch_errors, limit ) {
num = num || 1;
var start = LiteGraph.getTime();
this.globaltime = 0.001 * (start - this.starttime);
//not optimal: executes possible pending actions in node, problem is it is not optimized
//it is done here as if it was done in the later loop it wont be called in the node missed the onExecute
//from now on it will iterate only on executable nodes which is faster
var nodes = this._nodes_executable
? this._nodes_executable
: this._nodes;
if (!nodes) {
return;
}
limit = limit || nodes.length;
if (do_not_catch_errors) {
//iterations
for (var i = 0; i < num; i++) {
for (var j = 0; j < limit; ++j) {
var node = nodes[j];
if(LiteGraph.use_deferred_actions && node._waiting_actions && node._waiting_actions.length)
node.executePendingActions();
if (node.mode == LiteGraph.ALWAYS && node.onExecute) {
//wrap node.onExecute();
node.doExecute();
}
}
this.fixedtime += this.fixedtime_lapse;
if (this.onExecuteStep) {
this.onExecuteStep();
}
}
if (this.onAfterExecute) {
this.onAfterExecute();
}
} else { //catch errors
try {
//iterations
for (var i = 0; i < num; i++) {
for (var j = 0; j < limit; ++j) {
var node = nodes[j];
if(LiteGraph.use_deferred_actions && node._waiting_actions && node._waiting_actions.length)
node.executePendingActions();
if (node.mode == LiteGraph.ALWAYS && node.onExecute) {
node.onExecute();
}
}
this.fixedtime += this.fixedtime_lapse;
if (this.onExecuteStep) {
this.onExecuteStep();
}
}
if (this.onAfterExecute) {
this.onAfterExecute();
}
this.errors_in_execution = false;
} catch (err) {
this.errors_in_execution = true;
if (LiteGraph.throw_errors) {
throw err;
}
if (LiteGraph.debug) {
console.log("Error during execution: " + err);
}
this.stop();
}
}
var now = LiteGraph.getTime();
var elapsed = now - start;
if (elapsed == 0) {
elapsed = 1;
}
this.execution_time = 0.001 * elapsed;
this.globaltime += 0.001 * elapsed;
this.iteration += 1;
this.elapsed_time = (now - this.last_update_time) * 0.001;
this.last_update_time = now;
this.nodes_executing = [];
this.nodes_actioning = [];
this.nodes_executedAction = [];
};
/**
* Updates the graph execution order according to relevance of the nodes (nodes with only outputs have more relevance than
* nodes with only inputs.
* @method updateExecutionOrder
*/
LGraph.prototype.updateExecutionOrder = function() {
this._nodes_in_order = this.computeExecutionOrder(false);
this._nodes_executable = [];
for (var i = 0; i < this._nodes_in_order.length; ++i) {
if (this._nodes_in_order[i].onExecute) {
this._nodes_executable.push(this._nodes_in_order[i]);
}
}
};
//This is more internal, it computes the executable nodes in order and returns it
LGraph.prototype.computeExecutionOrder = function(
only_onExecute,
set_level
) {
var L = [];
var S = [];
var M = {};
var visited_links = {}; //to avoid repeating links
var remaining_links = {}; //to a
//search for the nodes without inputs (starting nodes)
for (var i = 0, l = this._nodes.length; i < l; ++i) {
var node = this._nodes[i];
if (only_onExecute && !node.onExecute) {
continue;
}
M[node.id] = node; //add to pending nodes
var num = 0; //num of input connections
if (node.inputs) {
for (var j = 0, l2 = node.inputs.length; j < l2; j++) {
if (node.inputs[j] && node.inputs[j].link != null) {
num += 1;
}
}
}
if (num == 0) {
//is a starting node
S.push(node);
if (set_level) {
node._level = 1;
}
} //num of input links
else {
if (set_level) {
node._level = 0;
}
remaining_links[node.id] = num;
}
}
while (true) {
if (S.length == 0) {
break;
}
//get an starting node
var node = S.shift();
L.push(node); //add to ordered list
delete M[node.id]; //remove from the pending nodes
if (!node.outputs) {
continue;
}
//for every output
for (var i = 0; i < node.outputs.length; i++) {
var output = node.outputs[i];
//not connected
if (
output == null ||
output.links == null ||
output.links.length == 0
) {
continue;
}
//for every connection
for (var j = 0; j < output.links.length; j++) {
var link_id = output.links[j];
var link = this.links[link_id];
if (!link) {
continue;
}
//already visited link (ignore it)
if (visited_links[link.id]) {
continue;
}
var target_node = this.getNodeById(link.target_id);
if (target_node == null) {
visited_links[link.id] = true;
continue;
}
if (
set_level &&
(!target_node._level ||
target_node._level <= node._level)
) {
target_node._level = node._level + 1;
}
visited_links[link.id] = true; //mark as visited
remaining_links[target_node.id] -= 1; //reduce the number of links remaining
if (remaining_links[target_node.id] == 0) {
S.push(target_node);
} //if no more links, then add to starters array
}
}
}
//the remaining ones (loops)
for (var i in M) {
L.push(M[i]);
}
if (L.length != this._nodes.length && LiteGraph.debug) {
console.warn("something went wrong, nodes missing");
}
var l = L.length;
//save order number in the node
for (var i = 0; i < l; ++i) {
L[i].order = i;
}
//sort now by priority
L = L.sort(function(A, B) {
var Ap = A.constructor.priority || A.priority || 0;
var Bp = B.constructor.priority || B.priority || 0;
if (Ap == Bp) {
//if same priority, sort by order
return A.order - B.order;
}
return Ap - Bp; //sort by priority
});
//save order number in the node, again...
for (var i = 0; i < l; ++i) {
L[i].order = i;
}
return L;
};
/**
* Returns all the nodes that could affect this one (ancestors) by crawling all the inputs recursively.
* It doesn't include the node itself
* @method getAncestors
* @return {Array} an array with all the LGraphNodes that affect this node, in order of execution
*/
LGraph.prototype.getAncestors = function(node) {
var ancestors = [];
var pending = [node];
var visited = {};
while (pending.length) {
var current = pending.shift();
if (!current.inputs) {
continue;
}
if (!visited[current.id] && current != node) {
visited[current.id] = true;
ancestors.push(current);
}
for (var i = 0; i < current.inputs.length; ++i) {
var input = current.getInputNode(i);
if (input && ancestors.indexOf(input) == -1) {
pending.push(input);
}
}
}
ancestors.sort(function(a, b) {
return a.order - b.order;
});
return ancestors;
};
/**
* Positions every node in a more readable manner
* @method arrange
*/
LGraph.prototype.arrange = function (margin, layout) {
margin = margin || 100;
const nodes = this.computeExecutionOrder(false, true);
const columns = [];
for (let i = 0; i < nodes.length; ++i) {
const node = nodes[i];
const col = node._level || 1;
if (!columns[col]) {
columns[col] = [];
}
columns[col].push(node);
}
let x = margin;
for (let i = 0; i < columns.length; ++i) {
const column = columns[i];
if (!column) {
continue;
}
let max_size = 100;
let y = margin + LiteGraph.NODE_TITLE_HEIGHT;
for (let j = 0; j < column.length; ++j) {
const node = column[j];
node.pos[0] = (layout == LiteGraph.VERTICAL_LAYOUT) ? y : x;
node.pos[1] = (layout == LiteGraph.VERTICAL_LAYOUT) ? x : y;
const max_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 1 : 0;
if (node.size[max_size_index] > max_size) {
max_size = node.size[max_size_index];
}
const node_size_index = (layout == LiteGraph.VERTICAL_LAYOUT) ? 0 : 1;
y += node.size[node_size_index] + margin + LiteGraph.NODE_TITLE_HEIGHT;
}
x += max_size + margin;
}
this.setDirtyCanvas(true, true);
};
/**
* Returns the amount of time the graph has been running in milliseconds
* @method getTime
* @return {number} number of milliseconds the graph has been running
*/
LGraph.prototype.getTime = function() {
return this.globaltime;
};
/**
* Returns the amount of time accumulated using the fixedtime_lapse var. This is used in context where the time increments should be constant
* @method getFixedTime
* @return {number} number of milliseconds the graph has been running
*/
LGraph.prototype.getFixedTime = function() {
return this.fixedtime;
};
/**
* Returns the amount of time it took to compute the latest iteration. Take into account that this number could be not correct
* if the nodes are using graphical actions
* @method getElapsedTime
* @return {number} number of milliseconds it took the last cycle
*/
LGraph.prototype.getElapsedTime = function() {
return this.elapsed_time;
};
/**
* Sends an event to all the nodes, useful to trigger stuff
* @method sendEventToAllNodes
* @param {String} eventname the name of the event (function to be called)
* @param {Array} params parameters in array format
*/
LGraph.prototype.sendEventToAllNodes = function(eventname, params, mode) {
mode = mode || LiteGraph.ALWAYS;
var nodes = this._nodes_in_order ? this._nodes_in_order : this._nodes;
if (!nodes) {
return;
}
for (var j = 0, l = nodes.length; j < l; ++j) {
var node = nodes[j];
if (
node.constructor === LiteGraph.Subgraph &&
eventname != "onExecute"
) {
if (node.mode == mode) {
node.sendEventToAllNodes(eventname, params, mode);
}
continue;
}
if (!node[eventname] || node.mode != mode) {
continue;
}
if (params === undefined) {
node[eventname]();
} else if (params && params.constructor === Array) {
node[eventname].apply(node, params);
} else {
node[eventname](params);
}
}
};
LGraph.prototype.sendActionToCanvas = function(action, params) {
if (!this.list_of_graphcanvas) {
return;
}
for (var i = 0; i < this.list_of_graphcanvas.length; ++i) {
var c = this.list_of_graphcanvas[i];
if (c[action]) {
c[action].apply(c, params);
}
}
};
/**
* Adds a new node instance to this graph
* @method add
* @param {LGraphNode} node the instance of the node
*/
LGraph.prototype.add = function(node, skip_compute_order) {
if (!node) {
return;
}
//groups
if (node.constructor === LGraphGroup) {
this._groups.push(node);
this.setDirtyCanvas(true);
this.change();
node.graph = this;
this._version++;
return;
}
//nodes
if (node.id != -1 && this._nodes_by_id[node.id] != null) {
console.warn(
"LiteGraph: there is already a node with this ID, changing it"
);
if (LiteGraph.use_uuids) {
node.id = LiteGraph.uuidv4();
}
else {
node.id = ++this.last_node_id;
}
}
if (this._nodes.length >= LiteGraph.MAX_NUMBER_OF_NODES) {
throw "LiteGraph: max number of nodes in a graph reached";
}
//give him an id
if (LiteGraph.use_uuids) {
if (node.id == null || node.id == -1)
node.id = LiteGraph.uuidv4();
}
else {
if (node.id == null || node.id == -1) {
node.id = ++this.last_node_id;
} else if (this.last_node_id < node.id) {
this.last_node_id = node.id;
}
}
node.graph = this;
this._version++;
this._nodes.push(node);
this._nodes_by_id[node.id] = node;
if (node.onAdded) {
node.onAdded(this);
}
if (this.config.align_to_grid) {
node.alignToGrid();
}
if (!skip_compute_order) {
this.updateExecutionOrder();
}
if (this.onNodeAdded) {
this.onNodeAdded(node);
}
this.setDirtyCanvas(true);
this.change();
return node; //to chain actions
};
/**
* Removes a node from the graph
* @method remove
* @param {LGraphNode} node the instance of the node
*/
LGraph.prototype.remove = function(node) {
if (node.constructor === LiteGraph.LGraphGroup) {
var index = this._groups.indexOf(node);
if (index != -1) {
this._groups.splice(index, 1);
}
node.graph = null;
this._version++;
this.setDirtyCanvas(true, true);
this.change();
return;
}
if (this._nodes_by_id[node.id] == null) {
return;
} //not found
if (node.ignore_remove) {
return;
} //cannot be removed
this.beforeChange(); //sure? - almost sure is wrong
//disconnect inputs
if (node.inputs) {
for (var i = 0; i < node.inputs.length; i++) {
var slot = node.inputs[i];
if (slot.link != null) {
node.disconnectInput(i);
}
}
}
//disconnect outputs
if (node.outputs) {
for (var i = 0; i < node.outputs.length; i++) {
var slot = node.outputs[i];
if (slot.links != null && slot.links.length) {
node.disconnectOutput(i);
}
}
}
//node.id = -1; //why?
//callback
if (node.onRemoved) {
node.onRemoved();
}
node.graph = null;
this._version++;
//remove from canvas render
if (this.list_of_graphcanvas) {
for (var i = 0; i < this.list_of_graphcanvas.length; ++i) {
var canvas = this.list_of_graphcanvas[i];
if (canvas.selected_nodes[node.id]) {
delete canvas.selected_nodes[node.id];
}
if (canvas.node_dragged == node) {
canvas.node_dragged = null;
}
}
}
//remove from containers
var pos = this._nodes.indexOf(node);
if (pos != -1) {
this._nodes.splice(pos, 1);
}
delete this._nodes_by_id[node.id];
if (this.onNodeRemoved) {
this.onNodeRemoved(node);
}
//close panels
this.sendActionToCanvas("checkPanels");
this.setDirtyCanvas(true, true);
this.afterChange(); //sure? - almost sure is wrong
this.change();
this.updateExecutionOrder();
};
/**
* Returns a node by its id.
* @method getNodeById
* @param {Number} id
*/
LGraph.prototype.getNodeById = function(id) {
if (id == null) {
return null;
}
return this._nodes_by_id[id];
};
/**
* Returns a list of nodes that matches a class
* @method findNodesByClass
* @param {Class} classObject the class itself (not an string)
* @return {Array} a list with all the nodes of this type
*/
LGraph.prototype.findNodesByClass = function(classObject, result) {
result = result || [];
result.length = 0;
for (var i = 0, l = this._nodes.length; i < l; ++i) {
if (this._nodes[i].constructor === classObject) {
result.push(this._nodes[i]);
}
}
return result;
};
/**
* Returns a list of nodes that matches a type
* @method findNodesByType
* @param {String} type the name of the node type
* @return {Array} a list with all the nodes of this type
*/
LGraph.prototype.findNodesByType = function(type, result) {
var type = type.toLowerCase();
result = result || [];
result.length = 0;
for (var i = 0, l = this._nodes.length; i < l; ++i) {
if (this._nodes[i].type.toLowerCase() == type) {
result.push(this._nodes[i]);
}
}
return result;
};
/**
* Returns the first node that matches a name in its title
* @method findNodeByTitle
* @param {String} name the name of the node to search
* @return {Node} the node or null
*/
LGraph.prototype.findNodeByTitle = function(title) {
for (var i = 0, l = this._nodes.length; i < l; ++i) {
if (this._nodes[i].title == title) {
return this._nodes[i];
}
}
return null;
};
/**
* Returns a list of nodes that matches a name
* @method findNodesByTitle
* @param {String} name the name of the node to search
* @return {Array} a list with all the nodes with this name
*/
LGraph.prototype.findNodesByTitle = function(title) {
var result = [];
for (var i = 0, l = this._nodes.length; i < l; ++i) {
if (this._nodes[i].title == title) {
result.push(this._nodes[i]);
}
}
return result;
};
/**
* Returns the top-most node in this position of the canvas
* @method getNodeOnPos
* @param {number} x the x coordinate in canvas space
* @param {number} y the y coordinate in canvas space
* @param {Array} nodes_list a list with all the nodes to search from, by default is all the nodes in the graph
* @return {LGraphNode} the node at this position or null
*/
LGraph.prototype.getNodeOnPos = function(x, y, nodes_list, margin) {
nodes_list = nodes_list || this._nodes;
var nRet = null;
for (var i = nodes_list.length - 1; i >= 0; i--) {
var n = nodes_list[i];
if (n.isPointInside(x, y, margin)) {
// check for lesser interest nodes (TODO check for overlapping, use the top)
/*if (typeof n == "LGraphGroup"){
nRet = n;
}else{*/
return n;
/*}*/
}
}
return nRet;
};
/**
* Returns the top-most group in that position
* @method getGroupOnPos
* @param {number} x the x coordinate in canvas space
* @param {number} y the y coordinate in canvas space
* @return {LGraphGroup} the group or null
*/
LGraph.prototype.getGroupOnPos = function(x, y) {
for (var i = this._groups.length - 1; i >= 0; i--) {
var g = this._groups[i];
if (g.isPointInside(x, y, 2, true)) {
return g;
}
}
return null;
};
/**
* Checks that the node type matches the node type registered, used when replacing a nodetype by a newer version during execution
* this replaces the ones using the old version with the new version
* @method checkNodeTypes
*/
LGraph.prototype.checkNodeTypes = function() {
var changes = false;
for (var i = 0; i < this._nodes.length; i++) {
var node = this._nodes[i];
var ctor = LiteGraph.registered_node_types[node.type];
if (node.constructor == ctor) {
continue;
}
console.log("node being replaced by newer version: " + node.type);
var newnode = LiteGraph.createNode(node.type);
changes = true;
this._nodes[i] = newnode;
newnode.configure(node.serialize());
newnode.graph = this;
this._nodes_by_id[newnode.id] = newnode;
if (node.inputs) {
newnode.inputs = node.inputs.concat();
}
if (node.outputs) {
newnode.outputs = node.outputs.concat();
}
}
this.updateExecutionOrder();
};
// ********** GLOBALS *****************
LGraph.prototype.onAction = function(action, param, options) {
this._input_nodes = this.findNodesByClass(
LiteGraph.GraphInput,
this._input_nodes
);
for (var i = 0; i < this._input_nodes.length; ++i) {
var node = this._input_nodes[i];
if (node.properties.name != action) {
continue;
}
//wrap node.onAction(action, param);
node.actionDo(action, param, options);
break;
}
};
LGraph.prototype.trigger = function(action, param) {
if (this.onTrigger) {
this.onTrigger(action, param);
}
};
/**
* Tell this graph it has a global graph input of this type
* @method addGlobalInput
* @param {String} name
* @param {String} type
* @param {*} value [optional]
*/
LGraph.prototype.addInput = function(name, type, value) {
var input = this.inputs[name];
if (input) {
//already exist
return;
}
this.beforeChange();
this.inputs[name] = { name: name, type: type, value: value };
this._version++;
this.afterChange();
if (this.onInputAdded) {
this.onInputAdded(name, type);
}
if (this.onInputsOutputsChange) {
this.onInputsOutputsChange();
}
};
/**
* Assign a data to the global graph input
* @method setGlobalInputData
* @param {String} name
* @param {*} data
*/
LGraph.prototype.setInputData = function(name, data) {
var input = this.inputs[name];
if (!input) {
return;
}
input.value = data;
};
/**
* Returns the current value of a global graph input
* @method getInputData
* @param {String} name
* @return {*} the data
*/
LGraph.prototype.getInputData = function(name) {
var input = this.inputs[name];
if (!input) {
return null;
}
return input.value;
};
/**
* Changes the name of a global graph input
* @method renameInput
* @param {String} old_name
* @param {String} new_name
*/
LGraph.prototype.renameInput = function(old_name, name) {
if (name == old_name) {
return;
}
if (!this.inputs[old_name]) {
return false;
}
if (this.inputs[name]) {
console.error("there is already one input with that name");
return false;
}
this.inputs[name] = this.inputs[old_name];
delete this.inputs[old_name];
this._version++;
if (this.onInputRenamed) {
this.onInputRenamed(old_name, name);
}
if (this.onInputsOutputsChange) {
this.onInputsOutputsChange();
}
};
/**
* Changes the type of a global graph input
* @method changeInputType
* @param {String} name
* @param {String} type
*/
LGraph.prototype.changeInputType = function(name, type) {
if (!this.inputs[name]) {
return false;
}
if (
this.inputs[name].type &&
String(this.inputs[name].type).toLowerCase() ==
String(type).toLowerCase()
) {
return;
}
this.inputs[name].type = type;
this._version++;
if (this.onInputTypeChanged) {
this.onInputTypeChanged(name, type);
}
};
/**
* Removes a global graph input
* @method removeInput
* @param {String} name
* @param {String} type
*/
LGraph.prototype.removeInput = function(name) {
if (!this.inputs[name]) {
return false;
}
delete this.inputs[name];
this._version++;
if (this.onInputRemoved) {
this.onInputRemoved(name);
}
if (this.onInputsOutputsChange) {
this.onInputsOutputsChange();
}
return true;
};
/**
* Creates a global graph output
* @method addOutput
* @param {String} name
* @param {String} type
* @param {*} value
*/
LGraph.prototype.addOutput = function(name, type, value) {
this.outputs[name] = { name: name, type: type, value: value };
this._version++;
if (this.onOutputAdded) {
this.onOutputAdded(name, type);
}
if (this.onInputsOutputsChange) {
this.onInputsOutputsChange();
}
};
/**
* Assign a data to the global output
* @method setOutputData
* @param {String} name
* @param {String} value
*/
LGraph.prototype.setOutputData = function(name, value) {
var output = this.outputs[name];
if (!output) {
return;
}
output.value = value;
};
/**
* Returns the current value of a global graph output
* @method getOutputData
* @param {String} name
* @return {*} the data
*/
LGraph.prototype.getOutputData = function(name) {
var output = this.outputs[name];
if (!output) {
return null;
}
return output.value;
};
/**
* Renames a global graph output
* @method renameOutput
* @param {String} old_name
* @param {String} new_name
*/
LGraph.prototype.renameOutput = function(old_name, name) {
if (!this.outputs[old_name]) {
return false;
}
if (this.outputs[name]) {
console.error("there is already one output with that name");
return false;
}
this.outputs[name] = this.outputs[old_name];
delete this.outputs[old_name];
this._version++;
if (this.onOutputRenamed) {
this.onOutputRenamed(old_name, name);
}
if (this.onInputsOutputsChange) {
this.onInputsOutputsChange();
}
};
/**
* Changes the type of a global graph output
* @method changeOutputType
* @param {String} name
* @param {String} type
*/
LGraph.prototype.changeOutputType = function(name, type) {
if (!this.outputs[name]) {
return false;
}
if (
this.outputs[name].type &&
String(this.outputs[name].type).toLowerCase() ==
String(type).toLowerCase()
) {
return;
}
this.outputs[name].type = type;
this._version++;
if (this.onOutputTypeChanged) {
this.onOutputTypeChanged(name, type);
}
};
/**
* Removes a global graph output
* @method removeOutput
* @param {String} name
*/
LGraph.prototype.removeOutput = function(name) {
if (!this.outputs[name]) {
return false;
}
delete this.outputs[name];
this._version++;
if (this.onOutputRemoved) {
this.onOutputRemoved(name);
}
if (this.onInputsOutputsChange) {
this.onInputsOutputsChange();
}
return true;
};
LGraph.prototype.triggerInput = function(name, value) {
var nodes = this.findNodesByTitle(name);
for (var i = 0; i < nodes.length; ++i) {
nodes[i].onTrigger(value);
}
};
LGraph.prototype.setCallback = function(name, func) {
var nodes = this.findNodesByTitle(name);
for (var i = 0; i < nodes.length; ++i) {
nodes[i].setTrigger(func);
}
};
//used for undo, called before any change is made to the graph
LGraph.prototype.beforeChange = function(info) {
if (this.onBeforeChange) {
this.onBeforeChange(this,info);
}
this.sendActionToCanvas("onBeforeChange", this);
};
//used to resend actions, called after any change is made to the graph
LGraph.prototype.afterChange = function(info) {
if (this.onAfterChange) {
this.onAfterChange(this,info);
}
this.sendActionToCanvas("onAfterChange", this);
};
LGraph.prototype.connectionChange = function(node, link_info) {
this.updateExecutionOrder();
if (this.onConnectionChange) {
this.onConnectionChange(node);
}
this._version++;
this.sendActionToCanvas("onConnectionChange");
};
/**
* returns if the graph is in live mode
* @method isLive
*/
LGraph.prototype.isLive = function() {
if (!this.list_of_graphcanvas) {
return false;
}
for (var i = 0; i < this.list_of_graphcanvas.length; ++i) {
var c = this.list_of_graphcanvas[i];
if (c.live_mode) {
return true;
}
}
return false;
};
/**
* clears the triggered slot animation in all links (stop visual animation)
* @method clearTriggeredSlots
*/
LGraph.prototype.clearTriggeredSlots = function() {
for (var i in this.links) {
var link_info = this.links[i];
if (!link_info) {
continue;
}
if (link_info._last_time) {
link_info._last_time = 0;
}
}
};
/* Called when something visually changed (not the graph!) */
LGraph.prototype.change = function() {
if (LiteGraph.debug) {
console.log("Graph changed");
}
this.sendActionToCanvas("setDirty", [true, true]);
if (this.on_change) {
this.on_change(this);
}
};
LGraph.prototype.setDirtyCanvas = function(fg, bg) {
this.sendActionToCanvas("setDirty", [fg, bg]);
};
/**
* Destroys a link
* @method removeLink
* @param {Number} link_id
*/
LGraph.prototype.removeLink = function(link_id) {
var link = this.links[link_id];
if (!link) {
return;
}
var node = this.getNodeById(link.target_id);
if (node) {
node.disconnectInput(link.target_slot);
}
};
//save and recover app state ***************************************
/**
* Creates a Object containing all the info about this graph, it can be serialized
* @method serialize
* @return {Object} value of the node
*/
LGraph.prototype.serialize = function() {
var nodes_info = [];
for (var i = 0, l = this._nodes.length; i < l; ++i) {
nodes_info.push(this._nodes[i].serialize());
}
//pack link info into a non-verbose format
var links = [];
for (var i in this.links) {
//links is an OBJECT
var link = this.links[i];
if (!link.serialize) {
//weird bug I havent solved yet
console.warn(
"weird LLink bug, link info is not a LLink but a regular object"
);
var link2 = new LLink();
for (var j in link) {
link2[j] = link[j];
}
this.links[i] = link2;
link = link2;
}
links.push(link.serialize());
}
var groups_info = [];
for (var i = 0; i < this._groups.length; ++i) {
groups_info.push(this._groups[i].serialize());
}
var data = {
last_node_id: this.last_node_id,
last_link_id: this.last_link_id,
nodes: nodes_info,
links: links,
groups: groups_info,
config: this.config,
extra: this.extra,
version: LiteGraph.VERSION
};
if(this.onSerialize)
this.onSerialize(data);
return data;
};
/**
* Configure a graph from a JSON string
* @method configure
* @param {String} str configure a graph from a JSON string
* @param {Boolean} returns if there was any error parsing
*/
LGraph.prototype.configure = function(data, keep_old) {
if (!data) {
return;
}
if (!keep_old) {
this.clear();
}
var nodes = data.nodes;
//decode links info (they are very verbose)
if (data.links && data.links.constructor === Array) {
var links = [];
for (var i = 0; i < data.links.length; ++i) {
var link_data = data.links[i];
if(!link_data) //weird bug
{
console.warn("serialized graph link data contains errors, skipping.");
continue;
}
var link = new LLink();
link.configure(link_data);
links[link.id] = link;
}
data.links = links;
}
//copy all stored fields
for (var i in data) {
if(i == "nodes" || i == "groups" ) //links must be accepted
continue;
this[i] = data[i];
}
var error = false;
//create nodes
this._nodes = [];
if (nodes) {
for (var i = 0, l = nodes.length; i < l; ++i) {
var n_info = nodes[i]; //stored info
var node = LiteGraph.createNode(n_info.type, n_info.title);
if (!node) {
if (LiteGraph.debug) {
console.log(
"Node not found or has errors: " + n_info.type
);
}
//in case of error we create a replacement node to avoid losing info
node = new LGraphNode();
node.last_serialization = n_info;
node.has_errors = true;
error = true;
//continue;
}
node.id = n_info.id; //id it or it will create a new id
this.add(node, true); //add before configure, otherwise configure cannot create links
}
//configure nodes afterwards so they can reach each other
for (var i = 0, l = nodes.length; i < l; ++i) {
var n_info = nodes[i];
var node = this.getNodeById(n_info.id);
if (node) {
node.configure(n_info);
}
}
}
//groups
this._groups.length = 0;
if (data.groups) {
for (var i = 0; i < data.groups.length; ++i) {
var group = new LiteGraph.LGraphGroup();
group.configure(data.groups[i]);
this.add(group);
}
}
this.updateExecutionOrder();
this.extra = data.extra || {};
if(this.onConfigure)
this.onConfigure(data);
this._version++;
this.setDirtyCanvas(true, true);
return error;
};
LGraph.prototype.load = function(url, callback) {
var that = this;
//from file
if(url.constructor === File || url.constructor === Blob)
{
var reader = new FileReader();
reader.addEventListener('load', function(event) {
var data = JSON.parse(event.target.result);
that.configure(data);
if(callback)
callback();
});
reader.readAsText(url);
return;
}
//is a string, then an URL
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.send(null);
req.onload = function(oEvent) {
if (req.status !== 200) {
console.error("Error loading graph:", req.status, req.response);
return;
}
var data = JSON.parse( req.response );
that.configure(data);
if(callback)
callback();
};
req.onerror = function(err) {
console.error("Error loading graph:", err);
};
};
LGraph.prototype.onNodeTrace = function(node, msg, color) {
//TODO
};
//this is the class in charge of storing link information
function LLink(id, type, origin_id, origin_slot, target_id, target_slot) {
this.id = id;
this.type = type;
this.origin_id = origin_id;
this.origin_slot = origin_slot;
this.target_id = target_id;
this.target_slot = target_slot;
this._data = null;
this._pos = new Float32Array(2); //center
}
LLink.prototype.configure = function(o) {
if (o.constructor === Array) {
this.id = o[0];
this.origin_id = o[1];
this.origin_slot = o[2];
this.target_id = o[3];
this.target_slot = o[4];
this.type = o[5];
} else {
this.id = o.id;
this.type = o.type;
this.origin_id = o.origin_id;
this.origin_slot = o.origin_slot;
this.target_id = o.target_id;
this.target_slot = o.target_slot;
}
};
LLink.prototype.serialize = function() {
return [
this.id,
this.origin_id,
this.origin_slot,
this.target_id,
this.target_slot,
this.type
];
};
LiteGraph.LLink = LLink;
// *************************************************************
// Node CLASS *******
// *************************************************************
/*
title: string
pos: [x,y]
size: [x,y]
input|output: every connection
+ { name:string, type:string, pos: [x,y]=Optional, direction: "input"|"output", links: Array });
general properties:
+ clip_area: if you render outside the node, it will be clipped
+ unsafe_execution: not allowed for safe execution
+ skip_repeated_outputs: when adding new outputs, it wont show if there is one already connected
+ resizable: if set to false it wont be resizable with the mouse
+ horizontal: slots are distributed horizontally
+ widgets_start_y: widgets start at y distance from the top of the node
flags object:
+ collapsed: if it is collapsed
supported callbacks:
+ onAdded: when added to graph (warning: this is called BEFORE the node is configured when loading)
+ onRemoved: when removed from graph
+ onStart: when the graph starts playing
+ onStop: when the graph stops playing
+ onDrawForeground: render the inside widgets inside the node
+ onDrawBackground: render the background area inside the node (only in edit mode)
+ onMouseDown
+ onMouseMove
+ onMouseUp
+ onMouseEnter
+ onMouseLeave
+ onExecute: execute the node
+ onPropertyChanged: when a property is changed in the panel (return true to skip default behaviour)
+ onGetInputs: returns an array of possible inputs
+ onGetOutputs: returns an array of possible outputs
+ onBounding: in case this node has a bigger bounding than the node itself (the callback receives the bounding as [x,y,w,h])
+ onDblClick: double clicked in the node
+ onInputDblClick: input slot double clicked (can be used to automatically create a node connected)
+ onOutputDblClick: output slot double clicked (can be used to automatically create a node connected)
+ onConfigure: called after the node has been configured
+ onSerialize: to add extra info when serializing (the callback receives the object that should be filled with the data)
+ onSelected
+ onDeselected
+ onDropItem : DOM item dropped over the node
+ onDropFile : file dropped over the node
+ onConnectInput : if returns false the incoming connection will be canceled
+ onConnectionsChange : a connection changed (new one or removed) (LiteGraph.INPUT or LiteGraph.OUTPUT, slot, true if connected, link_info, input_info )
+ onAction: action slot triggered
+ getExtraMenuOptions: to add option to context menu
*/
/**
* Base Class for all the node type classes
* @class LGraphNode
* @param {String} name a name for the node
*/
function LGraphNode(title) {
this._ctor(title);
}
global.LGraphNode = LiteGraph.LGraphNode = LGraphNode;
LGraphNode.prototype._ctor = function(title) {
this.title = title || "Unnamed";
this.size = [LiteGraph.NODE_WIDTH, 60];
this.graph = null;
this._pos = new Float32Array(10, 10);
Object.defineProperty(this, "pos", {
set: function(v) {
if (!v || v.length < 2) {
return;
}
this._pos[0] = v[0];
this._pos[1] = v[1];
},
get: function() {
return this._pos;
},
enumerable: true
});
if (LiteGraph.use_uuids) {
this.id = LiteGraph.uuidv4();
}
else {
this.id = -1; //not know till not added
}
this.type = null;
//inputs available: array of inputs
this.inputs = [];
this.outputs = [];
this.connections = [];
//local data
this.properties = {}; //for the values
this.properties_info = []; //for the info
this.flags = {};
};
/**
* configure a node from an object containing the serialized info
* @method configure
*/
LGraphNode.prototype.configure = function(info) {
if (this.graph) {
this.graph._version++;
}
for (var j in info) {
if (j == "properties") {
//i don't want to clone properties, I want to reuse the old container
for (var k in info.properties) {
this.properties[k] = info.properties[k];
if (this.onPropertyChanged) {
this.onPropertyChanged( k, info.properties[k] );
}
}
continue;
}
if (info[j] == null) {
continue;
} else if (typeof info[j] == "object") {
//object
if (this[j] && this[j].configure) {
this[j].configure(info[j]);
} else {
this[j] = LiteGraph.cloneObject(info[j], this[j]);
}
} //value
else {
this[j] = info[j];
}
}
if (!info.title) {
this.title = this.constructor.title;
}
if (this.inputs) {
for (var i = 0; i < this.inputs.length; ++i) {
var input = this.inputs[i];
var link_info = this.graph ? this.graph.links[input.link] : null;
if (this.onConnectionsChange)
this.onConnectionsChange( LiteGraph.INPUT, i, true, link_info, input ); //link_info has been created now, so its updated
if( this.onInputAdded )
this.onInputAdded(input);
}
}
if (this.outputs) {
for (var i = 0; i < this.outputs.length; ++i) {
var output = this.outputs[i];
if (!output.links) {
continue;
}
for (var j = 0; j < output.links.length; ++j) {
var link_info = this.graph ? this.graph.links[output.links[j]] : null;
if (this.onConnectionsChange)
this.onConnectionsChange( LiteGraph.OUTPUT, i, true, link_info, output ); //link_info has been created now, so its updated
}
if( this.onOutputAdded )
this.onOutputAdded(output);
}
}
if( this.widgets )
{
for (var i = 0; i < this.widgets.length; ++i)
{
var w = this.widgets[i];
if(!w)
continue;
if(w.options && w.options.property && (this.properties[ w.options.property ] != undefined))
w.value = JSON.parse( JSON.stringify( this.properties[ w.options.property ] ) );
}
if (info.widgets_values) {
for (var i = 0; i < info.widgets_values.length; ++i) {
if (this.widgets[i]) {
this.widgets[i].value = info.widgets_values[i];
}
}
}
}
if (this.onConfigure) {
this.onConfigure(info);
}
};
/**
* serialize the content
* @method serialize
*/
LGraphNode.prototype.serialize = function() {
//create serialization object
var o = {
id: this.id,
type: this.type,
pos: this.pos,
size: this.size,
flags: LiteGraph.cloneObject(this.flags),
order: this.order,
mode: this.mode
};
//special case for when there were errors
if (this.constructor === LGraphNode && this.last_serialization) {
return this.last_serialization;
}
if (this.inputs) {
o.inputs = this.inputs;
}
if (this.outputs) {
//clear outputs last data (because data in connections is never serialized but stored inside the outputs info)
for (var i = 0; i < this.outputs.length; i++) {
delete this.outputs[i]._data;
}
o.outputs = this.outputs;
}
if (this.title && this.title != this.constructor.title) {
o.title = this.title;
}
if (this.properties) {
o.properties = LiteGraph.cloneObject(this.properties);
}
if (this.widgets && this.serialize_widgets) {
o.widgets_values = [];
for (var i = 0; i < this.widgets.length; ++i) {
if(this.widgets[i])
o.widgets_values[i] = this.widgets[i].value;
else
o.widgets_values[i] = null;
}
}
if (!o.type) {
o.type = this.constructor.type;
}
if (this.color) {
o.color = this.color;
}
if (this.bgcolor) {
o.bgcolor = this.bgcolor;
}
if (this.boxcolor) {
o.boxcolor = this.boxcolor;
}
if (this.shape) {
o.shape = this.shape;
}
if (this.onSerialize) {
if (this.onSerialize(o)) {
console.warn(
"node onSerialize shouldnt return anything, data should be stored in the object pass in the first parameter"
);
}
}
return o;
};
/* Creates a clone of this node */
LGraphNode.prototype.clone = function() {
var node = LiteGraph.createNode(this.type);
if (!node) {
return null;
}
//we clone it because serialize returns shared containers
var data = LiteGraph.cloneObject(this.serialize());
//remove links
if (data.inputs) {
for (var i = 0; i < data.inputs.length; ++i) {
data.inputs[i].link = null;
}
}
if (data.outputs) {
for (var i = 0; i < data.outputs.length; ++i) {
if (data.outputs[i].links) {
data.outputs[i].links.length = 0;
}
}
}
delete data["id"];
if (LiteGraph.use_uuids) {
data["id"] = LiteGraph.uuidv4()
}
//remove links
node.configure(data);
return node;
};
/**
* serialize and stringify
* @method toString
*/
LGraphNode.prototype.toString = function() {
return JSON.stringify(this.serialize());
};
//LGraphNode.prototype.deserialize = function(info) {} //this cannot be done from within, must be done in LiteGraph
/**
* get the title string
* @method getTitle
*/
LGraphNode.prototype.getTitle = function() {
return this.title || this.constructor.title;
};
/**
* sets the value of a property
* @method setProperty
* @param {String} name
* @param {*} value
*/
LGraphNode.prototype.setProperty = function(name, value) {
if (!this.properties) {
this.properties = {};
}
if( value === this.properties[name] )
return;
var prev_value = this.properties[name];
this.properties[name] = value;
if (this.onPropertyChanged) {
if( this.onPropertyChanged(name, value, prev_value) === false ) //abort change
this.properties[name] = prev_value;
}
if(this.widgets) //widgets could be linked to properties
for(var i = 0; i < this.widgets.length; ++i)
{
var w = this.widgets[i];
if(!w)
continue;
if(w.options.property == name)
{
w.value = value;
break;
}
}
};
// Execution *************************
/**
* sets the output data
* @method setOutputData
* @param {number} slot
* @param {*} data
*/
LGraphNode.prototype.setOutputData = function(slot, data) {
if (!this.outputs) {
return;
}
//this maybe slow and a niche case
//if(slot && slot.constructor === String)
// slot = this.findOutputSlot(slot);
if (slot == -1 || slot >= this.outputs.length) {
return;
}
var output_info = this.outputs[slot];
if (!output_info) {
return;
}
//store data in the output itself in case we want to debug
output_info._data = data;
//if there are connections, pass the data to the connections
if (this.outputs[slot].links) {
for (var i = 0; i < this.outputs[slot].links.length; i++) {
var link_id = this.outputs[slot].links[i];
var link = this.graph.links[link_id];
if(link)
link.data = data;
}
}
};
/**
* sets the output data type, useful when you want to be able to overwrite the data type
* @method setOutputDataType
* @param {number} slot
* @param {String} datatype
*/
LGraphNode.prototype.setOutputDataType = function(slot, type) {
if (!this.outputs) {
return;
}
if (slot == -1 || slot >= this.outputs.length) {
return;
}
var output_info = this.outputs[slot];
if (!output_info) {
return;
}
//store data in the output itself in case we want to debug
output_info.type = type;
//if there are connections, pass the data to the connections
if (this.outputs[slot].links) {
for (var i = 0; i < this.outputs[slot].links.length; i++) {
var link_id = this.outputs[slot].links[i];
this.graph.links[link_id].type = type;
}
}
};
/**
* Retrieves the input data (data traveling through the connection) from one slot
* @method getInputData
* @param {number} slot
* @param {boolean} force_update if set to true it will force the connected node of this slot to output data into this link
* @return {*} data or if it is not connected returns undefined
*/
LGraphNode.prototype.getInputData = function(slot, force_update) {
if (!this.inputs) {
return;
} //undefined;
if (slot >= this.inputs.length || this.inputs[slot].link == null) {
return;
}
var link_id = this.inputs[slot].link;
var link = this.graph.links[link_id];
if (!link) {
//bug: weird case but it happens sometimes
return null;
}
if (!force_update) {
return link.data;
}
//special case: used to extract data from the incoming connection before the graph has been executed
var node = this.graph.getNodeById(link.origin_id);
if (!node) {
return link.data;
}
if (node.updateOutputData) {
node.updateOutputData(link.origin_slot);
} else if (node.onExecute) {
node.onExecute();
}
return link.data;
};
/**
* Retrieves the input data type (in case this supports multiple input types)
* @method getInputDataType
* @param {number} slot
* @return {String} datatype in string format
*/
LGraphNode.prototype.getInputDataType = function(slot) {
if (!this.inputs) {
return null;
} //undefined;
if (slot >= this.inputs.length || this.inputs[slot].link == null) {
return null;
}
var link_id = this.inputs[slot].link;
var link = this.graph.links[link_id];
if (!link) {
//bug: weird case but it happens sometimes
return null;
}
var node = this.graph.getNodeById(link.origin_id);
if (!node) {
return link.type;
}
var output_info = node.outputs[link.origin_slot];
if (output_info) {
return output_info.type;
}
return null;
};
/**
* Retrieves the input data from one slot using its name instead of slot number
* @method getInputDataByName
* @param {String} slot_name
* @param {boolean} force_update if set to true it will force the connected node of this slot to output data into this link
* @return {*} data or if it is not connected returns null
*/
LGraphNode.prototype.getInputDataByName = function(
slot_name,
force_update
) {
var slot = this.findInputSlot(slot_name);
if (slot == -1) {
return null;
}
return this.getInputData(slot, force_update);
};
/**
* tells you if there is a connection in one input slot
* @method isInputConnected
* @param {number} slot
* @return {boolean}
*/
LGraphNode.prototype.isInputConnected = function(slot) {
if (!this.inputs) {
return false;
}
return slot < this.inputs.length && this.inputs[slot].link != null;
};
/**
* tells you info about an input connection (which node, type, etc)
* @method getInputInfo
* @param {number} slot
* @return {Object} object or null { link: id, name: string, type: string or 0 }
*/
LGraphNode.prototype.getInputInfo = function(slot) {
if (!this.inputs) {
return null;
}
if (slot < this.inputs.length) {
return this.inputs[slot];
}
return null;
};
/**
* Returns the link info in the connection of an input slot
* @method getInputLink
* @param {number} slot
* @return {LLink} object or null
*/
LGraphNode.prototype.getInputLink = function(slot) {
if (!this.inputs) {
return null;
}
if (slot < this.inputs.length) {
var slot_info = this.inputs[slot];
return this.graph.links[ slot_info.link ];
}
return null;
};
/**
* returns the node connected in the input slot
* @method getInputNode
* @param {number} slot
* @return {LGraphNode} node or null
*/
LGraphNode.prototype.getInputNode = function(slot) {
if (!this.inputs) {
return null;
}
if (slot >= this.inputs.length) {
return null;
}
var input = this.inputs[slot];
if (!input || input.link === null) {
return null;
}
var link_info = this.graph.links[input.link];
if (!link_info) {
return null;
}
return this.graph.getNodeById(link_info.origin_id);
};
/**
* returns the value of an input with this name, otherwise checks if there is a property with that name
* @method getInputOrProperty
* @param {string} name
* @return {*} value
*/
LGraphNode.prototype.getInputOrProperty = function(name) {
if (!this.inputs || !this.inputs.length) {
return this.properties ? this.properties[name] : null;
}
for (var i = 0, l = this.inputs.length; i < l; ++i) {
var input_info = this.inputs[i];
if (name == input_info.name && input_info.link != null) {
var link = this.graph.links[input_info.link];
if (link) {
return link.data;
}
}
}
return this.properties[name];
};
/**
* tells you the last output data that went in that slot
* @method getOutputData
* @param {number} slot
* @return {Object} object or null
*/
LGraphNode.prototype.getOutputData = function(slot) {
if (!this.outputs) {
return null;
}
if (slot >= this.outputs.length) {
return null;
}
var info = this.outputs[slot];
return info._data;
};
/**
* tells you info about an output connection (which node, type, etc)
* @method getOutputInfo
* @param {number} slot
* @return {Object} object or null { name: string, type: string, links: [ ids of links in number ] }
*/
LGraphNode.prototype.getOutputInfo = function(slot) {
if (!this.outputs) {
return null;
}
if (slot < this.outputs.length) {
return this.outputs[slot];
}
return null;
};
/**
* tells you if there is a connection in one output slot
* @method isOutputConnected
* @param {number} slot
* @return {boolean}
*/
LGraphNode.prototype.isOutputConnected = function(slot) {
if (!this.outputs) {
return false;
}
return (
slot < this.outputs.length &&
this.outputs[slot].links &&
this.outputs[slot].links.length
);
};
/**
* tells you if there is any connection in the output slots
* @method isAnyOutputConnected
* @return {boolean}
*/
LGraphNode.prototype.isAnyOutputConnected = function() {
if (!this.outputs) {
return false;
}
for (var i = 0; i < this.outputs.length; ++i) {
if (this.outputs[i].links && this.outputs[i].links.length) {
return true;
}
}
return false;
};
/**
* retrieves all the nodes connected to this output slot
* @method getOutputNodes
* @param {number} slot
* @return {array}
*/
LGraphNode.prototype.getOutputNodes = function(slot) {
if (!this.outputs || this.outputs.length == 0) {
return null;
}
if (slot >= this.outputs.length) {
return null;
}
var output = this.outputs[slot];
if (!output.links || output.links.length == 0) {
return null;
}
var r = [];
for (var i = 0; i < output.links.length; i++) {
var link_id = output.links[i];
var link = this.graph.links[link_id];
if (link) {
var target_node = this.graph.getNodeById(link.target_id);
if (target_node) {
r.push(target_node);
}
}
}
return r;
};
LGraphNode.prototype.addOnTriggerInput = function(){
var trigS = this.findInputSlot("onTrigger");
if (trigS == -1){ //!trigS ||
var input = this.addInput("onTrigger", LiteGraph.EVENT, {optional: true, nameLocked: true});
return this.findInputSlot("onTrigger");
}
return trigS;
}
LGraphNode.prototype.addOnExecutedOutput = function(){
var trigS = this.findOutputSlot("onExecuted");
if (trigS == -1){ //!trigS ||
var output = this.addOutput("onExecuted", LiteGraph.ACTION, {optional: true, nameLocked: true});
return this.findOutputSlot("onExecuted");
}
return trigS;
}
LGraphNode.prototype.onAfterExecuteNode = function(param, options){
var trigS = this.findOutputSlot("onExecuted");
if (trigS != -1){
//console.debug(this.id+":"+this.order+" triggering slot onAfterExecute");
//console.debug(param);
//console.debug(options);
this.triggerSlot(trigS, param, null, options);
}
}
LGraphNode.prototype.changeMode = function(modeTo){
switch(modeTo){
case LiteGraph.ON_EVENT:
// this.addOnExecutedOutput();
break;
case LiteGraph.ON_TRIGGER:
this.addOnTriggerInput();
this.addOnExecutedOutput();
break;
case LiteGraph.NEVER:
break;
case LiteGraph.ALWAYS:
break;
case LiteGraph.ON_REQUEST:
break;
default:
return false;
break;
}
this.mode = modeTo;
return true;
};
/**
* Triggers the execution of actions that were deferred when the action was triggered
* @method executePendingActions
*/
LGraphNode.prototype.executePendingActions = function() {
if(!this._waiting_actions || !this._waiting_actions.length)
return;
for(var i = 0; i < this._waiting_actions.length;++i)
{
var p = this._waiting_actions[i];
this.onAction(p[0],p[1],p[2],p[3],p[4]);
}
this._waiting_actions.length = 0;
}
/**
* Triggers the node code execution, place a boolean/counter to mark the node as being executed
* @method doExecute
* @param {*} param
* @param {*} options
*/
LGraphNode.prototype.doExecute = function(param, options) {
options = options || {};
if (this.onExecute){
// enable this to give the event an ID
if (!options.action_call) options.action_call = this.id+"_exec_"+Math.floor(Math.random()*9999);
this.graph.nodes_executing[this.id] = true; //.push(this.id);
this.onExecute(param, options);
this.graph.nodes_executing[this.id] = false; //.pop();
// save execution/action ref
this.exec_version = this.graph.iteration;
if(options && options.action_call){
this.action_call = options.action_call; // if (param)
this.graph.nodes_executedAction[this.id] = options.action_call;
}
}
else {
}
this.execute_triggered = 2; // the nFrames it will be used (-- each step), means "how old" is the event
if(this.onAfterExecuteNode) this.onAfterExecuteNode(param, options); // callback
};
/**
* Triggers an action, wrapped by logics to control execution flow
* @method actionDo
* @param {String} action name
* @param {*} param
*/
LGraphNode.prototype.actionDo = function(action, param, options, action_slot ) {
options = options || {};
if (this.onAction){
// enable this to give the event an ID
if (!options.action_call) options.action_call = this.id+"_"+(action?action:"action")+"_"+Math.floor(Math.random()*9999);
this.graph.nodes_actioning[this.id] = (action?action:"actioning"); //.push(this.id);
this.onAction(action, param, options, action_slot);
this.graph.nodes_actioning[this.id] = false; //.pop();
// save execution/action ref
if(options && options.action_call){
this.action_call = options.action_call; // if (param)
this.graph.nodes_executedAction[this.id] = options.action_call;
}
}
this.action_triggered = 2; // the nFrames it will be used (-- each step), means "how old" is the event
if(this.onAfterExecuteNode) this.onAfterExecuteNode(param, options);
};
/**
* Triggers an event in this node, this will trigger any output with the same name
* @method trigger
* @param {String} event name ( "on_play", ... ) if action is equivalent to false then the event is send to all
* @param {*} param
*/
LGraphNode.prototype.trigger = function(action, param, options) {
if (!this.outputs || !this.outputs.length) {
return;
}
if (this.graph)
this.graph._last_trigger_time = LiteGraph.getTime();
for (var i = 0; i < this.outputs.length; ++i) {
var output = this.outputs[i];
if ( !output || output.type !== LiteGraph.EVENT || (action && output.name != action) )
continue;
this.triggerSlot(i, param, null, options);
}
};
/**
* Triggers a slot event in this node: cycle output slots and launch execute/action on connected nodes
* @method triggerSlot
* @param {Number} slot the index of the output slot
* @param {*} param
* @param {Number} link_id [optional] in case you want to trigger and specific output link in a slot
*/
LGraphNode.prototype.triggerSlot = function(slot, param, link_id, options) {
options = options || {};
if (!this.outputs) {
return;
}
if(slot == null)
{
console.error("slot must be a number");
return;
}
if(slot.constructor !== Number)
console.warn("slot must be a number, use node.trigger('name') if you want to use a string");
var output = this.outputs[slot];
if (!output) {
return;
}
var links = output.links;
if (!links || !links.length) {
return;
}
if (this.graph) {
this.graph._last_trigger_time = LiteGraph.getTime();
}
//for every link attached here
for (var k = 0; k < links.length; ++k) {
var id = links[k];
if (link_id != null && link_id != id) {
//to skip links
continue;
}
var link_info = this.graph.links[links[k]];
if (!link_info) {
//not connected
continue;
}
link_info._last_time = LiteGraph.getTime();
var node = this.graph.getNodeById(link_info.target_id);
if (!node) {
//node not found?
continue;
}
//used to mark events in graph
var target_connection = node.inputs[link_info.target_slot];
if (node.mode === LiteGraph.ON_TRIGGER)
{
// generate unique trigger ID if not present
if (!options.action_call) options.action_call = this.id+"_trigg_"+Math.floor(Math.random()*9999);
if (node.onExecute) {
// -- wrapping node.onExecute(param); --
node.doExecute(param, options);
}
}
else if (node.onAction) {
// generate unique action ID if not present
if (!options.action_call) options.action_call = this.id+"_act_"+Math.floor(Math.random()*9999);
//pass the action name
var target_connection = node.inputs[link_info.target_slot];
//instead of executing them now, it will be executed in the next graph loop, to ensure data flow
if(LiteGraph.use_deferred_actions && node.onExecute)
{
if(!node._waiting_actions)
node._waiting_actions = [];
node._waiting_actions.push([target_connection.name, param, options, link_info.target_slot]);
}
else
{
// wrap node.onAction(target_connection.name, param);
node.actionDo( target_connection.name, param, options, link_info.target_slot );
}
}
}
};
/**
* clears the trigger slot animation
* @method clearTriggeredSlot
* @param {Number} slot the index of the output slot
* @param {Number} link_id [optional] in case you want to trigger and specific output link in a slot
*/
LGraphNode.prototype.clearTriggeredSlot = function(slot, link_id) {
if (!this.outputs) {
return;
}
var output = this.outputs[slot];
if (!output) {
return;
}
var links = output.links;
if (!links || !links.length) {
return;
}
//for every link attached here
for (var k = 0; k < links.length; ++k) {
var id = links[k];
if (link_id != null && link_id != id) {
//to skip links
continue;
}
var link_info = this.graph.links[links[k]];
if (!link_info) {
//not connected
continue;
}
link_info._last_time = 0;
}
};
/**
* changes node size and triggers callback
* @method setSize
* @param {vec2} size
*/
LGraphNode.prototype.setSize = function(size)
{
this.size = size;
if(this.onResize)
this.onResize(this.size);
}
/**
* add a new property to this node
* @method addProperty
* @param {string} name
* @param {*} default_value
* @param {string} type string defining the output type ("vec3","number",...)
* @param {Object} extra_info this can be used to have special properties of the property (like values, etc)
*/
LGraphNode.prototype.addProperty = function(
name,
default_value,
type,
extra_info
) {
var o = { name: name, type: type, default_value: default_value };
if (extra_info) {
for (var i in extra_info) {
o[i] = extra_info[i];
}
}
if (!this.properties_info) {
this.properties_info = [];
}
this.properties_info.push(o);
if (!this.properties) {
this.properties = {};
}
this.properties[name] = default_value;
return o;
};
//connections
/**
* add a new output slot to use in this node
* @method addOutput
* @param {string} name
* @param {string} type string defining the output type ("vec3","number",...)
* @param {Object} extra_info this can be used to have special properties of an output (label, special color, position, etc)
*/
LGraphNode.prototype.addOutput = function(name, type, extra_info) {
var output = { name: name, type: type, links: null };
if (extra_info) {
for (var i in extra_info) {
output[i] = extra_info[i];
}
}
if (!this.outputs) {
this.outputs = [];
}
this.outputs.push(output);
if (this.onOutputAdded) {
this.onOutputAdded(output);
}
if (LiteGraph.auto_load_slot_types) LiteGraph.registerNodeAndSlotType(this,type,true);
this.setSize( this.computeSize() );
this.setDirtyCanvas(true, true);
return output;
};
/**
* add a new output slot to use in this node
* @method addOutputs
* @param {Array} array of triplets like [[name,type,extra_info],[...]]
*/
LGraphNode.prototype.addOutputs = function(array) {
for (var i = 0; i < array.length; ++i) {
var info = array[i];
var o = { name: info[0], type: info[1], link: null };
if (array[2]) {
for (var j in info[2]) {
o[j] = info[2][j];
}
}
if (!this.outputs) {
this.outputs = [];
}
this.outputs.push(o);
if (this.onOutputAdded) {
this.onOutputAdded(o);
}
if (LiteGraph.auto_load_slot_types) LiteGraph.registerNodeAndSlotType(this,info[1],true);
}
this.setSize( this.computeSize() );
this.setDirtyCanvas(true, true);
};
/**
* remove an existing output slot
* @method removeOutput
* @param {number} slot
*/
LGraphNode.prototype.removeOutput = function(slot) {
this.disconnectOutput(slot);
this.outputs.splice(slot, 1);
for (var i = slot; i < this.outputs.length; ++i) {
if (!this.outputs[i] || !this.outputs[i].links) {
continue;
}
var links = this.outputs[i].links;
for (var j = 0; j < links.length; ++j) {
var link = this.graph.links[links[j]];
if (!link) {
continue;
}
link.origin_slot -= 1;
}
}
this.setSize( this.computeSize() );
if (this.onOutputRemoved) {
this.onOutputRemoved(slot);
}
this.setDirtyCanvas(true, true);
};
/**
* add a new input slot to use in this node
* @method addInput
* @param {string} name
* @param {string} type string defining the input type ("vec3","number",...), it its a generic one use 0
* @param {Object} extra_info this can be used to have special properties of an input (label, color, position, etc)
*/
LGraphNode.prototype.addInput = function(name, type, extra_info) {
type = type || 0;
var input = { name: name, type: type, link: null };
if (extra_info) {
for (var i in extra_info) {
input[i] = extra_info[i];
}
}
if (!this.inputs) {
this.inputs = [];
}
this.inputs.push(input);
this.setSize( this.computeSize() );
if (this.onInputAdded) {
this.onInputAdded(input);
}
LiteGraph.registerNodeAndSlotType(this,type);
this.setDirtyCanvas(true, true);
return input;
};
/**
* add several new input slots in this node
* @method addInputs
* @param {Array} array of triplets like [[name,type,extra_info],[...]]
*/
LGraphNode.prototype.addInputs = function(array) {
for (var i = 0; i < array.length; ++i) {
var info = array[i];
var o = { name: info[0], type: info[1], link: null };
if (array[2]) {
for (var j in info[2]) {
o[j] = info[2][j];
}
}
if (!this.inputs) {
this.inputs = [];
}
this.inputs.push(o);
if (this.onInputAdded) {
this.onInputAdded(o);
}
LiteGraph.registerNodeAndSlotType(this,info[1]);
}
this.setSize( this.computeSize() );
this.setDirtyCanvas(true, true);
};
/**
* remove an existing input slot
* @method removeInput
* @param {number} slot
*/
LGraphNode.prototype.removeInput = function(slot) {
this.disconnectInput(slot);
var slot_info = this.inputs.splice(slot, 1);
for (var i = slot; i < this.inputs.length; ++i) {
if (!this.inputs[i]) {
continue;
}
var link = this.graph.links[this.inputs[i].link];
if (!link) {
continue;
}
link.target_slot -= 1;
}
this.setSize( this.computeSize() );
if (this.onInputRemoved) {
this.onInputRemoved(slot, slot_info[0] );
}
this.setDirtyCanvas(true, true);
};
/**
* add an special connection to this node (used for special kinds of graphs)
* @method addConnection
* @param {string} name
* @param {string} type string defining the input type ("vec3","number",...)
* @param {[x,y]} pos position of the connection inside the node
* @param {string} direction if is input or output
*/
LGraphNode.prototype.addConnection = function(name, type, pos, direction) {
var o = {
name: name,
type: type,
pos: pos,
direction: direction,
links: null
};
this.connections.push(o);
return o;
};
/**
* computes the minimum size of a node according to its inputs and output slots
* @method computeSize
* @param {vec2} minHeight
* @return {vec2} the total size
*/
LGraphNode.prototype.computeSize = function(out) {
if (this.constructor.size) {
return this.constructor.size.concat();
}
var rows = Math.max(
this.inputs ? this.inputs.length : 1,
this.outputs ? this.outputs.length : 1
);
var size = out || new Float32Array([0, 0]);
rows = Math.max(rows, 1);
var font_size = LiteGraph.NODE_TEXT_SIZE; //although it should be graphcanvas.inner_text_font size
var title_width = compute_text_size(this.title);
var input_width = 0;
var output_width = 0;
if (this.inputs) {
for (var i = 0, l = this.inputs.length; i < l; ++i) {
var input = this.inputs[i];
var text = input.label || input.name || "";
var text_width = compute_text_size(text);
if (input_width < text_width) {
input_width = text_width;
}
}
}
if (this.outputs) {
for (var i = 0, l = this.outputs.length; i < l; ++i) {
var output = this.outputs[i];
var text = output.label || output.name || "";
var text_width = compute_text_size(text);
if (output_width < text_width) {
output_width = text_width;
}
}
}
size[0] = Math.max(input_width + output_width + 10, title_width);
size[0] = Math.max(size[0], LiteGraph.NODE_WIDTH);
if (this.widgets && this.widgets.length) {
size[0] = Math.max(size[0], LiteGraph.NODE_WIDTH * 1.5);
}
size[1] = (this.constructor.slot_start_y || 0) + rows * LiteGraph.NODE_SLOT_HEIGHT;
var widgets_height = 0;
if (this.widgets && this.widgets.length) {
for (var i = 0, l = this.widgets.length; i < l; ++i) {
if (this.widgets[i].computeSize)
widgets_height += this.widgets[i].computeSize(size[0])[1] + 4;
else
widgets_height += LiteGraph.NODE_WIDGET_HEIGHT + 4;
}
widgets_height += 8;
}
//compute height using widgets height
if( this.widgets_up )
size[1] = Math.max( size[1], widgets_height );
else if( this.widgets_start_y != null )
size[1] = Math.max( size[1], widgets_height + this.widgets_start_y );
else
size[1] += widgets_height;
function compute_text_size(text) {
if (!text) {
return 0;
}
return font_size * text.length * 0.6;
}
if (
this.constructor.min_height &&
size[1] < this.constructor.min_height
) {
size[1] = this.constructor.min_height;
}
size[1] += 6; //margin
return size;
};
/**
* returns all the info available about a property of this node.
*
* @method getPropertyInfo
* @param {String} property name of the property
* @return {Object} the object with all the available info
*/
LGraphNode.prototype.getPropertyInfo = function( property )
{
var info = null;
//there are several ways to define info about a property
//legacy mode
if (this.properties_info) {
for (var i = 0; i < this.properties_info.length; ++i) {
if (this.properties_info[i].name == property) {
info = this.properties_info[i];
break;
}
}
}
//litescene mode using the constructor
if(this.constructor["@" + property])
info = this.constructor["@" + property];
if(this.constructor.widgets_info && this.constructor.widgets_info[property])
info = this.constructor.widgets_info[property];
//litescene mode using the constructor
if (!info && this.onGetPropertyInfo) {
info = this.onGetPropertyInfo(property);
}
if (!info)
info = {};
if(!info.type)
info.type = typeof this.properties[property];
if(info.widget == "combo")
info.type = "enum";
return info;
}
/**
* Defines a widget inside the node, it will be rendered on top of the node, you can control lots of properties
*
* @method addWidget
* @param {String} type the widget type (could be "number","string","combo"
* @param {String} name the text to show on the widget
* @param {String} value the default value
* @param {Function|String} callback function to call when it changes (optionally, it can be the name of the property to modify)
* @param {Object} options the object that contains special properties of this widget
* @return {Object} the created widget object
*/
LGraphNode.prototype.addWidget = function( type, name, value, callback, options )
{
if (!this.widgets) {
this.widgets = [];
}
if(!options && callback && callback.constructor === Object)
{
options = callback;
callback = null;
}
if(options && options.constructor === String) //options can be the property name
options = { property: options };
if(callback && callback.constructor === String) //callback can be the property name
{
if(!options)
options = {};
options.property = callback;
callback = null;
}
if(callback && callback.constructor !== Function)
{
console.warn("addWidget: callback must be a function");
callback = null;
}
var w = {
type: type.toLowerCase(),
name: name,
value: value,
callback: callback,
options: options || {}
};
if (w.options.y !== undefined) {
w.y = w.options.y;
}
if (!callback && !w.options.callback && !w.options.property) {
console.warn("LiteGraph addWidget(...) without a callback or property assigned");
}
if (type == "combo" && !w.options.values) {
throw "LiteGraph addWidget('combo',...) requires to pass values in options: { values:['red','blue'] }";
}
this.widgets.push(w);
this.setSize( this.computeSize() );
return w;
};
LGraphNode.prototype.addCustomWidget = function(custom_widget) {
if (!this.widgets) {
this.widgets = [];
}
this.widgets.push(custom_widget);
return custom_widget;
};
/**
* returns the bounding of the object, used for rendering purposes
* @method getBounding
* @param out {Float32Array[4]?} [optional] a place to store the output, to free garbage
* @param compute_outer {boolean?} [optional] set to true to include the shadow and connection points in the bounding calculation
* @return {Float32Array[4]} the bounding box in format of [topleft_cornerx, topleft_cornery, width, height]
*/
LGraphNode.prototype.getBounding = function(out, compute_outer) {
out = out || new Float32Array(4);
const nodePos = this.pos;
const isCollapsed = this.flags.collapsed;
const nodeSize = this.size;
let left_offset = 0;
// 1 offset due to how nodes are rendered
let right_offset = 1 ;
let top_offset = 0;
let bottom_offset = 0;
if (compute_outer) {
// 4 offset for collapsed node connection points
left_offset = 4;
// 6 offset for right shadow and collapsed node connection points
right_offset = 6 + left_offset;
// 4 offset for collapsed nodes top connection points
top_offset = 4;
// 5 offset for bottom shadow and collapsed node connection points
bottom_offset = 5 + top_offset;
}
out[0] = nodePos[0] - left_offset;
out[1] = nodePos[1] - LiteGraph.NODE_TITLE_HEIGHT - top_offset;
out[2] = isCollapsed ?
(this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH) + right_offset :
nodeSize[0] + right_offset;
out[3] = isCollapsed ?
LiteGraph.NODE_TITLE_HEIGHT + bottom_offset :
nodeSize[1] + LiteGraph.NODE_TITLE_HEIGHT + bottom_offset;
if (this.onBounding) {
this.onBounding(out);
}
return out;
};
/**
* checks if a point is inside the shape of a node
* @method isPointInside
* @param {number} x
* @param {number} y
* @return {boolean}
*/
LGraphNode.prototype.isPointInside = function(x, y, margin, skip_title) {
margin = margin || 0;
var margin_top = this.graph && this.graph.isLive() ? 0 : LiteGraph.NODE_TITLE_HEIGHT;
if (skip_title) {
margin_top = 0;
}
if (this.flags && this.flags.collapsed) {
//if ( distance([x,y], [this.pos[0] + this.size[0]*0.5, this.pos[1] + this.size[1]*0.5]) < LiteGraph.NODE_COLLAPSED_RADIUS)
if (
isInsideRectangle(
x,
y,
this.pos[0] - margin,
this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT - margin,
(this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH) +
2 * margin,
LiteGraph.NODE_TITLE_HEIGHT + 2 * margin
)
) {
return true;
}
} else if (
this.pos[0] - 4 - margin < x &&
this.pos[0] + this.size[0] + 4 + margin > x &&
this.pos[1] - margin_top - margin < y &&
this.pos[1] + this.size[1] + margin > y
) {
return true;
}
return false;
};
/**
* checks if a point is inside a node slot, and returns info about which slot
* @method getSlotInPosition
* @param {number} x
* @param {number} y
* @return {Object} if found the object contains { input|output: slot object, slot: number, link_pos: [x,y] }
*/
LGraphNode.prototype.getSlotInPosition = function(x, y) {
//search for inputs
var link_pos = new Float32Array(2);
if (this.inputs) {
for (var i = 0, l = this.inputs.length; i < l; ++i) {
var input = this.inputs[i];
this.getConnectionPos(true, i, link_pos);
if (
isInsideRectangle(
x,
y,
link_pos[0] - 10,
link_pos[1] - 5,
20,
10
)
) {
return { input: input, slot: i, link_pos: link_pos };
}
}
}
if (this.outputs) {
for (var i = 0, l = this.outputs.length; i < l; ++i) {
var output = this.outputs[i];
this.getConnectionPos(false, i, link_pos);
if (
isInsideRectangle(
x,
y,
link_pos[0] - 10,
link_pos[1] - 5,
20,
10
)
) {
return { output: output, slot: i, link_pos: link_pos };
}
}
}
return null;
};
/**
* returns the input slot with a given name (used for dynamic slots), -1 if not found
* @method findInputSlot
* @param {string} name the name of the slot
* @param {boolean} returnObj if the obj itself wanted
* @return {number_or_object} the slot (-1 if not found)
*/
LGraphNode.prototype.findInputSlot = function(name, returnObj) {
if (!this.inputs) {
return -1;
}
for (var i = 0, l = this.inputs.length; i < l; ++i) {
if (name == this.inputs[i].name) {
return !returnObj ? i : this.inputs[i];
}
}
return -1;
};
/**
* returns the output slot with a given name (used for dynamic slots), -1 if not found
* @method findOutputSlot
* @param {string} name the name of the slot
* @param {boolean} returnObj if the obj itself wanted
* @return {number_or_object} the slot (-1 if not found)
*/
LGraphNode.prototype.findOutputSlot = function(name, returnObj) {
returnObj = returnObj || false;
if (!this.outputs) {
return -1;
}
for (var i = 0, l = this.outputs.length; i < l; ++i) {
if (name == this.outputs[i].name) {
return !returnObj ? i : this.outputs[i];
}
}
return -1;
};
// TODO refactor: USE SINGLE findInput/findOutput functions! :: merge options
/**
* returns the first free input slot
* @method findInputSlotFree
* @param {object} options
* @return {number_or_object} the slot (-1 if not found)
*/
LGraphNode.prototype.findInputSlotFree = function(optsIn) {
var optsIn = optsIn || {};
var optsDef = {returnObj: false
,typesNotAccepted: []
};
var opts = Object.assign(optsDef,optsIn);
if (!this.inputs) {
return -1;
}
for (var i = 0, l = this.inputs.length; i < l; ++i) {
if (this.inputs[i].link && this.inputs[i].link != null) {
continue;
}
if (opts.typesNotAccepted && opts.typesNotAccepted.includes && opts.typesNotAccepted.includes(this.inputs[i].type)){
continue;
}
return !opts.returnObj ? i : this.inputs[i];
}
return -1;
};
/**
* returns the first output slot free
* @method findOutputSlotFree
* @param {object} options
* @return {number_or_object} the slot (-1 if not found)
*/
LGraphNode.prototype.findOutputSlotFree = function(optsIn) {
var optsIn = optsIn || {};
var optsDef = { returnObj: false
,typesNotAccepted: []
};
var opts = Object.assign(optsDef,optsIn);
if (!this.outputs) {
return -1;
}
for (var i = 0, l = this.outputs.length; i < l; ++i) {
if (this.outputs[i].links && this.outputs[i].links != null) {
continue;
}
if (opts.typesNotAccepted && opts.typesNotAccepted.includes && opts.typesNotAccepted.includes(this.outputs[i].type)){
continue;
}
return !opts.returnObj ? i : this.outputs[i];
}
return -1;
};
/**
* findSlotByType for INPUTS
*/
LGraphNode.prototype.findInputSlotByType = function(type, returnObj, preferFreeSlot, doNotUseOccupied) {
return this.findSlotByType(true, type, returnObj, preferFreeSlot, doNotUseOccupied);
};
/**
* findSlotByType for OUTPUTS
*/
LGraphNode.prototype.findOutputSlotByType = function(type, returnObj, preferFreeSlot, doNotUseOccupied) {
return this.findSlotByType(false, type, returnObj, preferFreeSlot, doNotUseOccupied);
};
/**
* returns the output (or input) slot with a given type, -1 if not found
* @method findSlotByType
* @param {boolean} input uise inputs instead of outputs
* @param {string} type the type of the slot
* @param {boolean} returnObj if the obj itself wanted
* @param {boolean} preferFreeSlot if we want a free slot (if not found, will return the first of the type anyway)
* @return {number_or_object} the slot (-1 if not found)
*/
LGraphNode.prototype.findSlotByType = function(input, type, returnObj, preferFreeSlot, doNotUseOccupied) {
input = input || false;
returnObj = returnObj || false;
preferFreeSlot = preferFreeSlot || false;
doNotUseOccupied = doNotUseOccupied || false;
var aSlots = input ? this.inputs : this.outputs;
if (!aSlots) {
return -1;
}
// !! empty string type is considered 0, * !!
if (type == "" || type == "*") type = 0;
for (var i = 0, l = aSlots.length; i < l; ++i) {
var tFound = false;
var aSource = (type+"").toLowerCase().split(",");
var aDest = aSlots[i].type=="0"||aSlots[i].type=="*"?"0":aSlots[i].type;
aDest = (aDest+"").toLowerCase().split(",");
for(var sI=0;sI<aSource.length;sI++){
for(var dI=0;dI<aDest.length;dI++){
if (aSource[sI]=="_event_") aSource[sI] = LiteGraph.EVENT;
if (aDest[sI]=="_event_") aDest[sI] = LiteGraph.EVENT;
if (aSource[sI]=="*") aSource[sI] = 0;
if (aDest[sI]=="*") aDest[sI] = 0;
if (aSource[sI] == aDest[dI]) {
if (preferFreeSlot && aSlots[i].links && aSlots[i].links !== null) continue;
return !returnObj ? i : aSlots[i];
}
}
}
}
// if didnt find some, stop checking for free slots
if (preferFreeSlot && !doNotUseOccupied){
for (var i = 0, l = aSlots.length; i < l; ++i) {
var tFound = false;
var aSource = (type+"").toLowerCase().split(",");
var aDest = aSlots[i].type=="0"||aSlots[i].type=="*"?"0":aSlots[i].type;
aDest = (aDest+"").toLowerCase().split(",");
for(var sI=0;sI<aSource.length;sI++){
for(var dI=0;dI<aDest.length;dI++){
if (aSource[sI]=="*") aSource[sI] = 0;
if (aDest[sI]=="*") aDest[sI] = 0;
if (aSource[sI] == aDest[dI]) {
return !returnObj ? i : aSlots[i];
}
}
}
}
}
return -1;
};
/**
* connect this node output to the input of another node BY TYPE
* @method connectByType
* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
* @param {LGraphNode} node the target node
* @param {string} target_type the input slot type of the target node
* @return {Object} the link_info is created, otherwise null
*/
LGraphNode.prototype.connectByType = function(slot, target_node, target_slotType, optsIn) {
var optsIn = optsIn || {};
var optsDef = { createEventInCase: true
,firstFreeIfOutputGeneralInCase: true
,generalTypeInCase: true
};
var opts = Object.assign(optsDef,optsIn);
if (target_node && target_node.constructor === Number) {
target_node = this.graph.getNodeById(target_node);
}
var target_slot = target_node.findInputSlotByType(target_slotType, false, true);
if (target_slot >= 0 && target_slot !== null){
//console.debug("CONNbyTYPE type "+target_slotType+" for "+target_slot)
return this.connect(slot, target_node, target_slot);
}else{
//console.log("type "+target_slotType+" not found or not free?")
if (opts.createEventInCase && target_slotType == LiteGraph.EVENT){
// WILL CREATE THE onTrigger IN SLOT
//console.debug("connect WILL CREATE THE onTrigger "+target_slotType+" to "+target_node);
return this.connect(slot, target_node, -1);
}
// connect to the first general output slot if not found a specific type and
if (opts.generalTypeInCase){
var target_slot = target_node.findInputSlotByType(0, false, true, true);
//console.debug("connect TO a general type (*, 0), if not found the specific type ",target_slotType," to ",target_node,"RES_SLOT:",target_slot);
if (target_slot >= 0){
return this.connect(slot, target_node, target_slot);
}
}
// connect to the first free input slot if not found a specific type and this output is general
if (opts.firstFreeIfOutputGeneralInCase && (target_slotType == 0 || target_slotType == "*" || target_slotType == "")){
var target_slot = target_node.findInputSlotFree({typesNotAccepted: [LiteGraph.EVENT] });
//console.debug("connect TO TheFirstFREE ",target_slotType," to ",target_node,"RES_SLOT:",target_slot);
if (target_slot >= 0){
return this.connect(slot, target_node, target_slot);
}
}
console.debug("no way to connect type: ",target_slotType," to targetNODE ",target_node);
//TODO filter
return null;
}
}
/**
* connect this node input to the output of another node BY TYPE
* @method connectByType
* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
* @param {LGraphNode} node the target node
* @param {string} target_type the output slot type of the target node
* @return {Object} the link_info is created, otherwise null
*/
LGraphNode.prototype.connectByTypeOutput = function(slot, source_node, source_slotType, optsIn) {
var optsIn = optsIn || {};
var optsDef = { createEventInCase: true
,firstFreeIfInputGeneralInCase: true
,generalTypeInCase: true
};
var opts = Object.assign(optsDef,optsIn);
if (source_node && source_node.constructor === Number) {
source_node = this.graph.getNodeById(source_node);
}
var source_slot = source_node.findOutputSlotByType(source_slotType, false, true);
if (source_slot >= 0 && source_slot !== null){
//console.debug("CONNbyTYPE OUT! type "+source_slotType+" for "+source_slot)
return source_node.connect(source_slot, this, slot);
}else{
// connect to the first general output slot if not found a specific type and
if (opts.generalTypeInCase){
var source_slot = source_node.findOutputSlotByType(0, false, true, true);
if (source_slot >= 0){
return source_node.connect(source_slot, this, slot);
}
}
if (opts.createEventInCase && source_slotType == LiteGraph.EVENT){
// WILL CREATE THE onExecuted OUT SLOT
if (LiteGraph.do_add_triggers_slots){
var source_slot = source_node.addOnExecutedOutput();
return source_node.connect(source_slot, this, slot);
}
}
// connect to the first free output slot if not found a specific type and this input is general
if (opts.firstFreeIfInputGeneralInCase && (source_slotType == 0 || source_slotType == "*" || source_slotType == "")){
var source_slot = source_node.findOutputSlotFree({typesNotAccepted: [LiteGraph.EVENT] });
if (source_slot >= 0){
return source_node.connect(source_slot, this, slot);
}
}
console.debug("no way to connect byOUT type: ",source_slotType," to sourceNODE ",source_node);
//TODO filter
//console.log("type OUT! "+source_slotType+" not found or not free?")
return null;
}
}
/**
* connect this node output to the input of another node
* @method connect
* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
* @param {LGraphNode} node the target node
* @param {number_or_string} target_slot the input slot of the target node (could be the number of the slot or the string with the name of the slot, or -1 to connect a trigger)
* @return {Object} the link_info is created, otherwise null
*/
LGraphNode.prototype.connect = function(slot, target_node, target_slot) {
target_slot = target_slot || 0;
if (!this.graph) {
//could be connected before adding it to a graph
console.log(
"Connect: Error, node doesn't belong to any graph. Nodes must be added first to a graph before connecting them."
); //due to link ids being associated with graphs
return null;
}
//seek for the output slot
if (slot.constructor === String) {
slot = this.findOutputSlot(slot);
if (slot == -1) {
if (LiteGraph.debug) {
console.log("Connect: Error, no slot of name " + slot);
}
return null;
}
} else if (!this.outputs || slot >= this.outputs.length) {
if (LiteGraph.debug) {
console.log("Connect: Error, slot number not found");
}
return null;
}
if (target_node && target_node.constructor === Number) {
target_node = this.graph.getNodeById(target_node);
}
if (!target_node) {
throw "target node is null";
}
//avoid loopback
if (target_node == this) {
return null;
}
//you can specify the slot by name
if (target_slot.constructor === String) {
target_slot = target_node.findInputSlot(target_slot);
if (target_slot == -1) {
if (LiteGraph.debug) {
console.log(
"Connect: Error, no slot of name " + target_slot
);
}
return null;
}
} else if (target_slot === LiteGraph.EVENT) {
if (LiteGraph.do_add_triggers_slots){
//search for first slot with event? :: NO this is done outside
//console.log("Connect: Creating triggerEvent");
// force mode
target_node.changeMode(LiteGraph.ON_TRIGGER);
target_slot = target_node.findInputSlot("onTrigger");
}else{
return null; // -- break --
}
} else if (
!target_node.inputs ||
target_slot >= target_node.inputs.length
) {
if (LiteGraph.debug) {
console.log("Connect: Error, slot number not found");
}
return null;
}
var changed = false;
var input = target_node.inputs[target_slot];
var link_info = null;
var output = this.outputs[slot];
if (!this.outputs[slot]){
/*console.debug("Invalid slot passed: "+slot);
console.debug(this.outputs);*/
return null;
}
// allow target node to change slot
if (target_node.onBeforeConnectInput) {
// This way node can choose another slot (or make a new one?)
target_slot = target_node.onBeforeConnectInput(target_slot); //callback
}
//check target_slot and check connection types
if (target_slot===false || target_slot===null || !LiteGraph.isValidConnection(output.type, input.type))
{
this.setDirtyCanvas(false, true);
if(changed)
this.graph.connectionChange(this, link_info);
return null;
}else{
//console.debug("valid connection",output.type, input.type);
}
//allows nodes to block connection, callback
if (target_node.onConnectInput) {
if ( target_node.onConnectInput(target_slot, output.type, output, this, slot) === false ) {
return null;
}
}
if (this.onConnectOutput) { // callback
if ( this.onConnectOutput(slot, input.type, input, target_node, target_slot) === false ) {
return null;
}
}
//if there is something already plugged there, disconnect
if (target_node.inputs[target_slot] && target_node.inputs[target_slot].link != null) {
this.graph.beforeChange();
target_node.disconnectInput(target_slot, {doProcessChange: false});
changed = true;
}
if (output.links !== null && output.links.length){
switch(output.type){
case LiteGraph.EVENT:
if (!LiteGraph.allow_multi_output_for_events){
this.graph.beforeChange();
this.disconnectOutput(slot, false, {doProcessChange: false}); // Input(target_slot, {doProcessChange: false});
changed = true;
}
break;
default:
break;
}
}
var nextId
if (LiteGraph.use_uuids)
nextId = LiteGraph.uuidv4();
else
nextId = ++this.graph.last_link_id;
//create link class
link_info = new LLink(
nextId,
input.type || output.type,
this.id,
slot,
target_node.id,
target_slot
);
//add to graph links list
this.graph.links[link_info.id] = link_info;
//connect in output
if (output.links == null) {
output.links = [];
}
output.links.push(link_info.id);
//connect in input
target_node.inputs[target_slot].link = link_info.id;
if (this.graph) {
this.graph._version++;
}
if (this.onConnectionsChange) {
this.onConnectionsChange(
LiteGraph.OUTPUT,
slot,
true,
link_info,
output
);
} //link_info has been created now, so its updated
if (target_node.onConnectionsChange) {
target_node.onConnectionsChange(
LiteGraph.INPUT,
target_slot,
true,
link_info,
input
);
}
if (this.graph && this.graph.onNodeConnectionChange) {
this.graph.onNodeConnectionChange(
LiteGraph.INPUT,
target_node,
target_slot,
this,
slot
);
this.graph.onNodeConnectionChange(
LiteGraph.OUTPUT,
this,
slot,
target_node,
target_slot
);
}
this.setDirtyCanvas(false, true);
this.graph.afterChange();
this.graph.connectionChange(this, link_info);
return link_info;
};
/**
* disconnect one output to an specific node
* @method disconnectOutput
* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
* @param {LGraphNode} target_node the target node to which this slot is connected [Optional, if not target_node is specified all nodes will be disconnected]
* @return {boolean} if it was disconnected successfully
*/
LGraphNode.prototype.disconnectOutput = function(slot, target_node) {
if (slot.constructor === String) {
slot = this.findOutputSlot(slot);
if (slot == -1) {
if (LiteGraph.debug) {
console.log("Connect: Error, no slot of name " + slot);
}
return false;
}
} else if (!this.outputs || slot >= this.outputs.length) {
if (LiteGraph.debug) {
console.log("Connect: Error, slot number not found");
}
return false;
}
//get output slot
var output = this.outputs[slot];
if (!output || !output.links || output.links.length == 0) {
return false;
}
//one of the output links in this slot
if (target_node) {
if (target_node.constructor === Number) {
target_node = this.graph.getNodeById(target_node);
}
if (!target_node) {
throw "Target Node not found";
}
for (var i = 0, l = output.links.length; i < l; i++) {
var link_id = output.links[i];
var link_info = this.graph.links[link_id];
//is the link we are searching for...
if (link_info.target_id == target_node.id) {
output.links.splice(i, 1); //remove here
var input = target_node.inputs[link_info.target_slot];
input.link = null; //remove there
delete this.graph.links[link_id]; //remove the link from the links pool
if (this.graph) {
this.graph._version++;
}
if (target_node.onConnectionsChange) {
target_node.onConnectionsChange(
LiteGraph.INPUT,
link_info.target_slot,
false,
link_info,
input
);
} //link_info hasn't been modified so its ok
if (this.onConnectionsChange) {
this.onConnectionsChange(
LiteGraph.OUTPUT,
slot,
false,
link_info,
output
);
}
if (this.graph && this.graph.onNodeConnectionChange) {
this.graph.onNodeConnectionChange(
LiteGraph.OUTPUT,
this,
slot
);
}
if (this.graph && this.graph.onNodeConnectionChange) {
this.graph.onNodeConnectionChange(
LiteGraph.OUTPUT,
this,
slot
);
this.graph.onNodeConnectionChange(
LiteGraph.INPUT,
target_node,
link_info.target_slot
);
}
break;
}
}
} //all the links in this output slot
else {
for (var i = 0, l = output.links.length; i < l; i++) {
var link_id = output.links[i];
var link_info = this.graph.links[link_id];
if (!link_info) {
//bug: it happens sometimes
continue;
}
var target_node = this.graph.getNodeById(link_info.target_id);
var input = null;
if (this.graph) {
this.graph._version++;
}
if (target_node) {
input = target_node.inputs[link_info.target_slot];
input.link = null; //remove other side link
if (target_node.onConnectionsChange) {
target_node.onConnectionsChange(
LiteGraph.INPUT,
link_info.target_slot,
false,
link_info,
input
);
} //link_info hasn't been modified so its ok
if (this.graph && this.graph.onNodeConnectionChange) {
this.graph.onNodeConnectionChange(
LiteGraph.INPUT,
target_node,
link_info.target_slot
);
}
}
delete this.graph.links[link_id]; //remove the link from the links pool
if (this.onConnectionsChange) {
this.onConnectionsChange(
LiteGraph.OUTPUT,
slot,
false,
link_info,
output
);
}
if (this.graph && this.graph.onNodeConnectionChange) {
this.graph.onNodeConnectionChange(
LiteGraph.OUTPUT,
this,
slot
);
this.graph.onNodeConnectionChange(
LiteGraph.INPUT,
target_node,
link_info.target_slot
);
}
}
output.links = null;
}
this.setDirtyCanvas(false, true);
this.graph.connectionChange(this);
return true;
};
/**
* disconnect one input
* @method disconnectInput
* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
* @return {boolean} if it was disconnected successfully
*/
LGraphNode.prototype.disconnectInput = function(slot) {
//seek for the output slot
if (slot.constructor === String) {
slot = this.findInputSlot(slot);
if (slot == -1) {
if (LiteGraph.debug) {
console.log("Connect: Error, no slot of name " + slot);
}
return false;
}
} else if (!this.inputs || slot >= this.inputs.length) {
if (LiteGraph.debug) {
console.log("Connect: Error, slot number not found");
}
return false;
}
var input = this.inputs[slot];
if (!input) {
return false;
}
var link_id = this.inputs[slot].link;
if(link_id != null)
{
this.inputs[slot].link = null;
//remove other side
var link_info = this.graph.links[link_id];
if (link_info) {
var target_node = this.graph.getNodeById(link_info.origin_id);
if (!target_node) {
return false;
}
var output = target_node.outputs[link_info.origin_slot];
if (!output || !output.links || output.links.length == 0) {
return false;
}
//search in the inputs list for this link
for (var i = 0, l = output.links.length; i < l; i++) {
if (output.links[i] == link_id) {
output.links.splice(i, 1);
break;
}
}
delete this.graph.links[link_id]; //remove from the pool
if (this.graph) {
this.graph._version++;
}
if (this.onConnectionsChange) {
this.onConnectionsChange(
LiteGraph.INPUT,
slot,
false,
link_info,
input
);
}
if (target_node.onConnectionsChange) {
target_node.onConnectionsChange(
LiteGraph.OUTPUT,
i,
false,
link_info,
output
);
}
if (this.graph && this.graph.onNodeConnectionChange) {
this.graph.onNodeConnectionChange(
LiteGraph.OUTPUT,
target_node,
i
);
this.graph.onNodeConnectionChange(LiteGraph.INPUT, this, slot);
}
}
} //link != null
this.setDirtyCanvas(false, true);
if(this.graph)
this.graph.connectionChange(this);
return true;
};
/**
* returns the center of a connection point in canvas coords
* @method getConnectionPos
* @param {boolean} is_input true if if a input slot, false if it is an output
* @param {number_or_string} slot (could be the number of the slot or the string with the name of the slot)
* @param {vec2} out [optional] a place to store the output, to free garbage
* @return {[x,y]} the position
**/
LGraphNode.prototype.getConnectionPos = function(
is_input,
slot_number,
out
) {
out = out || new Float32Array(2);
var num_slots = 0;
if (is_input && this.inputs) {
num_slots = this.inputs.length;
}
if (!is_input && this.outputs) {
num_slots = this.outputs.length;
}
var offset = LiteGraph.NODE_SLOT_HEIGHT * 0.5;
if (this.flags.collapsed) {
var w = this._collapsed_width || LiteGraph.NODE_COLLAPSED_WIDTH;
if (this.horizontal) {
out[0] = this.pos[0] + w * 0.5;
if (is_input) {
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
} else {
out[1] = this.pos[1];
}
} else {
if (is_input) {
out[0] = this.pos[0];
} else {
out[0] = this.pos[0] + w;
}
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT * 0.5;
}
return out;
}
//weird feature that never got finished
if (is_input && slot_number == -1) {
out[0] = this.pos[0] + LiteGraph.NODE_TITLE_HEIGHT * 0.5;
out[1] = this.pos[1] + LiteGraph.NODE_TITLE_HEIGHT * 0.5;
return out;
}
//hard-coded pos
if (
is_input &&
num_slots > slot_number &&
this.inputs[slot_number].pos
) {
out[0] = this.pos[0] + this.inputs[slot_number].pos[0];
out[1] = this.pos[1] + this.inputs[slot_number].pos[1];
return out;
} else if (
!is_input &&
num_slots > slot_number &&
this.outputs[slot_number].pos
) {
out[0] = this.pos[0] + this.outputs[slot_number].pos[0];
out[1] = this.pos[1] + this.outputs[slot_number].pos[1];
return out;
}
//horizontal distributed slots
if (this.horizontal) {
out[0] =
this.pos[0] + (slot_number + 0.5) * (this.size[0] / num_slots);
if (is_input) {
out[1] = this.pos[1] - LiteGraph.NODE_TITLE_HEIGHT;
} else {
out[1] = this.pos[1] + this.size[1];
}
return out;
}
//default vertical slots
if (is_input) {
out[0] = this.pos[0] + offset;
} else {
out[0] = this.pos[0] + this.size[0] + 1 - offset;
}
out[1] =
this.pos[1] +
(slot_number + 0.7) * LiteGraph.NODE_SLOT_HEIGHT +
(this.constructor.slot_start_y || 0);
return out;
};
/* Force align to grid */
LGraphNode.prototype.alignToGrid = function() {
this.pos[0] =
LiteGraph.CANVAS_GRID_SIZE *
Math.round(this.pos[0] / LiteGraph.CANVAS_GRID_SIZE);
this.pos[1] =
LiteGraph.CANVAS_GRID_SIZE *
Math.round(this.pos[1] / LiteGraph.CANVAS_GRID_SIZE);
};
/* Console output */
LGraphNode.prototype.trace = function(msg) {
if (!this.console) {
this.console = [];
}
this.console.push(msg);
if (this.console.length > LGraphNode.MAX_CONSOLE) {
this.console.shift();
}
if(this.graph.onNodeTrace)
this.graph.onNodeTrace(this, msg);
};
/* Forces to redraw or the main canvas (LGraphNode) or the bg canvas (links) */
LGraphNode.prototype.setDirtyCanvas = function(
dirty_foreground,
dirty_background
) {
if (!this.graph) {
return;
}
this.graph.sendActionToCanvas("setDirty", [
dirty_foreground,
dirty_background
]);
};
LGraphNode.prototype.loadImage = function(url) {
var img = new Image();
img.src = LiteGraph.node_images_path + url;
img.ready = false;
var that = this;
img.onload = function() {
this.ready = true;
that.setDirtyCanvas(true);
};
return img;
};
//safe LGraphNode action execution (not sure if safe)
/*
LGraphNode.prototype.executeAction = function(action)
{
if(action == "") return false;
if( action.indexOf(";") != -1 || action.indexOf("}") != -1)
{
this.trace("Error: Action contains unsafe characters");
return false;
}
var tokens = action.split("(");
var func_name = tokens[0];
if( typeof(this[func_name]) != "function")
{
this.trace("Error: Action not found on node: " + func_name);
return false;
}
var code = action;
try
{
var _foo = eval;
eval = null;
(new Function("with(this) { " + code + "}")).call(this);
eval = _foo;
}
catch (err)
{
this.trace("Error executing action {" + action + "} :" + err);
return false;
}
return true;
}
*/
/* Allows to get onMouseMove and onMouseUp events even if the mouse is out of focus */
LGraphNode.prototype.captureInput = function(v) {
if (!this.graph || !this.graph.list_of_graphcanvas) {
return;
}
var list = this.graph.list_of_graphcanvas;
for (var i = 0; i < list.length; ++i) {
var c = list[i];
//releasing somebody elses capture?!
if (!v && c.node_capturing_input != this) {
continue;
}
//change
c.node_capturing_input = v ? this : null;
}
};
/**
* Collapse the node to make it smaller on the canvas
* @method collapse
**/
LGraphNode.prototype.collapse = function(force) {
this.graph._version++;
if (this.constructor.collapsable === false && !force) {
return;
}
if (!this.flags.collapsed) {
this.flags.collapsed = true;
} else {
this.flags.collapsed = false;
}
this.setDirtyCanvas(true, true);
};
/**
* Forces the node to do not move or realign on Z
* @method pin
**/
LGraphNode.prototype.pin = function(v) {
this.graph._version++;
if (v === undefined) {
this.flags.pinned = !this.flags.pinned;
} else {
this.flags.pinned = v;
}
};
LGraphNode.prototype.localToScreen = function(x, y, graphcanvas) {
return [
(x + this.pos[0]) * graphcanvas.scale + graphcanvas.offset[0],
(y + this.pos[1]) * graphcanvas.scale + graphcanvas.offset[1]
];
};
function LGraphGroup(title) {
this._ctor(title);
}
global.LGraphGroup = LiteGraph.LGraphGroup = LGraphGroup;
LGraphGroup.prototype._ctor = function(title) {
this.title = title || "Group";
this.font_size = 24;
this.color = LGraphCanvas.node_colors.pale_blue
? LGraphCanvas.node_colors.pale_blue.groupcolor
: "#AAA";
this._bounding = new Float32Array([10, 10, 140, 80]);
this._pos = this._bounding.subarray(0, 2);
this._size = this._bounding.subarray(2, 4);
this._nodes = [];
this.graph = null;
Object.defineProperty(this, "pos", {
set: function(v) {
if (!v || v.length < 2) {
return;
}
this._pos[0] = v[0];
this._pos[1] = v[1];
},
get: function() {
return this._pos;
},
enumerable: true
});
Object.defineProperty(this, "size", {
set: function(v) {
if (!v || v.length < 2) {
return;
}
this._size[0] = Math.max(140, v[0]);
this._size[1] = Math.max(80, v[1]);
},
get: function() {
return this._size;
},
enumerable: true
});
};
LGraphGroup.prototype.configure = function(o) {
this.title = o.title;
this._bounding.set(o.bounding);
this.color = o.color;
this.font_size = o.font_size;
};
LGraphGroup.prototype.serialize = function() {
var b = this._bounding;
return {
title: this.title,
bounding: [
Math.round(b[0]),
Math.round(b[1]),
Math.round(b[2]),
Math.round(b[3])
],
color: this.color,
font_size: this.font_size
};
};
LGraphGroup.prototype.move = function(deltax, deltay, ignore_nodes) {
this._pos[0] += deltax;
this._pos[1] += deltay;
if (ignore_nodes) {
return;
}
for (var i = 0; i < this._nodes.length; ++i) {
var node = this._nodes[i];
node.pos[0] += deltax;
node.pos[1] += deltay;
}
};
LGraphGroup.prototype.recomputeInsideNodes = function() {
this._nodes.length = 0;
var nodes = this.graph._nodes;
var node_bounding = new Float32Array(4);
for (var i = 0; i < nodes.length; ++i) {
var node = nodes[i];
node.getBounding(node_bounding);
if (!overlapBounding(this._bounding, node_bounding)) {
continue;
} //out of the visible area
this._nodes.push(node);
}
};
LGraphGroup.prototype.isPointInside = LGraphNode.prototype.isPointInside;
LGraphGroup.prototype.setDirtyCanvas = LGraphNode.prototype.setDirtyCanvas;
//****************************************
//Scale and Offset
function DragAndScale(element, skip_events) {
this.offset = new Float32Array([0, 0]);
this.scale = 1;
this.max_scale = 10;
this.min_scale = 0.1;
this.onredraw = null;
this.enabled = true;
this.last_mouse = [0, 0];
this.element = null;
this.visible_area = new Float32Array(4);
if (element) {
this.element = element;
if (!skip_events) {
this.bindEvents(element);
}
}
}
LiteGraph.DragAndScale = DragAndScale;
DragAndScale.prototype.bindEvents = function(element) {
this.last_mouse = new Float32Array(2);
this._binded_mouse_callback = this.onMouse.bind(this);
LiteGraph.pointerListenerAdd(element,"down", this._binded_mouse_callback);
LiteGraph.pointerListenerAdd(element,"move", this._binded_mouse_callback);
LiteGraph.pointerListenerAdd(element,"up", this._binded_mouse_callback);
element.addEventListener(
"mousewheel",
this._binded_mouse_callback,
false
);
element.addEventListener("wheel", this._binded_mouse_callback, false);
};
DragAndScale.prototype.computeVisibleArea = function( viewport ) {
if (!this.element) {
this.visible_area[0] = this.visible_area[1] = this.visible_area[2] = this.visible_area[3] = 0;
return;
}
var width = this.element.width;
var height = this.element.height;
var startx = -this.offset[0];
var starty = -this.offset[1];
if( viewport )
{
startx += viewport[0] / this.scale;
starty += viewport[1] / this.scale;
width = viewport[2];
height = viewport[3];
}
var endx = startx + width / this.scale;
var endy = starty + height / this.scale;
this.visible_area[0] = startx;
this.visible_area[1] = starty;
this.visible_area[2] = endx - startx;
this.visible_area[3] = endy - starty;
};
DragAndScale.prototype.onMouse = function(e) {
if (!this.enabled) {
return;
}
var canvas = this.element;
var rect = canvas.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
e.canvasx = x;
e.canvasy = y;
e.dragging = this.dragging;
var is_inside = !this.viewport || ( this.viewport && x >= this.viewport[0] && x < (this.viewport[0] + this.viewport[2]) && y >= this.viewport[1] && y < (this.viewport[1] + this.viewport[3]) );
//console.log("pointerevents: DragAndScale onMouse "+e.type+" "+is_inside);
var ignore = false;
if (this.onmouse) {
ignore = this.onmouse(e);
}
if (e.type == LiteGraph.pointerevents_method+"down" && is_inside) {
this.dragging = true;
LiteGraph.pointerListenerRemove(canvas,"move",this._binded_mouse_callback);
LiteGraph.pointerListenerAdd(document,"move",this._binded_mouse_callback);
LiteGraph.pointerListenerAdd(document,"up",this._binded_mouse_callback);
} else if (e.type == LiteGraph.pointerevents_method+"move") {
if (!ignore) {
var deltax = x - this.last_mouse[0];
var deltay = y - this.last_mouse[1];
if (this.dragging) {
this.mouseDrag(deltax, deltay);
}
}
} else if (e.type == LiteGraph.pointerevents_method+"up") {
this.dragging = false;
LiteGraph.pointerListenerRemove(document,"move",this._binded_mouse_callback);
LiteGraph.pointerListenerRemove(document,"up",this._binded_mouse_callback);
LiteGraph.pointerListenerAdd(canvas,"move",this._binded_mouse_callback);
} else if ( is_inside &&
(e.type == "mousewheel" ||
e.type == "wheel" ||
e.type == "DOMMouseScroll")
) {
e.eventType = "mousewheel";
if (e.type == "wheel") {
e.wheel = -e.deltaY;
} else {
e.wheel =
e.wheelDeltaY != null ? e.wheelDeltaY : e.detail * -60;
}
//from stack overflow
e.delta = e.wheelDelta
? e.wheelDelta / 40
: e.deltaY
? -e.deltaY / 3
: 0;
this.changeDeltaScale(1.0 + e.delta * 0.05);
}
this.last_mouse[0] = x;
this.last_mouse[1] = y;
if(is_inside)
{
e.preventDefault();
e.stopPropagation();
return false;
}
};
DragAndScale.prototype.toCanvasContext = function(ctx) {
ctx.scale(this.scale, this.scale);
ctx.translate(this.offset[0], this.offset[1]);
};
DragAndScale.prototype.convertOffsetToCanvas = function(pos) {
//return [pos[0] / this.scale - this.offset[0], pos[1] / this.scale - this.offset[1]];
return [
(pos[0] + this.offset[0]) * this.scale,
(pos[1] + this.offset[1]) * this.scale
];
};
DragAndScale.prototype.convertCanvasToOffset = function(pos, out) {
out = out || [0, 0];
out[0] = pos[0] / this.scale - this.offset[0];
out[1] = pos[1] / this.scale - this.offset[1];
return out;
};
DragAndScale.prototype.mouseDrag = function(x, y) {
this.offset[0] += x / this.scale;
this.offset[1] += y / this.scale;
if (this.onredraw) {
this.onredraw(this);
}
};
DragAndScale.prototype.changeScale = function(value, zooming_center) {
if (value < this.min_scale) {
value = this.min_scale;
} else if (value > this.max_scale) {
value = this.max_scale;
}
if (value == this.scale) {
return;
}
if (!this.element) {
return;
}
var rect = this.element.getBoundingClientRect();
if (!rect) {
return;
}
zooming_center = zooming_center || [
rect.width * 0.5,
rect.height * 0.5
];
var center = this.convertCanvasToOffset(zooming_center);
this.scale = value;
if (Math.abs(this.scale - 1) < 0.01) {
this.scale = 1;
}
var new_center = this.convertCanvasToOffset(zooming_center);
var delta_offset = [
new_center[0] - center[0],
new_center[1] - center[1]
];
this.offset[0] += delta_offset[0];
this.offset[1] += delta_offset[1];
if (this.onredraw) {
this.onredraw(this);
}
};
DragAndScale.prototype.changeDeltaScale = function(value, zooming_center) {
this.changeScale(this.scale * value, zooming_center);
};
DragAndScale.prototype.reset = function() {
this.scale = 1;
this.offset[0] = 0;
this.offset[1] = 0;
};
//*********************************************************************************
// LGraphCanvas: LGraph renderer CLASS
//*********************************************************************************
/**
* This class is in charge of rendering one graph inside a canvas. And provides all the interaction required.
* Valid callbacks are: onNodeSelected, onNodeDeselected, onShowNodePanel, onNodeDblClicked
*
* @class LGraphCanvas
* @constructor
* @param {HTMLCanvas} canvas the canvas where you want to render (it accepts a selector in string format or the canvas element itself)
* @param {LGraph} graph [optional]
* @param {Object} options [optional] { skip_rendering, autoresize, viewport }
*/
function LGraphCanvas(canvas, graph, options) {
this.options = options = options || {};
//if(graph === undefined)
// throw ("No graph assigned");
this.background_image = LGraphCanvas.DEFAULT_BACKGROUND_IMAGE;
if (canvas && canvas.constructor === String) {
canvas = document.querySelector(canvas);
}
this.ds = new DragAndScale();
this.zoom_modify_alpha = true; //otherwise it generates ugly patterns when scaling down too much
this.title_text_font = "" + LiteGraph.NODE_TEXT_SIZE + "px Arial";
this.inner_text_font =
"normal " + LiteGraph.NODE_SUBTEXT_SIZE + "px Arial";
this.node_title_color = LiteGraph.NODE_TITLE_COLOR;
this.default_link_color = LiteGraph.LINK_COLOR;
this.default_connection_color = {
input_off: "#778",
input_on: "#7F7", //"#BBD"
output_off: "#778",
output_on: "#7F7" //"#BBD"
};
this.default_connection_color_byType = {
/*number: "#7F7",
string: "#77F",
boolean: "#F77",*/
}
this.default_connection_color_byTypeOff = {
/*number: "#474",
string: "#447",
boolean: "#744",*/
};
this.highquality_render = true;
this.use_gradients = false; //set to true to render titlebar with gradients
this.editor_alpha = 1; //used for transition
this.pause_rendering = false;
this.clear_background = true;
this.clear_background_color = "#222";
this.read_only = false; //if set to true users cannot modify the graph
this.render_only_selected = true;
this.live_mode = false;
this.show_info = true;
this.allow_dragcanvas = true;
this.allow_dragnodes = true;
this.allow_interaction = true; //allow to control widgets, buttons, collapse, etc
this.multi_select = false; //allow selecting multi nodes without pressing extra keys
this.allow_searchbox = true;
this.allow_reconnect_links = true; //allows to change a connection with having to redo it again
this.align_to_grid = false; //snap to grid
this.drag_mode = false;
this.dragging_rectangle = null;
this.filter = null; //allows to filter to only accept some type of nodes in a graph
this.set_canvas_dirty_on_mouse_event = true; //forces to redraw the canvas if the mouse does anything
this.always_render_background = false;
this.render_shadows = true;
this.render_canvas_border = true;
this.render_connections_shadows = false; //too much cpu
this.render_connections_border = true;
this.render_curved_connections = false;
this.render_connection_arrows = false;
this.render_collapsed_slots = true;
this.render_execution_order = false;
this.render_title_colored = true;
this.render_link_tooltip = true;
this.links_render_mode = LiteGraph.SPLINE_LINK;
this.mouse = [0, 0]; //mouse in canvas coordinates, where 0,0 is the top-left corner of the blue rectangle
this.graph_mouse = [0, 0]; //mouse in graph coordinates, where 0,0 is the top-left corner of the blue rectangle
this.canvas_mouse = this.graph_mouse; //LEGACY: REMOVE THIS, USE GRAPH_MOUSE INSTEAD
//to personalize the search box
this.onSearchBox = null;
this.onSearchBoxSelection = null;
//callbacks
this.onMouse = null;
this.onDrawBackground = null; //to render background objects (behind nodes and connections) in the canvas affected by transform
this.onDrawForeground = null; //to render foreground objects (above nodes and connections) in the canvas affected by transform
this.onDrawOverlay = null; //to render foreground objects not affected by transform (for GUIs)
this.onDrawLinkTooltip = null; //called when rendering a tooltip
this.onNodeMoved = null; //called after moving a node
this.onSelectionChange = null; //called if the selection changes
this.onConnectingChange = null; //called before any link changes
this.onBeforeChange = null; //called before modifying the graph
this.onAfterChange = null; //called after modifying the graph
this.connections_width = 3;
this.round_radius = 8;
this.current_node = null;
this.node_widget = null; //used for widgets
this.over_link_center = null;
this.last_mouse_position = [0, 0];
this.visible_area = this.ds.visible_area;
this.visible_links = [];
this.viewport = options.viewport || null; //to constraint render area to a portion of the canvas
//link canvas and graph
if (graph) {
graph.attachCanvas(this);
}
this.setCanvas(canvas,options.skip_events);
this.clear();
if (!options.skip_render) {
this.startRendering();
}
this.autoresize = options.autoresize;
}
global.LGraphCanvas = LiteGraph.LGraphCanvas = LGraphCanvas;
LGraphCanvas.DEFAULT_BACKGROUND_IMAGE = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQBJREFUeNrs1rEKwjAUhlETUkj3vP9rdmr1Ysammk2w5wdxuLgcMHyptfawuZX4pJSWZTnfnu/lnIe/jNNxHHGNn//HNbbv+4dr6V+11uF527arU7+u63qfa/bnmh8sWLBgwYJlqRf8MEptXPBXJXa37BSl3ixYsGDBMliwFLyCV/DeLIMFCxYsWLBMwSt4Be/NggXLYMGCBUvBK3iNruC9WbBgwYJlsGApeAWv4L1ZBgsWLFiwYJmCV/AK3psFC5bBggULloJX8BpdwXuzYMGCBctgwVLwCl7Be7MMFixYsGDBsu8FH1FaSmExVfAxBa/gvVmwYMGCZbBg/W4vAQYA5tRF9QYlv/QAAAAASUVORK5CYII=";
LGraphCanvas.link_type_colors = {
"-1": LiteGraph.EVENT_LINK_COLOR,
number: "#AAA",
node: "#DCA"
};
LGraphCanvas.gradients = {}; //cache of gradients
/**
* clears all the data inside
*
* @method clear
*/
LGraphCanvas.prototype.clear = function() {
this.frame = 0;
this.last_draw_time = 0;
this.render_time = 0;
this.fps = 0;
//this.scale = 1;
//this.offset = [0,0];
this.dragging_rectangle = null;
this.selected_nodes = {};
this.selected_group = null;
this.visible_nodes = [];
this.node_dragged = null;
this.node_over = null;
this.node_capturing_input = null;
this.connecting_node = null;
this.highlighted_links = {};
this.dragging_canvas = false;
this.dirty_canvas = true;
this.dirty_bgcanvas = true;
this.dirty_area = null;
this.node_in_panel = null;
this.node_widget = null;
this.last_mouse = [0, 0];
this.last_mouseclick = 0;
this.pointer_is_down = false;
this.pointer_is_double = false;
this.visible_area.set([0, 0, 0, 0]);
if (this.onClear) {
this.onClear();
}
};
/**
* assigns a graph, you can reassign graphs to the same canvas
*
* @method setGraph
* @param {LGraph} graph
*/
LGraphCanvas.prototype.setGraph = function(graph, skip_clear) {
if (this.graph == graph) {
return;
}
if (!skip_clear) {
this.clear();
}
if (!graph && this.graph) {
this.graph.detachCanvas(this);
return;
}
graph.attachCanvas(this);
//remove the graph stack in case a subgraph was open
if (this._graph_stack)
this._graph_stack = null;
this.setDirty(true, true);
};
/**
* returns the top level graph (in case there are subgraphs open on the canvas)
*
* @method getTopGraph
* @return {LGraph} graph
*/
LGraphCanvas.prototype.getTopGraph = function()
{
if(this._graph_stack.length)
return this._graph_stack[0];
return this.graph;
}
/**
* opens a graph contained inside a node in the current graph
*
* @method openSubgraph
* @param {LGraph} graph
*/
LGraphCanvas.prototype.openSubgraph = function(graph) {
if (!graph) {
throw "graph cannot be null";
}
if (this.graph == graph) {
throw "graph cannot be the same";
}
this.clear();
if (this.graph) {
if (!this._graph_stack) {
this._graph_stack = [];
}
this._graph_stack.push(this.graph);
}
graph.attachCanvas(this);
this.checkPanels();
this.setDirty(true, true);
};
/**
* closes a subgraph contained inside a node
*
* @method closeSubgraph
* @param {LGraph} assigns a graph
*/
LGraphCanvas.prototype.closeSubgraph = function() {
if (!this._graph_stack || this._graph_stack.length == 0) {
return;
}
var subgraph_node = this.graph._subgraph_node;
var graph = this._graph_stack.pop();
this.selected_nodes = {};
this.highlighted_links = {};
graph.attachCanvas(this);
this.setDirty(true, true);
if (subgraph_node) {
this.centerOnNode(subgraph_node);
this.selectNodes([subgraph_node]);
}
// when close sub graph back to offset [0, 0] scale 1
this.ds.offset = [0, 0]
this.ds.scale = 1
};
/**
* returns the visually active graph (in case there are more in the stack)
* @method getCurrentGraph
* @return {LGraph} the active graph
*/
LGraphCanvas.prototype.getCurrentGraph = function() {
return this.graph;
};
/**
* assigns a canvas
*
* @method setCanvas
* @param {Canvas} assigns a canvas (also accepts the ID of the element (not a selector)
*/
LGraphCanvas.prototype.setCanvas = function(canvas, skip_events) {
var that = this;
if (canvas) {
if (canvas.constructor === String) {
canvas = document.getElementById(canvas);
if (!canvas) {
throw "Error creating LiteGraph canvas: Canvas not found";
}
}
}
if (canvas === this.canvas) {
return;
}
if (!canvas && this.canvas) {
//maybe detach events from old_canvas
if (!skip_events) {
this.unbindEvents();
}
}
this.canvas = canvas;
this.ds.element = canvas;
if (!canvas) {
return;
}
//this.canvas.tabindex = "1000";
canvas.className += " lgraphcanvas";
canvas.data = this;
canvas.tabindex = "1"; //to allow key events
//bg canvas: used for non changing stuff
this.bgcanvas = null;
if (!this.bgcanvas) {
this.bgcanvas = document.createElement("canvas");
this.bgcanvas.width = this.canvas.width;
this.bgcanvas.height = this.canvas.height;
}
if (canvas.getContext == null) {
if (canvas.localName != "canvas") {
throw "Element supplied for LGraphCanvas must be a <canvas> element, you passed a " +
canvas.localName;
}
throw "This browser doesn't support Canvas";
}
var ctx = (this.ctx = canvas.getContext("2d"));
if (ctx == null) {
if (!canvas.webgl_enabled) {
console.warn(
"This canvas seems to be WebGL, enabling WebGL renderer"
);
}
this.enableWebGL();
}
//input: (move and up could be unbinded)
// why here? this._mousemove_callback = this.processMouseMove.bind(this);
// why here? this._mouseup_callback = this.processMouseUp.bind(this);
if (!skip_events) {
this.bindEvents();
}
};
//used in some events to capture them
LGraphCanvas.prototype._doNothing = function doNothing(e) {
//console.log("pointerevents: _doNothing "+e.type);
e.preventDefault();
return false;
};
LGraphCanvas.prototype._doReturnTrue = function doNothing(e) {
e.preventDefault();
return true;
};
/**
* binds mouse, keyboard, touch and drag events to the canvas
* @method bindEvents
**/
LGraphCanvas.prototype.bindEvents = function() {
if (this._events_binded) {
console.warn("LGraphCanvas: events already binded");
return;
}
//console.log("pointerevents: bindEvents");
var canvas = this.canvas;
var ref_window = this.getCanvasWindow();
var document = ref_window.document; //hack used when moving canvas between windows
this._mousedown_callback = this.processMouseDown.bind(this);
this._mousewheel_callback = this.processMouseWheel.bind(this);
// why mousemove and mouseup were not binded here?
this._mousemove_callback = this.processMouseMove.bind(this);
this._mouseup_callback = this.processMouseUp.bind(this);
//touch events -- TODO IMPLEMENT
//this._touch_callback = this.touchHandler.bind(this);
LiteGraph.pointerListenerAdd(canvas,"down", this._mousedown_callback, true); //down do not need to store the binded
canvas.addEventListener("mousewheel", this._mousewheel_callback, false);
LiteGraph.pointerListenerAdd(canvas,"up", this._mouseup_callback, true); // CHECK: ??? binded or not
LiteGraph.pointerListenerAdd(canvas,"move", this._mousemove_callback);
canvas.addEventListener("contextmenu", this._doNothing);
canvas.addEventListener(
"DOMMouseScroll",
this._mousewheel_callback,
false
);
//touch events -- THIS WAY DOES NOT WORK, finish implementing pointerevents, than clean the touchevents
/*if( 'touchstart' in document.documentElement )
{
canvas.addEventListener("touchstart", this._touch_callback, true);
canvas.addEventListener("touchmove", this._touch_callback, true);
canvas.addEventListener("touchend", this._touch_callback, true);
canvas.addEventListener("touchcancel", this._touch_callback, true);
}*/
//Keyboard ******************
this._key_callback = this.processKey.bind(this);
canvas.setAttribute("tabindex",1); //otherwise key events are ignored
canvas.addEventListener("keydown", this._key_callback, true);
document.addEventListener("keyup", this._key_callback, true); //in document, otherwise it doesn't fire keyup
//Dropping Stuff over nodes ************************************
this._ondrop_callback = this.processDrop.bind(this);
canvas.addEventListener("dragover", this._doNothing, false);
canvas.addEventListener("dragend", this._doNothing, false);
canvas.addEventListener("drop", this._ondrop_callback, false);
canvas.ad
gitextract_a35_aqba/
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmrc
├── .prettierrc
├── .vscode/
│ └── extensions.json
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build/
│ ├── litegraph.core.js
│ ├── litegraph.js
│ └── litegraph_mini.js
├── csharp/
│ ├── LiteGraph.cs
│ ├── LiteGraphNodes.cs
│ ├── LiteGraphTest.cs
│ ├── SimpleJSON.cs
│ ├── graph.JSON
│ └── readme.md
├── css/
│ ├── litegraph-editor.css
│ └── litegraph.css
├── doc/
│ ├── api.js
│ ├── assets/
│ │ ├── css/
│ │ │ └── main.css
│ │ ├── index.html
│ │ ├── js/
│ │ │ ├── api-filter.js
│ │ │ ├── api-list.js
│ │ │ ├── api-search.js
│ │ │ ├── apidocs.js
│ │ │ └── yui-prettify.js
│ │ └── vendor/
│ │ └── prettify/
│ │ ├── CHANGES.html
│ │ ├── COPYING
│ │ ├── README.html
│ │ ├── prettify-min.css
│ │ └── prettify-min.js
│ ├── classes/
│ │ ├── ContextMenu.html
│ │ ├── LGraph.html
│ │ ├── LGraphCanvas.html
│ │ ├── LGraphNode.html
│ │ ├── LiteGraph.html
│ │ └── index.html
│ ├── data.json
│ ├── elements/
│ │ └── index.html
│ ├── files/
│ │ ├── .._src_litegraph.js.html
│ │ └── index.html
│ ├── index.html
│ └── modules/
│ └── index.html
├── editor/
│ ├── demodata/
│ │ └── video.webm
│ ├── editor_mobile.html
│ ├── examples/
│ │ ├── audio.json
│ │ ├── audio_delay.json
│ │ ├── audio_reverb.json
│ │ ├── benchmark.json
│ │ ├── copypaste.json
│ │ ├── features.json
│ │ ├── midi_generation.json
│ │ └── subgraph.json
│ ├── index.html
│ ├── js/
│ │ ├── code.js
│ │ ├── defaults.js
│ │ ├── defaults_mobile.js
│ │ ├── demos.js
│ │ └── libs/
│ │ ├── audiosynth.js
│ │ ├── gl-matrix-min.js
│ │ ├── litegl.js
│ │ └── midi-parser.js
│ └── style.css
├── external/
│ ├── Basica.otf
│ ├── Criticized.otf
│ ├── DS-Digital.otf
│ └── beat.otf
├── gruntfile.js
├── guides/
│ └── README.md
├── index.html
├── jest.config.js
├── package.json
├── src/
│ ├── litegraph-editor.js
│ ├── litegraph.d.ts
│ ├── litegraph.js
│ ├── litegraph.test.js
│ └── nodes/
│ ├── audio.js
│ ├── base.js
│ ├── events.js
│ ├── geometry.js
│ ├── glfx.js
│ ├── glshaders.js
│ ├── gltextures.js
│ ├── graphics.js
│ ├── input.js
│ ├── interface.js
│ ├── logic.js
│ ├── math.js
│ ├── math3d.js
│ ├── midi.js
│ ├── network.js
│ ├── others.js
│ └── strings.js
├── style.css
└── utils/
├── build.sh
├── builder.py
├── deploy_files.txt
├── deploy_files_core.txt
├── deploy_files_mini.txt
├── generate_doc.sh
├── pack.sh
├── server.js
├── temp.js
└── test.sh
SYMBOL INDEX (1123 symbols across 35 files)
FILE: build/litegraph.core.js
function LGraph (line 837) | function LGraph(o) {
function on_frame (line 997) | function on_frame() {
function LLink (line 2378) | function LLink(id, type, origin_id, origin_slot, target_id, target_slot) {
function LGraphNode (line 2482) | function LGraphNode(title) {
function compute_text_size (line 3742) | function compute_text_size(text) {
function LGraphGroup (line 4992) | function LGraphGroup(title) {
function DragAndScale (line 5095) | function DragAndScale(element, skip_events) {
function LGraphCanvas (line 5327) | function LGraphCanvas(canvas, graph, options) {
function renderFrame (line 5891) | function renderFrame() {
function inner_clicked (line 10205) | function inner_clicked(v, option, event) {
function inner_value_change (line 10277) | function inner_value_change(widget, value) {
function inner_clicked (line 10577) | function inner_clicked(value) {
function inner_clicked (line 10589) | function inner_clicked(value) {
function inner_onMenuAdded (line 10602) | function inner_onMenuAdded(base_category ,prev_menu){
function inner_clicked (line 10734) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10839) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10938) | function inner_clicked(v, options, e, prev) {
function inner_clicked (line 10999) | function inner_clicked(v,options,e) {
function inner_clicked (line 11256) | function inner_clicked(v,options,e) {
function inner (line 11370) | function inner() {
function setValue (line 11374) | function setValue(value) {
function select (line 11754) | function select(name) {
function changeSelection (line 11872) | function changeSelection(forward) {
function refreshHelper (line 11896) | function refreshHelper() {
function inner (line 12179) | function inner() {
function setValue (line 12183) | function setValue(value) {
function inner_clicked (line 12478) | function inner_clicked(v, option, event) {
function innerChange (line 12490) | function innerChange(name, value)
function inner_refresh (line 12572) | function inner_refresh(){
function inner_refresh (line 12651) | function inner_refresh()
function inner_refresh (line 12792) | function inner_refresh()
function inner_refresh (line 12848) | function inner_refresh() {
function addOutput (line 12880) | function addOutput() {
function inner_clicked (line 12940) | function inner_clicked(v) {
function inner_clicked (line 13001) | function inner_clicked(v) {
function inner_clicked (line 13048) | function inner_clicked(v) {
function inner_option_clicked (line 13449) | function inner_option_clicked(v, options, e) {
function compareObjects (line 13521) | function compareObjects(a, b) {
function distance (line 13531) | function distance(a, b) {
function colorToString (line 13538) | function colorToString(c) {
function isInsideRectangle (line 13553) | function isInsideRectangle(x, y, left, top, width, height) {
function growBounding (line 13562) | function growBounding(bounding, x, y) {
function isInsideBounding (line 13578) | function isInsideBounding(p, bb) {
function overlapBounding (line 13592) | function overlapBounding(a, b) {
function hex2num (line 13613) | function hex2num(hex) {
function num2hex (line 13635) | function num2hex(triplet) {
function ContextMenu (line 13664) | function ContextMenu(values, options) {
function inner_over (line 13897) | function inner_over(e) {
function inner_onclick (line 13907) | function inner_onclick(e) {
function CurveEditor (line 14119) | function CurveEditor( points )
function clamp (line 14401) | function clamp(v, a, b) {
FILE: build/litegraph.js
function LGraph (line 837) | function LGraph(o) {
function on_frame (line 997) | function on_frame() {
function LLink (line 2378) | function LLink(id, type, origin_id, origin_slot, target_id, target_slot) {
function LGraphNode (line 2482) | function LGraphNode(title) {
function compute_text_size (line 3742) | function compute_text_size(text) {
function LGraphGroup (line 4992) | function LGraphGroup(title) {
function DragAndScale (line 5095) | function DragAndScale(element, skip_events) {
function LGraphCanvas (line 5327) | function LGraphCanvas(canvas, graph, options) {
function renderFrame (line 5891) | function renderFrame() {
function inner_clicked (line 10205) | function inner_clicked(v, option, event) {
function inner_value_change (line 10277) | function inner_value_change(widget, value) {
function inner_clicked (line 10577) | function inner_clicked(value) {
function inner_clicked (line 10589) | function inner_clicked(value) {
function inner_onMenuAdded (line 10602) | function inner_onMenuAdded(base_category ,prev_menu){
function inner_clicked (line 10734) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10839) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10938) | function inner_clicked(v, options, e, prev) {
function inner_clicked (line 10999) | function inner_clicked(v,options,e) {
function inner_clicked (line 11256) | function inner_clicked(v,options,e) {
function inner (line 11370) | function inner() {
function setValue (line 11374) | function setValue(value) {
function select (line 11754) | function select(name) {
function changeSelection (line 11872) | function changeSelection(forward) {
function refreshHelper (line 11896) | function refreshHelper() {
function inner (line 12179) | function inner() {
function setValue (line 12183) | function setValue(value) {
function inner_clicked (line 12478) | function inner_clicked(v, option, event) {
function innerChange (line 12490) | function innerChange(name, value)
function inner_refresh (line 12572) | function inner_refresh(){
function inner_refresh (line 12651) | function inner_refresh()
function inner_refresh (line 12792) | function inner_refresh()
function inner_refresh (line 12848) | function inner_refresh() {
function addOutput (line 12880) | function addOutput() {
function inner_clicked (line 12940) | function inner_clicked(v) {
function inner_clicked (line 13001) | function inner_clicked(v) {
function inner_clicked (line 13048) | function inner_clicked(v) {
function inner_option_clicked (line 13449) | function inner_option_clicked(v, options, e) {
function compareObjects (line 13521) | function compareObjects(a, b) {
function distance (line 13531) | function distance(a, b) {
function colorToString (line 13538) | function colorToString(c) {
function isInsideRectangle (line 13553) | function isInsideRectangle(x, y, left, top, width, height) {
function growBounding (line 13562) | function growBounding(bounding, x, y) {
function isInsideBounding (line 13578) | function isInsideBounding(p, bb) {
function overlapBounding (line 13592) | function overlapBounding(a, b) {
function hex2num (line 13613) | function hex2num(hex) {
function num2hex (line 13635) | function num2hex(triplet) {
function ContextMenu (line 13664) | function ContextMenu(values, options) {
function inner_over (line 13897) | function inner_over(e) {
function inner_onclick (line 13907) | function inner_onclick(e) {
function CurveEditor (line 14119) | function CurveEditor( points )
function clamp (line 14401) | function clamp(v, a, b) {
function Time (line 14433) | function Time() {
function Subgraph (line 14449) | function Subgraph() {
function GraphInput (line 14911) | function GraphInput() {
function GraphOutput (line 15072) | function GraphOutput() {
function ConstantNumber (line 15205) | function ConstantNumber() {
function ConstantBoolean (line 15239) | function ConstantBoolean() {
function ConstantString (line 15269) | function ConstantString() {
function ConstantObject (line 15301) | function ConstantObject() {
function ConstantFile (line 15316) | function ConstantFile() {
function JSONParse (line 15416) | function JSONParse() {
function ConstantData (line 15457) | function ConstantData() {
function ConstantArray (line 15492) | function ConstantArray() {
function SetArray (line 15541) | function SetArray()
function ArrayElement (line 15567) | function ArrayElement() {
function TableElement (line 15589) | function TableElement() {
function ObjectProperty (line 15620) | function ObjectProperty() {
function ObjectKeys (line 15658) | function ObjectKeys() {
function SetObject (line 15677) | function SetObject()
function MergeObjects (line 15704) | function MergeObjects() {
function Variable (line 15735) | function Variable() {
function length (line 15791) | function length(v) {
function length (line 15804) | function length(v) {
function DownloadData (line 15817) | function DownloadData() {
function Watch (line 15880) | function Watch() {
function Cast (line 15927) | function Cast() {
function Console (line 15943) | function Console() {
function Alert (line 15989) | function Alert() {
function NodeScript (line 16017) | function NodeScript() {
function GenericCompare (line 16101) | function GenericCompare() {
function LogEvent (line 16204) | function LogEvent() {
function TriggerEvent (line 16219) | function TriggerEvent() {
function Sequence (line 16250) | function Sequence() {
function WaitAll (line 16292) | function WaitAll() {
function Stepper (line 16349) | function Stepper() {
function FilterEvent (line 16416) | function FilterEvent() {
function EventBranch (line 16459) | function EventBranch() {
function EventCounter (line 16483) | function EventCounter() {
function DelayEvent (line 16538) | function DelayEvent() {
function TimerEvent (line 16589) | function TimerEvent() {
function SemaphoreEvent (line 16660) | function SemaphoreEvent() {
function OnceEvent (line 16695) | function OnceEvent() {
function DataStore (line 16722) | function DataStore() {
function WidgetButton (line 16767) | function WidgetButton() {
function WidgetToggle (line 16850) | function WidgetToggle() {
function WidgetNumber (line 16922) | function WidgetNumber() {
function WidgetCombo (line 17040) | function WidgetCombo() {
function WidgetKnob (line 17080) | function WidgetKnob() {
function WidgetSliderGUI (line 17241) | function WidgetSliderGUI() {
function WidgetHSlider (line 17278) | function WidgetHSlider() {
function WidgetProgress (line 17362) | function WidgetProgress() {
function WidgetText (line 17392) | function WidgetText() {
function WidgetPanel (line 17489) | function WidgetPanel() {
function GamepadInput (line 17563) | function GamepadInput() {
function Converter (line 17919) | function Converter() {
function Bypass (line 17994) | function Bypass() {
function ToNumber (line 18010) | function ToNumber() {
function MathRange (line 18025) | function MathRange() {
function MathRand (line 18108) | function MathRand() {
function MathNoise (line 18148) | function MathNoise() {
function MathSpikes (line 18218) | function MathSpikes() {
function MathClamp (line 18259) | function MathClamp() {
function MathLerp (line 18297) | function MathLerp() {
function MathAbs (line 18335) | function MathAbs() {
function MathFloor (line 18355) | function MathFloor() {
function MathFrac (line 18375) | function MathFrac() {
function MathSmoothStep (line 18395) | function MathSmoothStep() {
function MathScale (line 18425) | function MathScale() {
function Gate (line 18445) | function Gate() {
function MathAverageFilter (line 18464) | function MathAverageFilter() {
function MathTendTo (line 18516) | function MathTendTo() {
function MathOperation (line 18544) | function MathOperation() {
function MathCompare (line 18673) | function MathCompare() {
function MathCondition (line 18768) | function MathCondition() {
function MathBranch (line 18845) | function MathBranch() {
function MathAccumulate (line 18875) | function MathAccumulate() {
function MathTrigonometry (line 18902) | function MathTrigonometry() {
function MathFormula (line 18989) | function MathFormula() {
function Math3DVec2ToXY (line 19071) | function Math3DVec2ToXY() {
function Math3DXYToVec2 (line 19092) | function Math3DXYToVec2() {
function Math3DVec3ToXYZ (line 19121) | function Math3DVec3ToXYZ() {
function Math3DXYZToVec3 (line 19144) | function Math3DXYZToVec3() {
function Math3DVec4ToXYZW (line 19178) | function Math3DVec4ToXYZW() {
function Math3DXYZWToVec4 (line 19203) | function Math3DXYZWToVec4() {
function Math3DMat4 (line 19253) | function Math3DMat4()
function Math3DOperation (line 19316) | function Math3DOperation() {
function Math3DVec3Scale (line 19426) | function Math3DVec3Scale() {
function Math3DVec3Length (line 19456) | function Math3DVec3Length() {
function Math3DVec3Normalize (line 19475) | function Math3DVec3Normalize() {
function Math3DVec3Lerp (line 19500) | function Math3DVec3Lerp() {
function Math3DVec3Dot (line 19533) | function Math3DVec3Dot() {
function Math3DQuaternion (line 19560) | function Math3DQuaternion() {
function Math3DRotation (line 19591) | function Math3DRotation() {
function MathEulerToQuat (line 19619) | function MathEulerToQuat() {
function MathQuatToEuler (line 19644) | function MathQuatToEuler() {
function Math3DRotateVec3 (line 19666) | function Math3DRotateVec3() {
function Math3DMultQuat (line 19693) | function Math3DMultQuat() {
function Math3DQuatSlerp (line 19719) | function Math3DQuatSlerp() {
function Math3DRemapRange (line 19756) | function Math3DRemapRange() {
function toString (line 19827) | function toString(a) {
function compare (line 19844) | function compare(a, b) {
function concatenate (line 19855) | function concatenate(a, b) {
function contains (line 19872) | function contains(a, b) {
function toUpperCase (line 19886) | function toUpperCase(a) {
function split (line 19900) | function split(str, separator) {
function toFixed (line 19927) | function toFixed(a) {
function StringToTable (line 19943) | function StringToTable() {
function Selector (line 19977) | function Selector() {
function Sequence (line 20021) | function Sequence() {
function logicAnd (line 20060) | function logicAnd(){
function logicOr (line 20086) | function logicOr(){
function logicNot (line 20112) | function logicNot(){
function logicCompare (line 20126) | function logicCompare(){
function logicBranch (line 20155) | function logicBranch(){
function GraphicsPlot (line 20179) | function GraphicsPlot() {
function GraphicsImage (line 20253) | function GraphicsImage() {
function ColorPalette (line 20351) | function ColorPalette() {
function ImageFrame (line 20426) | function ImageFrame() {
function ImageFade (line 20477) | function ImageFade() {
function ImageCrop (line 20536) | function ImageCrop() {
function CanvasNode (line 20619) | function CanvasNode() {
function DrawImageNode (line 20656) | function DrawImageNode() {
function DrawRectangleNode (line 20686) | function DrawRectangleNode() {
function ImageVideo (line 20721) | function ImageVideo() {
function ImageWebcam (line 20910) | function ImageWebcam() {
function onFailSoHard (line 20940) | function onFailSoHard(e) {
function LGraphTexture (line 21085) | function LGraphTexture() {
function LGraphTexturePreview (line 21464) | function LGraphTexturePreview() {
function LGraphTextureSave (line 21513) | function LGraphTextureSave() {
function LGraphTextureOperation (line 21560) | function LGraphTextureOperation() {
function LGraphTextureShader (line 21824) | function LGraphTextureShader() {
function LGraphTextureScaleOffset (line 22040) | function LGraphTextureScaleOffset() {
function LGraphTextureWarp (line 22157) | function LGraphTextureWarp() {
function LGraphTextureToViewport (line 22290) | function LGraphTextureToViewport() {
function LGraphTextureCopy (line 22477) | function LGraphTextureCopy() {
function LGraphTextureDownsample (line 22562) | function LGraphTextureDownsample() {
function LGraphTextureResize (line 22690) | function LGraphTextureResize() {
function LGraphTextureAverage (line 22752) | function LGraphTextureAverage() {
function LGraphTextureMinMax (line 22908) | function LGraphTextureMinMax() {
function LGraphTextureTemporalSmooth (line 23034) | function LGraphTextureTemporalSmooth() {
function LGraphTextureLinearAvgSmooth (line 23116) | function LGraphTextureLinearAvgSmooth() {
function LGraphImageToTexture (line 23242) | function LGraphImageToTexture() {
function LGraphTextureLUT (line 23294) | function LGraphTextureLUT() {
function LGraphTextureEncode (line 23414) | function LGraphTextureEncode() {
function LGraphTextureChannels (line 23537) | function LGraphTextureChannels() {
function LGraphChannelsTexture (line 23644) | function LGraphChannelsTexture() {
function LGraphTextureColor (line 23761) | function LGraphTextureColor() {
function LGraphTextureGradient (line 23860) | function LGraphTextureGradient() {
function LGraphTextureMix (line 23973) | function LGraphTextureMix() {
function LGraphTextureEdges (line 24092) | function LGraphTextureEdges() {
function LGraphTextureDepthRange (line 24195) | function LGraphTextureDepthRange() {
function LGraphTextureLinearDepth (line 24337) | function LGraphTextureLinearDepth() {
function LGraphTextureBlur (line 24433) | function LGraphTextureBlur() {
function FXGlow (line 24556) | function FXGlow()
function LGraphTextureGlow (line 24787) | function LGraphTextureGlow() {
function LGraphTextureKuwaharaFilter (line 24947) | function LGraphTextureKuwaharaFilter() {
function LGraphTextureXDoGFilter (line 25137) | function LGraphTextureXDoGFilter() {
function LGraphTextureWebcam (line 25277) | function LGraphTextureWebcam() {
function onFailSoHard (line 25308) | function onFailSoHard(e) {
function LGraphLensFX (line 25466) | function LGraphLensFX() {
function LGraphTextureFromData (line 25604) | function LGraphTextureFromData() {
function LGraphTextureCurve (line 25652) | function LGraphTextureCurve() {
function LGraphExposition (line 25868) | function LGraphExposition() {
function LGraphToneMapping (line 25946) | function LGraphToneMapping() {
function LGraphTexturePerlin (line 26110) | function LGraphTexturePerlin() {
function LGraphTextureCanvas2D (line 26296) | function LGraphTextureCanvas2D() {
function LGraphTextureMatte (line 26440) | function LGraphTextureMatte() {
function LGraphCubemapToTexture2D (line 26535) | function LGraphCubemapToTexture2D() {
function parseGLSLDescriptions (line 26623) | function parseGLSLDescriptions()
function registerShaderNode (line 26649) | function registerShaderNode( type, node_ctor )
function getShaderNodeVarName (line 26708) | function getShaderNodeVarName( node, name )
function getInputLinkID (line 26713) | function getInputLinkID( node, slot )
function getOutputLinkID (line 26729) | function getOutputLinkID( node, slot )
function LGShaderContext (line 26892) | function LGShaderContext()
function LGraphShaderGraph (line 27089) | function LGraphShaderGraph() {
function shaderNodeFromFunction (line 27325) | function shaderNodeFromFunction( classname, params, return_type, code )
function LGraphShaderUniform (line 27333) | function LGraphShaderUniform() {
function LGraphShaderAttribute (line 27387) | function LGraphShaderAttribute() {
function LGraphShaderSampler2D (line 27426) | function LGraphShaderSampler2D() {
function LGraphShaderConstant (line 27467) | function LGraphShaderConstant()
function LGraphShaderVec2 (line 27569) | function LGraphShaderVec2()
function LGraphShaderVec3 (line 27625) | function LGraphShaderVec3()
function LGraphShaderVec4 (line 27690) | function LGraphShaderVec4()
function LGraphShaderFragColor (line 27760) | function LGraphShaderFragColor() {
function LGraphShaderOperation (line 27812) | function LGraphShaderOperation()
function LGraphShaderFunc (line 27885) | function LGraphShaderFunc()
function LGraphShaderSnippet (line 27986) | function LGraphShaderSnippet()
function LGraphShaderRand (line 28063) | function LGraphShaderRand()
function LGraphShaderNoise (line 28086) | function LGraphShaderNoise()
function LGraphShaderTime (line 28267) | function LGraphShaderTime()
function LGraphShaderDither (line 28289) | function LGraphShaderDither()
function LGraphShaderRemap (line 28333) | function LGraphShaderRemap()
function generateGeometryId (line 28420) | function generateGeometryId() {
function LGraphPoints3D (line 28424) | function LGraphPoints3D() {
function findRandomTriangle (line 28756) | function findRandomTriangle( areas, f )
function LGraphPointsToInstances (line 28911) | function LGraphPointsToInstances() {
function LGraphGeometryTransform (line 29050) | function LGraphGeometryTransform() {
function LGraphGeometryPolygon (line 29175) | function LGraphGeometryPolygon() {
function LGraphGeometryExtrude (line 29249) | function LGraphGeometryExtrude() {
function LGraphGeometryEval (line 29338) | function LGraphGeometryEval() {
function LGraphConnectPoints (line 29526) | function LGraphConnectPoints() {
function LGraphToGeometry (line 29615) | function LGraphToGeometry() {
function LGraphGeometryToMesh (line 29653) | function LGraphGeometryToMesh() {
function LGraphRenderMesh (line 29722) | function LGraphRenderMesh() {
function LGraphGeometryPrimitive (line 29826) | function LGraphGeometryPrimitive() {
function LGraphRenderPoints (line 29900) | function LGraphRenderPoints() {
function LGraphFXLens (line 30319) | function LGraphFXLens() {
function LGraphFXBokeh (line 30560) | function LGraphFXBokeh() {
function LGraphFXGeneric (line 30806) | function LGraphFXGeneric() {
function LGraphFXVigneting (line 31006) | function LGraphFXVigneting() {
function MIDIEvent (line 31105) | function MIDIEvent(data) {
function MIDIInterface (line 31432) | function MIDIInterface(on_ready, on_error) {
function LGMIDIIn (line 31567) | function LGMIDIIn() {
function LGMIDIOut (line 31693) | function LGMIDIOut() {
function LGMIDIShow (line 31762) | function LGMIDIShow() {
function LGMIDIFilter (line 31809) | function LGMIDIFilter() {
function LGMIDIEvent (line 31917) | function LGMIDIEvent() {
function LGMIDICC (line 32091) | function LGMIDICC() {
function LGMIDIGenerator (line 32116) | function LGMIDIGenerator() {
function LGMIDITranspose (line 32207) | function LGMIDITranspose() {
function LGMIDIQuantize (line 32251) | function LGMIDIQuantize() {
function LGMIDIFromFile (line 32328) | function LGMIDIFromFile() {
function LGMIDIPlay (line 32444) | function LGMIDIPlay() {
function LGMIDIKeys (line 32503) | function LGMIDIKeys() {
function now (line 32683) | function now() {
function onError (line 32922) | function onError(err) {
function LGAudioSource (line 32934) | function LGAudioSource() {
function inner (line 33137) | function inner(buffer) {
function LGAudioMediaSource (line 33180) | function LGAudioMediaSource() {
function onFailSoHard (line 33253) | function onFailSoHard(err) {
function LGAudioAnalyser (line 33331) | function LGAudioAnalyser() {
function LGAudioGain (line 33416) | function LGAudioGain() {
function LGAudioConvolver (line 33448) | function LGAudioConvolver() {
function inner (line 33506) | function inner(buffer) {
function LGAudioDynamicsCompressor (line 33518) | function LGAudioDynamicsCompressor() {
function LGAudioWaveShaper (line 33570) | function LGAudioWaveShaper() {
function LGAudioMixer (line 33603) | function LGAudioMixer() {
function LGAudioADSR (line 33675) | function LGAudioADSR() {
function LGAudioDelay (line 33733) | function LGAudioDelay() {
function LGAudioBiquadFilter (line 33759) | function LGAudioBiquadFilter() {
function LGAudioOscillatorNode (line 33814) | function LGAudioOscillatorNode() {
function LGAudioVisualization (line 33891) | function LGAudioVisualization() {
function LGAudioBandSignal (line 33963) | function LGAudioBandSignal() {
function LGAudioScript (line 34014) | function LGAudioScript() {
function LGAudioDestination (line 34135) | function LGAudioDestination() {
function LGWebSocket (line 34149) | function LGWebSocket() {
function LGSillyClient (line 34297) | function LGSillyClient() {
function HTTPRequestNode (line 34511) | function HTTPRequestNode() {
FILE: build/litegraph_mini.js
function LGraph (line 837) | function LGraph(o) {
function on_frame (line 997) | function on_frame() {
function LLink (line 2378) | function LLink(id, type, origin_id, origin_slot, target_id, target_slot) {
function LGraphNode (line 2482) | function LGraphNode(title) {
function compute_text_size (line 3742) | function compute_text_size(text) {
function LGraphGroup (line 4992) | function LGraphGroup(title) {
function DragAndScale (line 5095) | function DragAndScale(element, skip_events) {
function LGraphCanvas (line 5327) | function LGraphCanvas(canvas, graph, options) {
function renderFrame (line 5891) | function renderFrame() {
function inner_clicked (line 10205) | function inner_clicked(v, option, event) {
function inner_value_change (line 10277) | function inner_value_change(widget, value) {
function inner_clicked (line 10577) | function inner_clicked(value) {
function inner_clicked (line 10589) | function inner_clicked(value) {
function inner_onMenuAdded (line 10602) | function inner_onMenuAdded(base_category ,prev_menu){
function inner_clicked (line 10734) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10839) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10938) | function inner_clicked(v, options, e, prev) {
function inner_clicked (line 10999) | function inner_clicked(v,options,e) {
function inner_clicked (line 11256) | function inner_clicked(v,options,e) {
function inner (line 11370) | function inner() {
function setValue (line 11374) | function setValue(value) {
function select (line 11754) | function select(name) {
function changeSelection (line 11872) | function changeSelection(forward) {
function refreshHelper (line 11896) | function refreshHelper() {
function inner (line 12179) | function inner() {
function setValue (line 12183) | function setValue(value) {
function inner_clicked (line 12478) | function inner_clicked(v, option, event) {
function innerChange (line 12490) | function innerChange(name, value)
function inner_refresh (line 12572) | function inner_refresh(){
function inner_refresh (line 12651) | function inner_refresh()
function inner_refresh (line 12792) | function inner_refresh()
function inner_refresh (line 12848) | function inner_refresh() {
function addOutput (line 12880) | function addOutput() {
function inner_clicked (line 12940) | function inner_clicked(v) {
function inner_clicked (line 13001) | function inner_clicked(v) {
function inner_clicked (line 13048) | function inner_clicked(v) {
function inner_option_clicked (line 13449) | function inner_option_clicked(v, options, e) {
function compareObjects (line 13521) | function compareObjects(a, b) {
function distance (line 13531) | function distance(a, b) {
function colorToString (line 13538) | function colorToString(c) {
function isInsideRectangle (line 13553) | function isInsideRectangle(x, y, left, top, width, height) {
function growBounding (line 13562) | function growBounding(bounding, x, y) {
function isInsideBounding (line 13578) | function isInsideBounding(p, bb) {
function overlapBounding (line 13592) | function overlapBounding(a, b) {
function hex2num (line 13613) | function hex2num(hex) {
function num2hex (line 13635) | function num2hex(triplet) {
function ContextMenu (line 13664) | function ContextMenu(values, options) {
function inner_over (line 13897) | function inner_over(e) {
function inner_onclick (line 13907) | function inner_onclick(e) {
function CurveEditor (line 14119) | function CurveEditor( points )
function clamp (line 14401) | function clamp(v, a, b) {
function Time (line 14433) | function Time() {
function Subgraph (line 14449) | function Subgraph() {
function GraphInput (line 14911) | function GraphInput() {
function GraphOutput (line 15072) | function GraphOutput() {
function ConstantNumber (line 15205) | function ConstantNumber() {
function ConstantBoolean (line 15239) | function ConstantBoolean() {
function ConstantString (line 15269) | function ConstantString() {
function ConstantObject (line 15301) | function ConstantObject() {
function ConstantFile (line 15316) | function ConstantFile() {
function JSONParse (line 15416) | function JSONParse() {
function ConstantData (line 15457) | function ConstantData() {
function ConstantArray (line 15492) | function ConstantArray() {
function SetArray (line 15541) | function SetArray()
function ArrayElement (line 15567) | function ArrayElement() {
function TableElement (line 15589) | function TableElement() {
function ObjectProperty (line 15620) | function ObjectProperty() {
function ObjectKeys (line 15658) | function ObjectKeys() {
function SetObject (line 15677) | function SetObject()
function MergeObjects (line 15704) | function MergeObjects() {
function Variable (line 15735) | function Variable() {
function length (line 15791) | function length(v) {
function length (line 15804) | function length(v) {
function DownloadData (line 15817) | function DownloadData() {
function Watch (line 15880) | function Watch() {
function Cast (line 15927) | function Cast() {
function Console (line 15943) | function Console() {
function Alert (line 15989) | function Alert() {
function NodeScript (line 16017) | function NodeScript() {
function GenericCompare (line 16101) | function GenericCompare() {
function LogEvent (line 16204) | function LogEvent() {
function TriggerEvent (line 16219) | function TriggerEvent() {
function Sequence (line 16250) | function Sequence() {
function WaitAll (line 16292) | function WaitAll() {
function Stepper (line 16349) | function Stepper() {
function FilterEvent (line 16416) | function FilterEvent() {
function EventBranch (line 16459) | function EventBranch() {
function EventCounter (line 16483) | function EventCounter() {
function DelayEvent (line 16538) | function DelayEvent() {
function TimerEvent (line 16589) | function TimerEvent() {
function SemaphoreEvent (line 16660) | function SemaphoreEvent() {
function OnceEvent (line 16695) | function OnceEvent() {
function DataStore (line 16722) | function DataStore() {
function GamepadInput (line 16764) | function GamepadInput() {
function Converter (line 17120) | function Converter() {
function Bypass (line 17195) | function Bypass() {
function ToNumber (line 17211) | function ToNumber() {
function MathRange (line 17226) | function MathRange() {
function MathRand (line 17309) | function MathRand() {
function MathNoise (line 17349) | function MathNoise() {
function MathSpikes (line 17419) | function MathSpikes() {
function MathClamp (line 17460) | function MathClamp() {
function MathLerp (line 17498) | function MathLerp() {
function MathAbs (line 17536) | function MathAbs() {
function MathFloor (line 17556) | function MathFloor() {
function MathFrac (line 17576) | function MathFrac() {
function MathSmoothStep (line 17596) | function MathSmoothStep() {
function MathScale (line 17626) | function MathScale() {
function Gate (line 17646) | function Gate() {
function MathAverageFilter (line 17665) | function MathAverageFilter() {
function MathTendTo (line 17717) | function MathTendTo() {
function MathOperation (line 17745) | function MathOperation() {
function MathCompare (line 17874) | function MathCompare() {
function MathCondition (line 17969) | function MathCondition() {
function MathBranch (line 18046) | function MathBranch() {
function MathAccumulate (line 18076) | function MathAccumulate() {
function MathTrigonometry (line 18103) | function MathTrigonometry() {
function MathFormula (line 18190) | function MathFormula() {
function Math3DVec2ToXY (line 18272) | function Math3DVec2ToXY() {
function Math3DXYToVec2 (line 18293) | function Math3DXYToVec2() {
function Math3DVec3ToXYZ (line 18322) | function Math3DVec3ToXYZ() {
function Math3DXYZToVec3 (line 18345) | function Math3DXYZToVec3() {
function Math3DVec4ToXYZW (line 18379) | function Math3DVec4ToXYZW() {
function Math3DXYZWToVec4 (line 18404) | function Math3DXYZWToVec4() {
function toString (line 18454) | function toString(a) {
function compare (line 18471) | function compare(a, b) {
function concatenate (line 18482) | function concatenate(a, b) {
function contains (line 18499) | function contains(a, b) {
function toUpperCase (line 18513) | function toUpperCase(a) {
function split (line 18527) | function split(str, separator) {
function toFixed (line 18554) | function toFixed(a) {
function StringToTable (line 18570) | function StringToTable() {
function Selector (line 18604) | function Selector() {
function Sequence (line 18648) | function Sequence() {
function logicAnd (line 18687) | function logicAnd(){
function logicOr (line 18713) | function logicOr(){
function logicNot (line 18739) | function logicNot(){
function logicCompare (line 18753) | function logicCompare(){
function logicBranch (line 18782) | function logicBranch(){
function LGWebSocket (line 18807) | function LGWebSocket() {
function LGSillyClient (line 18955) | function LGSillyClient() {
function HTTPRequestNode (line 19169) | function HTTPRequestNode() {
FILE: csharp/LiteGraph.cs
type DataType (line 11) | public enum DataType { NONE, ENUM, NUMBER, STRING, BOOL, VEC2, VEC3 };
type vec2 (line 13) | public struct vec2 {
type vec3 (line 18) | public struct vec3
class MutableType (line 26) | public class MutableType {
method Set (line 39) | public void Set(bool v) { type = DataType.BOOL; data_bool = v; }
method Set (line 40) | public void Set(int v) { type = DataType.ENUM; data_number = v; }
method Set (line 41) | public void Set(float v) { type = DataType.NUMBER; data_number = v; }
method Set (line 42) | public void Set(string v) { type = DataType.STRING; data_string = v; }
method Set (line 43) | public void Set(vec2 v) { type = DataType.VEC2; data_vec2 = v; }
method Set (line 44) | public void Set(vec3 v) { type = DataType.VEC3; data_vec3 = v; }
method ToString (line 45) | public override string ToString() {
class LLink (line 61) | public class LLink {
method LLink (line 76) | public LLink(int id, DataType type, int origin_id, int origin_slot, in...
method setData (line 86) | public void setData(bool data)
method setData (line 92) | public void setData(float data)
method setData (line 98) | public void setData(string data)
method setData (line 104) | public void setData(vec2 data)
method setData (line 110) | public void setData(vec3 data)
class LSlot (line 119) | public class LSlot
method LSlot (line 127) | public LSlot(string name, DataType type)
class LGraphNode (line 135) | public class LGraphNode {
method LGraphNode (line 144) | public LGraphNode()
method addInput (line 148) | public virtual LSlot addInput(string name, DataType type = DataType.NONE)
method addOutput (line 156) | public virtual LSlot addOutput(string name, DataType type = DataType.N...
method getInputData (line 164) | public virtual bool getInputData(int slot_num, bool default_value)
method getInputData (line 172) | public virtual float getInputData(int slot_num, float default_value )
method getInputData (line 180) | public virtual string getInputData(int slot_num, string default_value)
method getInputData (line 188) | public virtual vec2 getInputData(int slot_num, vec2 default_value)
method getInputData (line 196) | public virtual vec3 getInputData(int slot_num, vec3 default_value)
method setOutputData (line 204) | public virtual void setOutputData(int slot_num, bool v)
method setOutputData (line 220) | public virtual void setOutputData(int slot_num, float v)
method setOutputData (line 236) | public virtual void setOutputData(int slot_num, string v)
method setOutputData (line 252) | public virtual void setOutputData(int slot_num, vec2 v)
method setOutputData (line 268) | public virtual void setOutputData(int slot_num, vec3 v)
method transferData (line 284) | public virtual void transferData(int input_slot_num, int output_slot_num)
method connect (line 311) | public virtual bool connect(int origin_slot, LGraphNode target, int ta...
method onExecute (line 337) | public virtual void onExecute()
method configure (line 341) | public virtual void configure(JSONNode json_node)
method onConfigure (line 412) | public virtual void onConfigure(JSONNode json_node)
class Globals (line 419) | public class Globals
method registerType (line 424) | static public void registerType(string name, Func<LGraphNode> ctor )
method createNodeType (line 428) | static public LGraphNode createNodeType(string name)
class LGraph (line 442) | public class LGraph
method LGraph (line 458) | public LGraph()
method add (line 462) | public void add(LGraphNode node)
method clear (line 474) | public void clear()
method runStep (line 488) | public void runStep(float dt = 0)
method configure (line 498) | public void configure(string data)
method sortByExecutionOrder (line 503) | public void sortByExecutionOrder()
method fromJSONText (line 513) | public void fromJSONText(string text)
method getOutput (line 562) | public float getOutput(string name, float def_value)
class Main (line 571) | public class Main
method Init (line 573) | public static void Init()
method loadNodes (line 578) | public static void loadNodes()
method test (line 590) | public static void test()
FILE: csharp/LiteGraphNodes.cs
class ConstNumberNode (line 10) | public class ConstNumberNode : LGraphNode
method ConstNumberNode (line 16) | public ConstNumberNode()
method onExecute (line 21) | override public void onExecute()
method onConfigure (line 26) | override public void onConfigure( JSONNode o)
class RandomNumberNode (line 33) | public class RandomNumberNode : LGraphNode
method RandomNumberNode (line 41) | public RandomNumberNode()
method onExecute (line 46) | override public void onExecute()
method onConfigure (line 51) | override public void onConfigure(JSONNode o)
class GraphOutputNode (line 59) | public class GraphOutputNode : LGraphNode
method GraphOutputNode (line 66) | public GraphOutputNode()
method onExecute (line 71) | override public void onExecute()
method onConfigure (line 82) | override public void onConfigure(JSONNode o)
class ConditionNode (line 98) | public class ConditionNode : LGraphNode
type OPERATION (line 102) | public enum OPERATION { NONE,GREATER,LOWER,EQUAL,NEQUAL,GEQUAL,LEQUAL,...
method ConditionNode (line 109) | public ConditionNode()
method onExecute (line 116) | override public void onExecute()
method onConfigure (line 137) | override public void onConfigure(JSONNode o)
class GateNode (line 151) | public class GateNode : LGraphNode
method GateNode (line 155) | public GateNode()
method onExecute (line 163) | override public void onExecute()
class TimeNode (line 170) | public class TimeNode : LGraphNode
method TimeNode (line 174) | public TimeNode()
method onExecute (line 180) | override public void onExecute()
class WatchNode (line 188) | public class WatchNode : LGraphNode
method WatchNode (line 192) | public WatchNode()
method onExecute (line 197) | override public void onExecute()
FILE: csharp/LiteGraphTest.cs
class LiteGraphTest (line 8) | public class LiteGraphTest : MonoBehaviour
method Start (line 19) | void Start()
method Update (line 47) | void Update()
FILE: csharp/SimpleJSON.cs
type JSONNodeType (line 138) | public enum JSONNodeType
type JSONTextMode (line 149) | public enum JSONTextMode
class JSONNode (line 155) | public abstract partial class JSONNode
type Enumerator (line 158) | public struct Enumerator
type Type (line 160) | private enum Type { None, Array, Object }
method Enumerator (line 165) | public Enumerator(List<JSONNode>.Enumerator aArrayEnum)
method Enumerator (line 171) | public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
method MoveNext (line 187) | public bool MoveNext()
type ValueEnumerator (line 196) | public struct ValueEnumerator
method ValueEnumerator (line 199) | public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(...
method ValueEnumerator (line 200) | public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDict...
method ValueEnumerator (line 201) | public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnu...
method MoveNext (line 203) | public bool MoveNext() { return m_Enumerator.MoveNext(); }
method GetEnumerator (line 204) | public ValueEnumerator GetEnumerator() { return this; }
type KeyEnumerator (line 206) | public struct KeyEnumerator
method KeyEnumerator (line 209) | public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(ne...
method KeyEnumerator (line 210) | public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEn...
method KeyEnumerator (line 211) | public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnume...
method MoveNext (line 213) | public bool MoveNext() { return m_Enumerator.MoveNext(); }
method GetEnumerator (line 214) | public KeyEnumerator GetEnumerator() { return this; }
class LinqEnumerator (line 217) | public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNod...
method LinqEnumerator (line 221) | internal LinqEnumerator(JSONNode aNode)
method MoveNext (line 229) | public bool MoveNext() { return m_Enumerator.MoveNext(); }
method Dispose (line 231) | public void Dispose()
method GetEnumerator (line 237) | public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()
method Reset (line 242) | public void Reset()
method GetEnumerator (line 248) | IEnumerator IEnumerable.GetEnumerator()
method Add (line 281) | public virtual void Add(string aKey, JSONNode aItem)
method Add (line 284) | public virtual void Add(JSONNode aItem)
method Remove (line 289) | public virtual JSONNode Remove(string aKey)
method Remove (line 294) | public virtual JSONNode Remove(int aIndex)
method Remove (line 299) | public virtual JSONNode Remove(JSONNode aNode)
method HasKey (line 322) | public virtual bool HasKey(string aKey)
method GetValueOrDefault (line 327) | public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
method ToString (line 332) | public override string ToString()
method ToString (line 339) | public virtual string ToString(int aIndent)
method WriteToStringBuilder (line 345) | internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIn...
method GetEnumerator (line 347) | public abstract Enumerator GetEnumerator();
method Equals (line 512) | public override bool Equals(object obj)
method GetHashCode (line 517) | public override int GetHashCode()
method Escape (line 534) | internal static string Escape(string aText)
method ParseElement (line 581) | private static JSONNode ParseElement(string token, bool quoted)
method Parse (line 597) | public static JSONNode Parse(string aJSON)
class JSONArray (line 770) | public partial class JSONArray : JSONNode
method GetEnumerator (line 782) | public override Enumerator GetEnumerator() { return new Enumerator(m_L...
method Add (line 819) | public override void Add(string aKey, JSONNode aItem)
method Remove (line 826) | public override JSONNode Remove(int aIndex)
method Remove (line 835) | public override JSONNode Remove(JSONNode aNode)
method WriteToStringBuilder (line 851) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
class JSONObject (line 875) | public partial class JSONObject : JSONNode
method GetEnumerator (line 889) | public override Enumerator GetEnumerator() { return new Enumerator(m_D...
method Add (line 936) | public override void Add(string aKey, JSONNode aItem)
method Remove (line 952) | public override JSONNode Remove(string aKey)
method Remove (line 961) | public override JSONNode Remove(int aIndex)
method Remove (line 970) | public override JSONNode Remove(JSONNode aNode)
method HasKey (line 984) | public override bool HasKey(string aKey)
method GetValueOrDefault (line 989) | public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefa...
method WriteToStringBuilder (line 1006) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
class JSONString (line 1036) | public partial class JSONString : JSONNode
method GetEnumerator (line 1043) | public override Enumerator GetEnumerator() { return new Enumerator(); }
method JSONString (line 1055) | public JSONString(string aData)
method WriteToStringBuilder (line 1060) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
method Equals (line 1064) | public override bool Equals(object obj)
method GetHashCode (line 1076) | public override int GetHashCode()
class JSONNumber (line 1083) | public partial class JSONNumber : JSONNode
method GetEnumerator (line 1089) | public override Enumerator GetEnumerator() { return new Enumerator(); }
method JSONNumber (line 1113) | public JSONNumber(double aData)
method JSONNumber (line 1118) | public JSONNumber(string aData)
method WriteToStringBuilder (line 1123) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
method IsNumeric (line 1127) | private static bool IsNumeric(object value)
method Equals (line 1136) | public override bool Equals(object obj)
method GetHashCode (line 1149) | public override int GetHashCode()
class JSONBool (line 1156) | public partial class JSONBool : JSONNode
method GetEnumerator (line 1162) | public override Enumerator GetEnumerator() { return new Enumerator(); }
method JSONBool (line 1180) | public JSONBool(bool aData)
method JSONBool (line 1185) | public JSONBool(string aData)
method WriteToStringBuilder (line 1190) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
method Equals (line 1194) | public override bool Equals(object obj)
method GetHashCode (line 1202) | public override int GetHashCode()
class JSONNull (line 1209) | public partial class JSONNull : JSONNode
method CreateOrGet (line 1213) | public static JSONNull CreateOrGet()
method JSONNull (line 1219) | private JSONNull() { }
method GetEnumerator (line 1223) | public override Enumerator GetEnumerator() { return new Enumerator(); }
method Equals (line 1236) | public override bool Equals(object obj)
method GetHashCode (line 1242) | public override int GetHashCode()
method WriteToStringBuilder (line 1247) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
class JSONLazyCreator (line 1254) | internal partial class JSONLazyCreator : JSONNode
method GetEnumerator (line 1259) | public override Enumerator GetEnumerator() { return new Enumerator(); }
method JSONLazyCreator (line 1261) | public JSONLazyCreator(JSONNode aNode)
method JSONLazyCreator (line 1267) | public JSONLazyCreator(JSONNode aNode, string aKey)
method Set (line 1273) | private T Set<T>(T aVal) where T : JSONNode
method Add (line 1295) | public override void Add(JSONNode aItem)
method Add (line 1300) | public override void Add(string aKey, JSONNode aItem)
method Equals (line 1317) | public override bool Equals(object obj)
method GetHashCode (line 1324) | public override int GetHashCode()
method WriteToStringBuilder (line 1381) | internal override void WriteToStringBuilder(StringBuilder aSB, int aIn...
class JSON (line 1388) | public static class JSON
method Parse (line 1390) | public static JSONNode Parse(string aJSON)
FILE: doc/assets/js/api-list.js
function getFilterResultNode (line 100) | function getFilterResultNode() {
function onFilterResults (line 107) | function onFilterResults(e) {
function onSearchClear (line 137) | function onSearchClear(e) {
function onSearchKey (line 142) | function onSearchKey(e) {
function onSearchResults (line 156) | function onSearchResults(e) {
function onTabSelectionChange (line 176) | function onTabSelectionChange(e) {
function onTabSwitchKey (line 227) | function onTabSwitchKey(e) {
FILE: doc/assets/js/apidocs.js
function scrollToNode (line 200) | function scrollToNode() {
FILE: doc/assets/vendor/prettify/prettify-min.js
function l (line 1) | function l(ab){var af=0;var U=false;var ae=false;for(var X=0,W=ab.length...
function b (line 1) | function b(aa,Y){var W=/(?:^|\s)nocode(?:\s|$)/;var ab=[];var Z=0;var X=...
function C (line 1) | function C(U,W,Y,V){if(!W){return}var X={sourceCode:W,basePos:U};Y(X);V....
function p (line 1) | function p(U){var X=undefined;for(var W=U.firstChild;W;W=W.nextSibling){...
function h (line 1) | function h(W,V){var U={};var X;(function(){var af=W.concat(V);var aj=[];...
function i (line 1) | function i(V){var Y=[],U=[];if(V.tripleQuotedStrings){Y.push([D,/^(?:\'\...
function S (line 1) | function S(W,ah,aa){var V=/(?:^|\s)nocode(?:\s|$)/;var ac=/\r\n?|\n/;var...
function E (line 1) | function E(af){var X=/\bMSIE\s(\d+)/.exec(navigator.userAgent);X=X&&+X[1...
function d (line 1) | function d(W,X){for(var U=X.length;--U>=0;){var V=X[U];if(!u.hasOwnPrope...
function r (line 1) | function r(V,U){if(!(V&&u.hasOwnProperty(V))){V=/^\s*</.test(U)?"default...
function e (line 1) | function e(X){var W=X.langExtension;try{var U=b(X.sourceNode,X.pre);var ...
function z (line 1) | function z(Y,X,W){var U=document.createElement("pre");U.innerHTML=Y;if(W...
function c (line 1) | function c(aj){function ab(al){return document.getElementsByTagName(al)}...
FILE: editor/js/code.js
function updateEditorHiPPICanvas (line 19) | function updateEditorHiPPICanvas() {
function addDemo (line 88) | function addDemo( name, url )
function enableWebGL (line 117) | function enableWebGL()
FILE: editor/js/demos.js
function demo (line 2) | function demo()
function multiConnection (line 7) | function multiConnection()
function CopyPasteWithConnectionToUnselectedOutputTest (line 46) | function CopyPasteWithConnectionToUnselectedOutputTest()
function sortTest (line 91) | function sortTest()
function benchmark (line 110) | function benchmark()
function TestWidgetsNode (line 128) | function TestWidgetsNode()
function TestSpecialNode (line 151) | function TestSpecialNode()
function TestSlotsNode (line 235) | function TestSlotsNode()
function TestPropertyEditorsNode (line 251) | function TestPropertyEditorsNode()
function LargeInputNode (line 278) | function LargeInputNode()
FILE: editor/js/libs/gl-matrix-min.js
function r (line 28) | function r(a){if(n[a])return n[a].exports;var e=n[a]={i:a,l:!1,exports:{...
function e (line 28) | function e(){var t=new a.ARRAY_TYPE(4);return a.ARRAY_TYPE!=Float32Array...
function u (line 28) | function u(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t[2]=n[2]-r[2],t[...
function o (line 28) | function o(t,n,r){return t[0]=n[0]*r[0],t[1]=n[1]*r[1],t[2]=n[2]*r[2],t[...
function i (line 28) | function i(t,n,r){return t[0]=n[0]/r[0],t[1]=n[1]/r[1],t[2]=n[2]/r[2],t[...
function s (line 28) | function s(t,n){var r=n[0]-t[0],a=n[1]-t[1],e=n[2]-t[2],u=n[3]-t[3];retu...
function c (line 28) | function c(t,n){var r=n[0]-t[0],a=n[1]-t[1],e=n[2]-t[2],u=n[3]-t[3];retu...
function f (line 28) | function f(t){var n=t[0],r=t[1],a=t[2],e=t[3];return Math.sqrt(n*n+r*r+a...
function M (line 28) | function M(t){var n=t[0],r=t[1],a=t[2],e=t[3];return n*n+r*r+a*a+e*e}
function e (line 28) | function e(){var t=new a.ARRAY_TYPE(3);return a.ARRAY_TYPE!=Float32Array...
function u (line 28) | function u(t){var n=t[0],r=t[1],a=t[2];return Math.sqrt(n*n+r*r+a*a)}
function o (line 28) | function o(t,n,r){var e=new a.ARRAY_TYPE(3);return e[0]=t,e[1]=n,e[2]=r,e}
function i (line 28) | function i(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t[2]=n[2]-r[2],t}
function s (line 28) | function s(t,n,r){return t[0]=n[0]*r[0],t[1]=n[1]*r[1],t[2]=n[2]*r[2],t}
function c (line 28) | function c(t,n,r){return t[0]=n[0]/r[0],t[1]=n[1]/r[1],t[2]=n[2]/r[2],t}
function f (line 28) | function f(t,n){var r=n[0]-t[0],a=n[1]-t[1],e=n[2]-t[2];return Math.sqrt...
function M (line 28) | function M(t,n){var r=n[0]-t[0],a=n[1]-t[1],e=n[2]-t[2];return r*r+a*a+e*e}
function h (line 28) | function h(t){var n=t[0],r=t[1],a=t[2];return n*n+r*r+a*a}
function l (line 28) | function l(t,n){var r=n[0],a=n[1],e=n[2],u=r*r+a*a+e*e;return u>0&&(u=1/...
function v (line 28) | function v(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}
function i (line 28) | function i(t){if(t&&t.__esModule)return t;var n={};if(null!=t)for(var r ...
function s (line 28) | function s(){var t=new a.ARRAY_TYPE(4);return a.ARRAY_TYPE!=Float32Array...
function c (line 28) | function c(t,n,r){r*=.5;var a=Math.sin(r);return t[0]=a*n[0],t[1]=a*n[1]...
function f (line 28) | function f(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=r[0],s=r[1],c=r[2],f...
function M (line 28) | function M(t,n,r,e){var u=n[0],o=n[1],i=n[2],s=n[3],c=r[0],f=r[1],M=r[2]...
function h (line 28) | function h(t,n){var r=n[0]+n[4]+n[8],a=void 0;if(r>0)a=Math.sqrt(r+1),t[...
function e (line 28) | function e(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[...
function u (line 28) | function u(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=n[4],s=n[5],c=n[6],f...
function o (line 28) | function o(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=a+a,s=e+e,c=u+u,f=a*...
function i (line 28) | function i(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t[2]=n[2]-r[2],t[...
function e (line 28) | function e(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=n[4],s=n[5],c=n[6],f...
function u (line 28) | function u(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t[2]=n[2]-r[2],t[...
function e (line 28) | function e(){var t=new a.ARRAY_TYPE(2);return a.ARRAY_TYPE!=Float32Array...
function u (line 28) | function u(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t}
function o (line 28) | function o(t,n,r){return t[0]=n[0]*r[0],t[1]=n[1]*r[1],t}
function i (line 28) | function i(t,n,r){return t[0]=n[0]/r[0],t[1]=n[1]/r[1],t}
function s (line 28) | function s(t,n){var r=n[0]-t[0],a=n[1]-t[1];return Math.sqrt(r*r+a*a)}
function c (line 28) | function c(t,n){var r=n[0]-t[0],a=n[1]-t[1];return r*r+a*a}
function f (line 28) | function f(t){var n=t[0],r=t[1];return Math.sqrt(n*n+r*r)}
function M (line 28) | function M(t){var n=t[0],r=t[1];return n*n+r*r}
function o (line 28) | function o(t){if(t&&t.__esModule)return t;var n={};if(null!=t)for(var r ...
function i (line 28) | function i(t,n,r){var a=.5*r[0],e=.5*r[1],u=.5*r[2],o=n[0],i=n[1],s=n[2]...
function s (line 28) | function s(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4]...
function c (line 28) | function c(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=r[4],s=r[5],c=r[6],f...
function e (line 28) | function e(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=n[4],s=n[5],c=r[0],f...
function u (line 28) | function u(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t[2]=n[2]-r[2],t[...
function e (line 28) | function e(t,n,r){var a=n[0],e=n[1],u=n[2],o=n[3],i=r[0],s=r[1],c=r[2],f...
function u (line 28) | function u(t,n,r){return t[0]=n[0]-r[0],t[1]=n[1]-r[1],t[2]=n[2]-r[2],t[...
function l (line 28) | function l(t){if(t&&t.__esModule)return t;var n={};if(null!=t)for(var r ...
FILE: editor/js/libs/litegl.js
function typedToArray (line 279) | function typedToArray(){
function fourCCToInt32 (line 933) | function fourCCToInt32(value) {
function int32ToFourCC (line 940) | function int32ToFourCC(value) {
function dxtToRgb565 (line 1021) | function dxtToRgb565(src, src16Offset, width, height) {
function BGRtoRGB (line 1080) | function BGRtoRGB( byteArray )
function flipDXT (line 1090) | function flipDXT( width, blockBytes, byteArray )
function uploadDDSLevels (line 1107) | function uploadDDSLevels(gl, ext, arrayBuffer, loadMipmaps) {
function getDDSLevels (line 1248) | function getDDSLevels( arrayBuffer, compressed_not_supported )
function loadDDSTextureEx (line 1369) | function loadDDSTextureEx(gl, ext, src, texture, loadMipmaps, callback) {
function loadDDSTextureFromMemoryEx (line 1407) | function loadDDSTextureFromMemoryEx(gl, ext, data, texture, loadMipmaps) {
function getDDSTextureFromMemoryEx (line 1444) | function getDDSTextureFromMemoryEx(data) {
function loadDDSTexture (line 1471) | function loadDDSTexture(gl, ext, src, callback) {
function apply_transform (line 4192) | function apply_transform( array, start, length, matrix )
function apply_transform2D (line 4202) | function apply_transform2D( array, start, length, matrix )
function apply_offset (line 4212) | function apply_offset( array, start, length, offset )
function linearizeArray (line 4321) | function linearizeArray( array, typed_array_class )
function DynamicMesh (line 4350) | function DynamicMesh( size, normals, coords, colors, gl )
function middlePoint (line 5088) | function middlePoint( A, B )
function toTypedArray (line 5269) | function toTypedArray( data )
function inner_check_destroy (line 5720) | function inner_check_destroy()
function FBO (line 7355) | function FBO( textures, depth_texture, stencil, gl )
function compileShader (line 8120) | function compileShader()
function loop (line 9496) | function loop() {
function onmouse (line 9632) | function onmouse(e) {
function ontouch (line 9750) | function ontouch( e )
function ongesture (line 9791) | function ongesture(e)
function inner (line 9822) | function inner(e) { onkey(e, prevent_default); }
function onkey (line 9828) | function onkey(e, prevent_default)
function addGamepadXBOXmapping (line 9998) | function addGamepadXBOXmapping(gamepad)
function getAndApplyExtension (line 10088) | function getAndApplyExtension( gl, name ) {
function normalize (line 11352) | function normalize(pos)
FILE: src/litegraph-editor.js
function Editor (line 2) | function Editor(container_id, options) {
FILE: src/litegraph.d.ts
type Vector2 (line 5) | type Vector2 = [number, number];
type Vector4 (line 6) | type Vector4 = [number, number, number, number];
type widgetTypes (line 7) | type widgetTypes =
type SlotShape (line 14) | type SlotShape =
type INodeSlot (line 22) | interface INodeSlot {
type INodeInputSlot (line 38) | interface INodeInputSlot extends INodeSlot {
type INodeOutputSlot (line 41) | interface INodeOutputSlot extends INodeSlot {
type WidgetCallback (line 45) | type WidgetCallback<T extends IWidget = IWidget> = (
type IWidget (line 54) | interface IWidget<TValue = any, TOptions = any> {
type IButtonWidget (line 85) | interface IButtonWidget extends IWidget<null, {}> {
type IToggleWidget (line 88) | interface IToggleWidget
type ISliderWidget (line 92) | interface ISliderWidget
type INumberWidget (line 96) | interface INumberWidget extends IWidget<number, { precision: number }> {
type IComboWidget (line 99) | interface IComboWidget
type ITextWidget (line 111) | interface ITextWidget extends IWidget<string, {}> {
type IContextMenuItem (line 115) | interface IContextMenuItem {
type IContextMenuOptions (line 127) | interface IContextMenuOptions {
type ContextMenuItem (line 137) | type ContextMenuItem = IContextMenuItem | null;
type ContextMenuEventListener (line 138) | type ContextMenuEventListener = (
type serializedLGraph (line 333) | type serializedLGraph<
class LGraph (line 348) | class LGraph {
type SerializedLLink (line 561) | type SerializedLLink = [number, string, number, number, number, number];
class LLink (line 562) | class LLink {
type SerializedLGraphNode (line 581) | type SerializedLGraphNode<T extends LGraphNode = LGraphNode> = {
class LGraphNode (line 596) | class LGraphNode {
type LGraphNodeConstructor (line 1041) | type LGraphNodeConstructor<T extends LGraphNode = LGraphNode> = {
type SerializedLGraphGroup (line 1045) | type SerializedLGraphGroup = {
class LGraphGroup (line 1051) | class LGraphGroup {
class DragAndScale (line 1065) | class DragAndScale {
class LGraphCanvas (line 1096) | class LGraphCanvas {
class ContextMenu (line 1475) | class ContextMenu {
FILE: src/litegraph.js
function LGraph (line 835) | function LGraph(o) {
function on_frame (line 995) | function on_frame() {
function LLink (line 2376) | function LLink(id, type, origin_id, origin_slot, target_id, target_slot) {
function LGraphNode (line 2480) | function LGraphNode(title) {
function compute_text_size (line 3740) | function compute_text_size(text) {
function LGraphGroup (line 4990) | function LGraphGroup(title) {
function DragAndScale (line 5093) | function DragAndScale(element, skip_events) {
function LGraphCanvas (line 5325) | function LGraphCanvas(canvas, graph, options) {
function renderFrame (line 5889) | function renderFrame() {
function inner_clicked (line 10203) | function inner_clicked(v, option, event) {
function inner_value_change (line 10275) | function inner_value_change(widget, value) {
function inner_clicked (line 10575) | function inner_clicked(value) {
function inner_clicked (line 10587) | function inner_clicked(value) {
function inner_onMenuAdded (line 10600) | function inner_onMenuAdded(base_category ,prev_menu){
function inner_clicked (line 10732) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10837) | function inner_clicked(v, e, prev) {
function inner_clicked (line 10936) | function inner_clicked(v, options, e, prev) {
function inner_clicked (line 10997) | function inner_clicked(v,options,e) {
function inner_clicked (line 11254) | function inner_clicked(v,options,e) {
function inner (line 11368) | function inner() {
function setValue (line 11372) | function setValue(value) {
function select (line 11752) | function select(name) {
function changeSelection (line 11870) | function changeSelection(forward) {
function refreshHelper (line 11894) | function refreshHelper() {
function inner (line 12177) | function inner() {
function setValue (line 12181) | function setValue(value) {
function inner_clicked (line 12476) | function inner_clicked(v, option, event) {
function innerChange (line 12488) | function innerChange(name, value)
function inner_refresh (line 12570) | function inner_refresh(){
function inner_refresh (line 12649) | function inner_refresh()
function inner_refresh (line 12790) | function inner_refresh()
function inner_refresh (line 12846) | function inner_refresh() {
function addOutput (line 12878) | function addOutput() {
function inner_clicked (line 12938) | function inner_clicked(v) {
function inner_clicked (line 12999) | function inner_clicked(v) {
function inner_clicked (line 13046) | function inner_clicked(v) {
function inner_option_clicked (line 13447) | function inner_option_clicked(v, options, e) {
function compareObjects (line 13519) | function compareObjects(a, b) {
function distance (line 13529) | function distance(a, b) {
function colorToString (line 13536) | function colorToString(c) {
function isInsideRectangle (line 13551) | function isInsideRectangle(x, y, left, top, width, height) {
function growBounding (line 13560) | function growBounding(bounding, x, y) {
function isInsideBounding (line 13576) | function isInsideBounding(p, bb) {
function overlapBounding (line 13590) | function overlapBounding(a, b) {
function hex2num (line 13611) | function hex2num(hex) {
function num2hex (line 13633) | function num2hex(triplet) {
function ContextMenu (line 13662) | function ContextMenu(values, options) {
function inner_over (line 13895) | function inner_over(e) {
function inner_onclick (line 13905) | function inner_onclick(e) {
function CurveEditor (line 14117) | function CurveEditor( points )
function clamp (line 14399) | function clamp(v, a, b) {
FILE: src/litegraph.test.js
function NewCalcSum (line 89) | function NewCalcSum(a, b) {
function Times (line 117) | function Times() {
function ToInt (line 156) | function ToInt() {
function BlankNode (line 218) | function BlankNode() {}
FILE: src/nodes/audio.js
function onError (line 235) | function onError(err) {
function LGAudioSource (line 247) | function LGAudioSource() {
function inner (line 450) | function inner(buffer) {
function LGAudioMediaSource (line 493) | function LGAudioMediaSource() {
function onFailSoHard (line 566) | function onFailSoHard(err) {
function LGAudioAnalyser (line 644) | function LGAudioAnalyser() {
function LGAudioGain (line 729) | function LGAudioGain() {
function LGAudioConvolver (line 761) | function LGAudioConvolver() {
function inner (line 819) | function inner(buffer) {
function LGAudioDynamicsCompressor (line 831) | function LGAudioDynamicsCompressor() {
function LGAudioWaveShaper (line 883) | function LGAudioWaveShaper() {
function LGAudioMixer (line 916) | function LGAudioMixer() {
function LGAudioADSR (line 988) | function LGAudioADSR() {
function LGAudioDelay (line 1046) | function LGAudioDelay() {
function LGAudioBiquadFilter (line 1072) | function LGAudioBiquadFilter() {
function LGAudioOscillatorNode (line 1127) | function LGAudioOscillatorNode() {
function LGAudioVisualization (line 1204) | function LGAudioVisualization() {
function LGAudioBandSignal (line 1276) | function LGAudioBandSignal() {
function LGAudioScript (line 1327) | function LGAudioScript() {
function LGAudioDestination (line 1448) | function LGAudioDestination() {
FILE: src/nodes/base.js
function Time (line 6) | function Time() {
function Subgraph (line 22) | function Subgraph() {
function GraphInput (line 484) | function GraphInput() {
function GraphOutput (line 645) | function GraphOutput() {
function ConstantNumber (line 778) | function ConstantNumber() {
function ConstantBoolean (line 812) | function ConstantBoolean() {
function ConstantString (line 842) | function ConstantString() {
function ConstantObject (line 874) | function ConstantObject() {
function ConstantFile (line 889) | function ConstantFile() {
function JSONParse (line 989) | function JSONParse() {
function ConstantData (line 1030) | function ConstantData() {
function ConstantArray (line 1065) | function ConstantArray() {
function SetArray (line 1114) | function SetArray()
function ArrayElement (line 1140) | function ArrayElement() {
function TableElement (line 1162) | function TableElement() {
function ObjectProperty (line 1193) | function ObjectProperty() {
function ObjectKeys (line 1231) | function ObjectKeys() {
function SetObject (line 1250) | function SetObject()
function MergeObjects (line 1277) | function MergeObjects() {
function Variable (line 1308) | function Variable() {
function length (line 1364) | function length(v) {
function length (line 1377) | function length(v) {
function DownloadData (line 1390) | function DownloadData() {
function Watch (line 1453) | function Watch() {
function Cast (line 1500) | function Cast() {
function Console (line 1516) | function Console() {
function Alert (line 1562) | function Alert() {
function NodeScript (line 1590) | function NodeScript() {
function GenericCompare (line 1674) | function GenericCompare() {
FILE: src/nodes/events.js
function LogEvent (line 6) | function LogEvent() {
function TriggerEvent (line 21) | function TriggerEvent() {
function Sequence (line 52) | function Sequence() {
function WaitAll (line 94) | function WaitAll() {
function Stepper (line 151) | function Stepper() {
function FilterEvent (line 218) | function FilterEvent() {
function EventBranch (line 261) | function EventBranch() {
function EventCounter (line 285) | function EventCounter() {
function DelayEvent (line 340) | function DelayEvent() {
function TimerEvent (line 391) | function TimerEvent() {
function SemaphoreEvent (line 462) | function SemaphoreEvent() {
function OnceEvent (line 497) | function OnceEvent() {
function DataStore (line 524) | function DataStore() {
FILE: src/nodes/geometry.js
function generateGeometryId (line 19) | function generateGeometryId() {
function LGraphPoints3D (line 23) | function LGraphPoints3D() {
function findRandomTriangle (line 355) | function findRandomTriangle( areas, f )
function LGraphPointsToInstances (line 510) | function LGraphPointsToInstances() {
function LGraphGeometryTransform (line 649) | function LGraphGeometryTransform() {
function LGraphGeometryPolygon (line 774) | function LGraphGeometryPolygon() {
function LGraphGeometryExtrude (line 848) | function LGraphGeometryExtrude() {
function LGraphGeometryEval (line 937) | function LGraphGeometryEval() {
function LGraphConnectPoints (line 1125) | function LGraphConnectPoints() {
function LGraphToGeometry (line 1214) | function LGraphToGeometry() {
function LGraphGeometryToMesh (line 1252) | function LGraphGeometryToMesh() {
function LGraphRenderMesh (line 1321) | function LGraphRenderMesh() {
function LGraphGeometryPrimitive (line 1425) | function LGraphGeometryPrimitive() {
function LGraphRenderPoints (line 1499) | function LGraphRenderPoints() {
FILE: src/nodes/glfx.js
function LGraphFXLens (line 8) | function LGraphFXLens() {
function LGraphFXBokeh (line 249) | function LGraphFXBokeh() {
function LGraphFXGeneric (line 495) | function LGraphFXGeneric() {
function LGraphFXVigneting (line 695) | function LGraphFXVigneting() {
FILE: src/nodes/glshaders.js
function parseGLSLDescriptions (line 62) | function parseGLSLDescriptions()
function registerShaderNode (line 88) | function registerShaderNode( type, node_ctor )
function getShaderNodeVarName (line 147) | function getShaderNodeVarName( node, name )
function getInputLinkID (line 152) | function getInputLinkID( node, slot )
function getOutputLinkID (line 168) | function getOutputLinkID( node, slot )
function LGShaderContext (line 331) | function LGShaderContext()
function LGraphShaderGraph (line 528) | function LGraphShaderGraph() {
function shaderNodeFromFunction (line 764) | function shaderNodeFromFunction( classname, params, return_type, code )
function LGraphShaderUniform (line 772) | function LGraphShaderUniform() {
function LGraphShaderAttribute (line 826) | function LGraphShaderAttribute() {
function LGraphShaderSampler2D (line 865) | function LGraphShaderSampler2D() {
function LGraphShaderConstant (line 906) | function LGraphShaderConstant()
function LGraphShaderVec2 (line 1008) | function LGraphShaderVec2()
function LGraphShaderVec3 (line 1064) | function LGraphShaderVec3()
function LGraphShaderVec4 (line 1129) | function LGraphShaderVec4()
function LGraphShaderFragColor (line 1199) | function LGraphShaderFragColor() {
function LGraphShaderOperation (line 1251) | function LGraphShaderOperation()
function LGraphShaderFunc (line 1324) | function LGraphShaderFunc()
function LGraphShaderSnippet (line 1425) | function LGraphShaderSnippet()
function LGraphShaderRand (line 1502) | function LGraphShaderRand()
function LGraphShaderNoise (line 1525) | function LGraphShaderNoise()
function LGraphShaderTime (line 1706) | function LGraphShaderTime()
function LGraphShaderDither (line 1728) | function LGraphShaderDither()
function LGraphShaderRemap (line 1772) | function LGraphShaderRemap()
FILE: src/nodes/gltextures.js
function LGraphTexture (line 13) | function LGraphTexture() {
function LGraphTexturePreview (line 392) | function LGraphTexturePreview() {
function LGraphTextureSave (line 441) | function LGraphTextureSave() {
function LGraphTextureOperation (line 488) | function LGraphTextureOperation() {
function LGraphTextureShader (line 752) | function LGraphTextureShader() {
function LGraphTextureScaleOffset (line 968) | function LGraphTextureScaleOffset() {
function LGraphTextureWarp (line 1085) | function LGraphTextureWarp() {
function LGraphTextureToViewport (line 1218) | function LGraphTextureToViewport() {
function LGraphTextureCopy (line 1405) | function LGraphTextureCopy() {
function LGraphTextureDownsample (line 1490) | function LGraphTextureDownsample() {
function LGraphTextureResize (line 1618) | function LGraphTextureResize() {
function LGraphTextureAverage (line 1680) | function LGraphTextureAverage() {
function LGraphTextureMinMax (line 1836) | function LGraphTextureMinMax() {
function LGraphTextureTemporalSmooth (line 1962) | function LGraphTextureTemporalSmooth() {
function LGraphTextureLinearAvgSmooth (line 2044) | function LGraphTextureLinearAvgSmooth() {
function LGraphImageToTexture (line 2170) | function LGraphImageToTexture() {
function LGraphTextureLUT (line 2222) | function LGraphTextureLUT() {
function LGraphTextureEncode (line 2342) | function LGraphTextureEncode() {
function LGraphTextureChannels (line 2465) | function LGraphTextureChannels() {
function LGraphChannelsTexture (line 2572) | function LGraphChannelsTexture() {
function LGraphTextureColor (line 2689) | function LGraphTextureColor() {
function LGraphTextureGradient (line 2788) | function LGraphTextureGradient() {
function LGraphTextureMix (line 2901) | function LGraphTextureMix() {
function LGraphTextureEdges (line 3020) | function LGraphTextureEdges() {
function LGraphTextureDepthRange (line 3123) | function LGraphTextureDepthRange() {
function LGraphTextureLinearDepth (line 3265) | function LGraphTextureLinearDepth() {
function LGraphTextureBlur (line 3361) | function LGraphTextureBlur() {
function FXGlow (line 3484) | function FXGlow()
function LGraphTextureGlow (line 3715) | function LGraphTextureGlow() {
function LGraphTextureKuwaharaFilter (line 3875) | function LGraphTextureKuwaharaFilter() {
function LGraphTextureXDoGFilter (line 4065) | function LGraphTextureXDoGFilter() {
function LGraphTextureWebcam (line 4205) | function LGraphTextureWebcam() {
function onFailSoHard (line 4236) | function onFailSoHard(e) {
function LGraphLensFX (line 4394) | function LGraphLensFX() {
function LGraphTextureFromData (line 4532) | function LGraphTextureFromData() {
function LGraphTextureCurve (line 4580) | function LGraphTextureCurve() {
function LGraphExposition (line 4796) | function LGraphExposition() {
function LGraphToneMapping (line 4874) | function LGraphToneMapping() {
function LGraphTexturePerlin (line 5038) | function LGraphTexturePerlin() {
function LGraphTextureCanvas2D (line 5224) | function LGraphTextureCanvas2D() {
function LGraphTextureMatte (line 5368) | function LGraphTextureMatte() {
function LGraphCubemapToTexture2D (line 5463) | function LGraphCubemapToTexture2D() {
FILE: src/nodes/graphics.js
function GraphicsPlot (line 4) | function GraphicsPlot() {
function GraphicsImage (line 78) | function GraphicsImage() {
function ColorPalette (line 176) | function ColorPalette() {
function ImageFrame (line 251) | function ImageFrame() {
function ImageFade (line 302) | function ImageFade() {
function ImageCrop (line 361) | function ImageCrop() {
function CanvasNode (line 444) | function CanvasNode() {
function DrawImageNode (line 481) | function DrawImageNode() {
function DrawRectangleNode (line 511) | function DrawRectangleNode() {
function ImageVideo (line 546) | function ImageVideo() {
function ImageWebcam (line 735) | function ImageWebcam() {
function onFailSoHard (line 765) | function onFailSoHard(e) {
FILE: src/nodes/input.js
function GamepadInput (line 4) | function GamepadInput() {
FILE: src/nodes/interface.js
function WidgetButton (line 7) | function WidgetButton() {
function WidgetToggle (line 90) | function WidgetToggle() {
function WidgetNumber (line 162) | function WidgetNumber() {
function WidgetCombo (line 280) | function WidgetCombo() {
function WidgetKnob (line 320) | function WidgetKnob() {
function WidgetSliderGUI (line 481) | function WidgetSliderGUI() {
function WidgetHSlider (line 518) | function WidgetHSlider() {
function WidgetProgress (line 602) | function WidgetProgress() {
function WidgetText (line 632) | function WidgetText() {
function WidgetPanel (line 729) | function WidgetPanel() {
FILE: src/nodes/logic.js
function Selector (line 4) | function Selector() {
function Sequence (line 48) | function Sequence() {
function logicAnd (line 87) | function logicAnd(){
function logicOr (line 113) | function logicOr(){
function logicNot (line 139) | function logicNot(){
function logicCompare (line 153) | function logicCompare(){
function logicBranch (line 182) | function logicBranch(){
FILE: src/nodes/math.js
function Converter (line 5) | function Converter() {
function Bypass (line 80) | function Bypass() {
function ToNumber (line 96) | function ToNumber() {
function MathRange (line 111) | function MathRange() {
function MathRand (line 194) | function MathRand() {
function MathNoise (line 234) | function MathNoise() {
function MathSpikes (line 304) | function MathSpikes() {
function MathClamp (line 345) | function MathClamp() {
function MathLerp (line 383) | function MathLerp() {
function MathAbs (line 421) | function MathAbs() {
function MathFloor (line 441) | function MathFloor() {
function MathFrac (line 461) | function MathFrac() {
function MathSmoothStep (line 481) | function MathSmoothStep() {
function MathScale (line 511) | function MathScale() {
function Gate (line 531) | function Gate() {
function MathAverageFilter (line 550) | function MathAverageFilter() {
function MathTendTo (line 602) | function MathTendTo() {
function MathOperation (line 630) | function MathOperation() {
function MathCompare (line 759) | function MathCompare() {
function MathCondition (line 854) | function MathCondition() {
function MathBranch (line 931) | function MathBranch() {
function MathAccumulate (line 961) | function MathAccumulate() {
function MathTrigonometry (line 988) | function MathTrigonometry() {
function MathFormula (line 1075) | function MathFormula() {
function Math3DVec2ToXY (line 1157) | function Math3DVec2ToXY() {
function Math3DXYToVec2 (line 1178) | function Math3DXYToVec2() {
function Math3DVec3ToXYZ (line 1207) | function Math3DVec3ToXYZ() {
function Math3DXYZToVec3 (line 1230) | function Math3DXYZToVec3() {
function Math3DVec4ToXYZW (line 1264) | function Math3DVec4ToXYZW() {
function Math3DXYZWToVec4 (line 1289) | function Math3DXYZWToVec4() {
FILE: src/nodes/math3d.js
function Math3DMat4 (line 5) | function Math3DMat4()
function Math3DOperation (line 68) | function Math3DOperation() {
function Math3DVec3Scale (line 178) | function Math3DVec3Scale() {
function Math3DVec3Length (line 208) | function Math3DVec3Length() {
function Math3DVec3Normalize (line 227) | function Math3DVec3Normalize() {
function Math3DVec3Lerp (line 252) | function Math3DVec3Lerp() {
function Math3DVec3Dot (line 285) | function Math3DVec3Dot() {
function Math3DQuaternion (line 312) | function Math3DQuaternion() {
function Math3DRotation (line 343) | function Math3DRotation() {
function MathEulerToQuat (line 371) | function MathEulerToQuat() {
function MathQuatToEuler (line 396) | function MathQuatToEuler() {
function Math3DRotateVec3 (line 418) | function Math3DRotateVec3() {
function Math3DMultQuat (line 445) | function Math3DMultQuat() {
function Math3DQuatSlerp (line 471) | function Math3DQuatSlerp() {
function Math3DRemapRange (line 508) | function Math3DRemapRange() {
FILE: src/nodes/midi.js
function MIDIEvent (line 5) | function MIDIEvent(data) {
function MIDIInterface (line 332) | function MIDIInterface(on_ready, on_error) {
function LGMIDIIn (line 467) | function LGMIDIIn() {
function LGMIDIOut (line 593) | function LGMIDIOut() {
function LGMIDIShow (line 662) | function LGMIDIShow() {
function LGMIDIFilter (line 709) | function LGMIDIFilter() {
function LGMIDIEvent (line 817) | function LGMIDIEvent() {
function LGMIDICC (line 991) | function LGMIDICC() {
function LGMIDIGenerator (line 1016) | function LGMIDIGenerator() {
function LGMIDITranspose (line 1107) | function LGMIDITranspose() {
function LGMIDIQuantize (line 1151) | function LGMIDIQuantize() {
function LGMIDIFromFile (line 1228) | function LGMIDIFromFile() {
function LGMIDIPlay (line 1344) | function LGMIDIPlay() {
function LGMIDIKeys (line 1403) | function LGMIDIKeys() {
function now (line 1583) | function now() {
FILE: src/nodes/network.js
function LGWebSocket (line 5) | function LGWebSocket() {
function LGSillyClient (line 153) | function LGSillyClient() {
function HTTPRequestNode (line 367) | function HTTPRequestNode() {
FILE: src/nodes/strings.js
function toString (line 5) | function toString(a) {
function compare (line 22) | function compare(a, b) {
function concatenate (line 33) | function concatenate(a, b) {
function contains (line 50) | function contains(a, b) {
function toUpperCase (line 64) | function toUpperCase(a) {
function split (line 78) | function split(str, separator) {
function toFixed (line 105) | function toFixed(a) {
function StringToTable (line 121) | function StringToTable() {
FILE: utils/builder.py
function packJSCode (line 49) | def packJSCode(files):
function compileAndMinify (line 76) | def compileAndMinify(input_path, output_path):
Condensed preview — 106 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (5,055K chars).
[
{
"path": ".eslintignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": ".eslintrc.js",
"chars": 1395,
"preview": "module.exports = {\n \"env\": {\n \"browser\": true,\n \"es2021\": true,\n \"node\": true,\n \"jest/glo"
},
{
"path": ".gitignore",
"chars": 128,
"preview": "node_modules/\nnode_modules/*\nnpm-debug.log\ntemp/\ntemp/*\ncoverage/\n\n# Editors\n/.vscode/*\n!/.vscode/extensions.json\n*.bak\n"
},
{
"path": ".npmrc",
"chars": 18,
"preview": "package-lock=false"
},
{
"path": ".prettierrc",
"chars": 66,
"preview": "{\n \"singleQuote\": false,\n \"semi\": true,\n \"tabWidth\": 4\n}\n"
},
{
"path": ".vscode/extensions.json",
"chars": 488,
"preview": "{\n // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.\n // Extension id"
},
{
"path": "CONTRIBUTING.md",
"chars": 479,
"preview": "# Contribution Rules\nThere are some simple rules that everyone should follow:\n\n### Do not commit files from build folder"
},
{
"path": "LICENSE",
"chars": 1077,
"preview": "Copyright (C) 2013 by Javi Agenjo\r\n\r\nPermission is hereby granted, free of charge, to any person obtaining a copy\r\nof th"
},
{
"path": "README.md",
"chars": 5370,
"preview": "# litegraph.js\r\n\r\nA library in Javascript to create graphs in the browser similar to Unreal Blueprints. Nodes can be pro"
},
{
"path": "build/litegraph.core.js",
"chars": 493273,
"preview": "//packer version\n\n\n(function(global) {\n // *************************************************************\n // Lit"
},
{
"path": "build/litegraph.js",
"chars": 1074483,
"preview": "//packer version\n\n\n(function(global) {\n // *************************************************************\n // Lit"
},
{
"path": "build/litegraph_mini.js",
"chars": 635361,
"preview": "//packer version\n\n\n(function(global) {\n // *************************************************************\n // Lit"
},
{
"path": "csharp/LiteGraph.cs",
"chars": 20666,
"preview": "using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\n//using System.Diagnostics;\r\nusing UnityEn"
},
{
"path": "csharp/LiteGraphNodes.cs",
"chars": 6076,
"preview": "using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\nusing SimpleJSON;\r\n\r"
},
{
"path": "csharp/LiteGraphTest.cs",
"chars": 1298,
"preview": "using System.Collections;\r\nusing System.Collections.Generic;\r\nusing UnityEngine;\r\n\r\nusing LiteGraph;\r\n\r\n\r\npublic class "
},
{
"path": "csharp/SimpleJSON.cs",
"chars": 47354,
"preview": "/* * * * *\n * A simple JSON Parser / builder\n * ------------------------------\n * \n * It mainly has been written as a si"
},
{
"path": "csharp/graph.JSON",
"chars": 1662,
"preview": "{\"last_node_id\":15,\"last_link_id\":26,\"nodes\":[{\"id\":5,\"type\":\"graph/output\",\"pos\":[1265,331],\"size\":[180,60],\"flags\":{\"c"
},
{
"path": "csharp/readme.md",
"chars": 116,
"preview": "# C SHARP\n\nThis code allows to execute a subset of nodes of LiteGraph directly in Unity.\n\nStill a work in progress.\n"
},
{
"path": "css/litegraph-editor.css",
"chars": 3995,
"preview": ".litegraph-editor {\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n\n background-color: #333;\n c"
},
{
"path": "css/litegraph.css",
"chars": 12820,
"preview": "/* this CSS contains only the basic CSS needed to run the app and use it */\n\n.lgraphcanvas {\n /*cursor: crosshair;*/\n"
},
{
"path": "doc/api.js",
"chars": 260,
"preview": "YUI.add(\"yuidoc-meta\", function(Y) {\n Y.YUIDoc = { meta: {\n \"classes\": [\n \"ContextMenu\",\n \"LGraph\",\n "
},
{
"path": "doc/assets/css/main.css",
"chars": 18199,
"preview": "/*\nFont sizes for all selectors other than the body are given in percentages,\nwith 100% equal to 13px. To calculate a fo"
},
{
"path": "doc/assets/index.html",
"chars": 216,
"preview": "<!doctype html>\n<html>\n <head>\n <title>Redirector</title>\n <meta http-equiv=\"refresh\" content=\"0;url=.."
},
{
"path": "doc/assets/js/api-filter.js",
"chars": 1563,
"preview": "YUI.add('api-filter', function (Y) {\n\nY.APIFilter = Y.Base.create('apiFilter', Y.Base, [Y.AutoCompleteBase], {\n // --"
},
{
"path": "doc/assets/js/api-list.js",
"chars": 6770,
"preview": "YUI.add('api-list', function (Y) {\n\nvar Lang = Y.Lang,\n YArray = Y.Array,\n\n APIList = Y.namespace('APIList'),\n\n "
},
{
"path": "doc/assets/js/api-search.js",
"chars": 2924,
"preview": "YUI.add('api-search', function (Y) {\n\nvar Lang = Y.Lang,\n Node = Y.Node,\n YArray = Y.Array;\n\nY.APISearch = Y.B"
},
{
"path": "doc/assets/js/apidocs.js",
"chars": 10497,
"preview": "YUI().use(\n 'yuidoc-meta',\n 'api-list', 'history-hash', 'node-screen', 'node-style', 'pjax',\nfunction (Y) {\n\nvar w"
},
{
"path": "doc/assets/js/yui-prettify.js",
"chars": 482,
"preview": "YUI().use('node', function(Y) {\n var code = Y.all('.prettyprint.linenums');\n if (code.size()) {\n code.each("
},
{
"path": "doc/assets/vendor/prettify/CHANGES.html",
"chars": 6084,
"preview": "<html>\n <head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n <title>Change Log</title>\n "
},
{
"path": "doc/assets/vendor/prettify/COPYING",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "doc/assets/vendor/prettify/README.html",
"chars": 7912,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
},
{
"path": "doc/assets/vendor/prettify/prettify-min.css",
"chars": 675,
"preview": ".pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,"
},
{
"path": "doc/assets/vendor/prettify/prettify-min.js",
"chars": 17803,
"preview": "window.PR_SHOULD_USE_CONTINUATION=true;var prettyPrintOne;var prettyPrint;(function(){var O=window;var j=[\"break,continu"
},
{
"path": "doc/classes/ContextMenu.html",
"chars": 6555,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>ContextMenu</title>\n <link rel=\"stylesh"
},
{
"path": "doc/classes/LGraph.html",
"chars": 59747,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>LGraph</title>\n <link rel=\"stylesheet\" "
},
{
"path": "doc/classes/LGraphCanvas.html",
"chars": 43651,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>LGraphCanvas</title>\n <link rel=\"styles"
},
{
"path": "doc/classes/LGraphNode.html",
"chars": 73636,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>LGraphNode</title>\n <link rel=\"styleshe"
},
{
"path": "doc/classes/LiteGraph.html",
"chars": 18654,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>LiteGraph</title>\n <link rel=\"styleshee"
},
{
"path": "doc/classes/index.html",
"chars": 216,
"preview": "<!doctype html>\n<html>\n <head>\n <title>Redirector</title>\n <meta http-equiv=\"refresh\" content=\"0;url=.."
},
{
"path": "doc/data.json",
"chars": 72119,
"preview": "{\n \"project\": {},\n \"files\": {\n \"../src/litegraph.js\": {\n \"name\": \"../src/litegraph.js\",\n "
},
{
"path": "doc/elements/index.html",
"chars": 216,
"preview": "<!doctype html>\n<html>\n <head>\n <title>Redirector</title>\n <meta http-equiv=\"refresh\" content=\"0;url=.."
},
{
"path": "doc/files/.._src_litegraph.js.html",
"chars": 240832,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title>../src/litegraph.js</title>\n <link rel="
},
{
"path": "doc/files/index.html",
"chars": 216,
"preview": "<!doctype html>\n<html>\n <head>\n <title>Redirector</title>\n <meta http-equiv=\"refresh\" content=\"0;url=.."
},
{
"path": "doc/index.html",
"chars": 4823,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <title></title>\n <link rel=\"stylesheet\" href=\""
},
{
"path": "doc/modules/index.html",
"chars": 216,
"preview": "<!doctype html>\n<html>\n <head>\n <title>Redirector</title>\n <meta http-equiv=\"refresh\" content=\"0;url=.."
},
{
"path": "editor/editor_mobile.html",
"chars": 5530,
"preview": "<!-- Javi Agenjo (@tamat) on 31/9/2011 -->\n<!DOCTYPE html>\n<html>\n<head>\n <title>LiteGraph</title>\n\t<!--<meta name=\"v"
},
{
"path": "editor/examples/audio.json",
"chars": 4695,
"preview": "{\"last_node_id\":16,\"last_link_id\":16,\"nodes\":[{\"id\":9,\"type\":\"widget/knob\",\"pos\":[440,81],\"size\":[80,100],\"flags\":{},\"mo"
},
{
"path": "editor/examples/audio_delay.json",
"chars": 2240,
"preview": "{\"last_node_id\":7,\"last_link_id\":7,\"nodes\":[{\"id\":6,\"type\":\"widget/knob\",\"pos\":[199,296],\"size\":[64,84],\"flags\":{},\"orde"
},
{
"path": "editor/examples/audio_reverb.json",
"chars": 1991,
"preview": "{\"last_node_id\":8,\"last_link_id\":9,\"nodes\":[{\"id\":4,\"type\":\"widget/knob\",\"pos\":[408,59],\"size\":[81,93],\"flags\":{},\"order"
},
{
"path": "editor/examples/benchmark.json",
"chars": 15627,
"preview": "{\"last_node_id\":60,\"last_link_id\":50,\"nodes\":[{\"id\":9,\"type\":\"features/slots\",\"pos\":[846,473],\"size\":[100,40],\"flags\":{\""
},
{
"path": "editor/examples/copypaste.json",
"chars": 16711,
"preview": "{\"last_node_id\":62,\"last_link_id\":157,\"nodes\":[{\"id\":35,\"type\":\"widget/number\",\"pos\":[354.0977802999988,-703.69409839999"
},
{
"path": "editor/examples/features.json",
"chars": 2686,
"preview": "{\"last_node_id\":14,\"last_link_id\":14,\"nodes\":[{\"id\":9,\"type\":\"features/slots\",\"pos\":[847,479],\"size\":[100,40],\"flags\":{\""
},
{
"path": "editor/examples/midi_generation.json",
"chars": 9492,
"preview": "{\"last_node_id\":47,\"last_link_id\":64,\"nodes\":[{\"id\":8,\"type\":\"midi/generator\",\"pos\":[548,390],\"size\":{\"0\":140,\"1\":66},\"f"
},
{
"path": "editor/examples/subgraph.json",
"chars": 2648,
"preview": "{\"last_node_id\":6,\"last_link_id\":5,\"nodes\":[{\"id\":3,\"type\":\"basic/time\",\"pos\":[312,145],\"size\":{\"0\":140,\"1\":46},\"flags\":"
},
{
"path": "editor/index.html",
"chars": 2421,
"preview": "<!-- Javi Agenjo (@tamat) on 31/9/2011 -->\n<!DOCTYPE html>\n<html><head>\n <title>LiteGraph</title>\n\t<!--<meta name=\"vi"
},
{
"path": "editor/js/code.js",
"chars": 5648,
"preview": "var webgl_canvas = null;\n\nLiteGraph.node_images_path = \"../nodes_data/\";\n\nvar editor = new LiteGraph.Editor(\"main\",{mini"
},
{
"path": "editor/js/defaults.js",
"chars": 3191,
"preview": "\nLiteGraph.debug = false;\nLiteGraph.catch_exceptions = true;\nLiteGraph.throw_errors = true;\nLiteGraph.allow_scripts = fa"
},
{
"path": "editor/js/defaults_mobile.js",
"chars": 3195,
"preview": "\nLiteGraph.debug = false;\nLiteGraph.catch_exceptions = true;\nLiteGraph.throw_errors = true;\nLiteGraph.allow_scripts = fa"
},
{
"path": "editor/js/demos.js",
"chars": 7594,
"preview": "\nfunction demo()\n{\n\tmultiConnection();\n}\n\nfunction multiConnection()\n{\n\tvar node_button = LiteGraph.createNode(\"widget/b"
},
{
"path": "editor/js/libs/audiosynth.js",
"chars": 11657,
"preview": "var Synth, AudioSynth, AudioSynthInstrument;\n!function(){\n\n\tvar URL = window.URL || window.webkitURL;\n\tvar Blob = window"
},
{
"path": "editor/js/libs/gl-matrix-min.js",
"chars": 55991,
"preview": "/*!\n@fileoverview gl-matrix - High performance matrix and vector operations\n@author Brandon Jones\n@author Colin MacKenzi"
},
{
"path": "editor/js/libs/litegl.js",
"chars": 402646,
"preview": "//packer version\n//litegl.js by Javi Agenjo 2014 @tamat (tamats.com)\n//forked from lightgl.js by Evan Wallace (madebyeva"
},
{
"path": "editor/js/libs/midi-parser.js",
"chars": 22270,
"preview": "/*\n Project Name : midi-parser-js\n Project Url : https://github.com/colxi/midi-parser-js/\n Author : colx"
},
{
"path": "editor/style.css",
"chars": 3920,
"preview": "html,body {\n\twidth: 100%;\n\theight: 100%;\n\tmargin: 0;\n\tpadding: 0;\n}\n\nbody {\n\tbackground-color: #333;\n\tcolor: #EEE;\n\tfont"
},
{
"path": "gruntfile.js",
"chars": 1418,
"preview": "module.exports = function (grunt) {\n grunt.initConfig({\n pkg: grunt.file.readJSON('package.json'),\n projectFiles:"
},
{
"path": "guides/README.md",
"chars": 13904,
"preview": "# LiteGraph\n\nHere is a list of useful info when working with LiteGraph.\nThe library is divided in four levels:\n* **LGrap"
},
{
"path": "index.html",
"chars": 3036,
"preview": "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\""
},
{
"path": "jest.config.js",
"chars": 6459,
"preview": "/*\n * For a detailed explanation regarding each configuration property, visit:\n * https://jestjs.io/docs/configuration\n "
},
{
"path": "package.json",
"chars": 1625,
"preview": "{\n \"name\": \"litegraph.js\",\n \"version\": \"0.7.14\",\n \"description\": \"A graph node editor similar to PD or UDK Blue"
},
{
"path": "src/litegraph-editor.js",
"chars": 9444,
"preview": "//Creates an interface to access extra features from a graph (like play, stop, live, etc)\r\nfunction Editor(container_id,"
},
{
"path": "src/litegraph.d.ts",
"chars": 53235,
"preview": "// Type definitions for litegraph.js 0.7.0\n// Project: litegraph.js\n// Definitions by: NateScarlet <https://github.com/N"
},
{
"path": "src/litegraph.js",
"chars": 493254,
"preview": "\n(function(global) {\n // *************************************************************\n // LiteGraph CLASS "
},
{
"path": "src/litegraph.test.js",
"chars": 8390,
"preview": "describe(\"register node types\", () => {\n let lg;\n let Sum;\n\n beforeEach(() => {\n jest.resetModules();\n "
},
{
"path": "src/nodes/audio.js",
"chars": 46195,
"preview": "(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n var LGAudio = {};\r\n global.LGAudio = LGAudio;\r\n\r\n "
},
{
"path": "src/nodes/base.js",
"chars": 52962,
"preview": "//basic nodes\r\n(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n //Constant\r\n function Time() {\r\n "
},
{
"path": "src/nodes/events.js",
"chars": 16915,
"preview": "//event related nodes\r\n(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n //Show value inside the debug c"
},
{
"path": "src/nodes/geometry.js",
"chars": 52841,
"preview": "(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n\tvar view_matrix = new Float32Array(16);\r\n\tvar projection_"
},
{
"path": "src/nodes/glfx.js",
"chars": 27075,
"preview": "(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n var LGraphTexture = global.LGraphTexture;\r\n\r\n //Works"
},
{
"path": "src/nodes/glshaders.js",
"chars": 53760,
"preview": "(function(global) {\r\n\r\n if (typeof GL == \"undefined\")\r\n\t\treturn;\r\n\r\n var LiteGraph = global.LiteGraph;\r\n\tvar LGrap"
},
{
"path": "src/nodes/gltextures.js",
"chars": 143394,
"preview": "(function(global) {\n var LiteGraph = global.LiteGraph;\n\tvar LGraphCanvas = global.LGraphCanvas;\n\n //Works with Lit"
},
{
"path": "src/nodes/graphics.js",
"chars": 26125,
"preview": "(function(global) {\n var LiteGraph = global.LiteGraph;\n\n function GraphicsPlot() {\n this.addInput(\"A\", \"Num"
},
{
"path": "src/nodes/input.js",
"chars": 12882,
"preview": "(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n function GamepadInput() {\r\n this.addOutput(\"lef"
},
{
"path": "src/nodes/interface.js",
"chars": 23133,
"preview": "//widgets\n(function(global) {\n var LiteGraph = global.LiteGraph;\n\n /* Button ****************/\n\n function Widge"
},
{
"path": "src/nodes/logic.js",
"chars": 5880,
"preview": "(function(global) {\n var LiteGraph = global.LiteGraph;\n\n function Selector() {\n this.addInput(\"sel\", \"numbe"
},
{
"path": "src/nodes/math.js",
"chars": 37262,
"preview": "(function(global) {\n var LiteGraph = global.LiteGraph;\n\n //Converter\n function Converter() {\n this.addIn"
},
{
"path": "src/nodes/math3d.js",
"chars": 17513,
"preview": "(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n\r\n\tfunction Math3DMat4()\r\n\t{\r\n this.addInput(\"T\", \""
},
{
"path": "src/nodes/midi.js",
"chars": 49077,
"preview": "(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n var MIDI_COLOR = \"#243\";\r\n\r\n function MIDIEvent(data)"
},
{
"path": "src/nodes/network.js",
"chars": 12690,
"preview": "//event related nodes\r\n(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n function LGWebSocket() {\r\n "
},
{
"path": "src/nodes/others.js",
"chars": 2528,
"preview": "(function(global) {\n var LiteGraph = global.LiteGraph;\n \n /* in types :: run in console :: var s=\"\"; LiteGraph."
},
{
"path": "src/nodes/strings.js",
"chars": 3490,
"preview": "//basic nodes\r\n(function(global) {\r\n var LiteGraph = global.LiteGraph;\r\n\r\n function toString(a) {\r\n\t\tif(a && a.con"
},
{
"path": "style.css",
"chars": 196,
"preview": "body { background-color: #DDD; }\r\nh1 {\r\n\tmargin: 0;\r\n}\r\n\r\n#wrap {\r\n\tmargin: auto;\r\n\twidth: 800px;\r\n\tmin-height: 400px;\r\n"
},
{
"path": "utils/build.sh",
"chars": 344,
"preview": "cd \"$(dirname \"$0\")\"\npython builder.py deploy_files.txt -o ../build/litegraph.min.js -o2 ../build/litegraph.js\npython bu"
},
{
"path": "utils/builder.py",
"chars": 3706,
"preview": "#!/usr/bin/python\n\nimport re, os, sys, time, tempfile, shutil\nimport argparse\nfrom datetime import date\n\nroot_path = \"./"
},
{
"path": "utils/deploy_files.txt",
"chars": 410,
"preview": "../src/litegraph.js\r\n../src/nodes/base.js\r\n../src/nodes/events.js\r\n../src/nodes/interface.js\r\n../src/nodes/input.js\r\n../"
},
{
"path": "utils/deploy_files_core.txt",
"chars": 20,
"preview": "../src/litegraph.js\n"
},
{
"path": "utils/deploy_files_mini.txt",
"chars": 185,
"preview": "../src/litegraph.js\r\n../src/nodes/base.js\r\n../src/nodes/events.js\r\n../src/nodes/input.js\r\n../src/nodes/math.js\r\n../src/n"
},
{
"path": "utils/generate_doc.sh",
"chars": 209,
"preview": "#!/bin/bash\n\n# For migration to JSDoc (YUIDoc was deprecated in 2014): https://github.com/pnstickne/yuidoc-to-jsdoc\n\ncd "
},
{
"path": "utils/pack.sh",
"chars": 255,
"preview": "cd \"$(dirname \"$0\")\"\npython builder.py deploy_files.txt -o ../build/litegraph.min.js -o2 ../build/litegraph.js --nomin\np"
},
{
"path": "utils/server.js",
"chars": 356,
"preview": "const express = require('express')\nconst app = express()\n\napp.use('/css', express.static('css'))\napp.use('/src', express"
},
{
"path": "utils/temp.js",
"chars": 10348,
"preview": "LiteGraph.registerNodeType(\"color/palette\",{title:\"Palette\",desc:\"Generates a color\",inputs:[[\"f\",\"number\"]],outputs:[[\""
},
{
"path": "utils/test.sh",
"chars": 400,
"preview": "#!/bin/bash\n\nset -eo pipefail\ncd \"$(dirname \"$(readlink -f \"${BASH_SOURCE[0]}\")\")\"\n\nexport NVM_DIR=$HOME/.nvm\nsource \"$N"
}
]
// ... and 5 more files (download for full content)
About this extraction
This page contains the full source code of the jagenjo/litegraph.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 106 files (4.5 MB), approximately 1.2M tokens, and a symbol index with 1123 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.