Skip to content

Commit

Permalink
Updated docs, using docsify now
Browse files Browse the repository at this point in the history
  • Loading branch information
newcat committed Feb 17, 2019
1 parent 19edcfd commit 18ccb2c
Show file tree
Hide file tree
Showing 17 changed files with 288 additions and 80 deletions.
Empty file added docs/.nojekyll
Empty file.
12 changes: 12 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# BaklavaJS

[![Build Status](https://travis-ci.org/newcat/baklavajs.svg?branch=master)](https://travis-ci.org/newcat/baklavajs)
[![npm version](https://badge.fury.io/js/baklavajs.svg)](https://badge.fury.io/js/baklavajs)

Graph / node editor in the browser using VueJS
![example](img/example.png)

### Roadmap
* Add panning for all nodes
* Allow connections from input to output (auto-reverse)
* Optional keyboard shortcuts
10 changes: 10 additions & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
* **Usage**
* [Documentation](/)
* [Getting Started](/getting-started.md)
* [Editor Instance](/editor.md)
* [Styling](/styling.md)
* **Custom Nodes**
* [Creating Custom Nodes](/custom-nodes.md)
* [Prebuilt Options](/prebuilt-options.md)
* **Reference**
* [API Reference](/api.md)
167 changes: 167 additions & 0 deletions docs/custom-nodes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Creating Custom Nodes <!-- omit in toc -->

- [Basics](#basics)
- [Node Interfaces](#node-interfaces)
- [Node Options](#node-options)
- [Sidebar](#sidebar)
- [Prebuilt Options](#prebuilt-options)
- [Default Values](#default-values)
- [Custom Node Implementation](#custom-node-implementation)
- [Node Builder](#node-builder)
- [Class](#class)
- [Calculation](#calculation)

## Basics
Every node consists of three parts:
* [Output Interfaces](#node-interfaces)
* [Options](#node-options)
* [Input Interfaces](#node-interfaces)

![node parts](img/node_parts.png)

All of these parts are customizable.

## Node Interfaces
Interfaces are used to receive data from other nodes (*input interfaces*) or send data to other nodes (*output interfaces*). A node interface has two important properties:

| Property | Description |
| --- | --- |
| <p>**name**</p> | <p>The name is displayed to the user. You also need the name to get the value of the interface</p> |
| <p>**type**</p> | <p> The type can be any word (spaces would break the CSS class). By default, connections are only allowed between NodeInterfaces, that have the same type. The "dot" will also be assigned the following CSS class: `--iftype-{TYPE}`. For example, if the type is "string", the CSS class would be `--iftype-string`. You can use this to [style](styling.md) your interfaces.</p> |

An input interface, which is not connected, can display a node option to allow the user to change its value.

## Node Options
Options are just Vue components, that support the `v-model` directive.
This means, they receive the option's value through the `value` prop and can write updates
to the value using the `input` event.
Additionally, each option can emit the `openSidebar` event, which will open the [sidebar](#sidebar)
to display a more advanced UI for the option.

Their value can be written or read by using the [setOptionValue](docs/api.md#Node+setOptionValue)
or [getOptionValue](docs/api.md#Node+getOptionValue) methods.

### Sidebar
Some options can require a more complex UI which would not fit in the limited space that a node provides.
In this case, you can display a button in the node that will open the sidebar when pressed.
The advanced UI can now be displayed in the sidebar.

> Open the sidebar by emitting the `openSidebar` event in an option.
```js
import { Options } from "baklavajs";
import MySidebarOption from "./MySidebarOption.vue";

// in the node constructor
this.addOption("SidebarTest", Options.ButtonOption, () => ({ testtext: "any" }), MySidebarOption);
```

Both the component in the node as well as the component in the sidebar
will receive the current option value through the `value` prop.

### Prebuilt Options
There are prebuilt options like text and number input, dropdown menu and many more available.
These are documented [here](/prebuilt-options).

### Default Values
> When providing complex default values like arrays or objects as default values using the NodeBuilder's
> [addInputInterface](docs/api.md#NodeBuilder+addInputInterface) or
> [addOption](docs/api.md#NodeBuilder+addOption) method, you need to provide an option that returns
> the default array or object. This ensures that multiple instances of the node interface or node option
> all have their own data objects.
Example:
```js
new NodeBuilder("MyNode")
// This is fine, because we provide a primitive as default value
.addInputInterface("Primitive", "type", MyOption, "default")
// But in this case we need to provide a function to create an object
.addInputInterface("Complex", "type", MyOption, () => {
return { a: 1, b: "Hello World!" };
})
```

## Custom Node Implementation
There are two ways to create custom nodes:

### Node Builder
The [node builder](api.md#NodeBuilder) is a simple way to build nodes "on the fly".
```js
import { NodeBuilder, Options } from "baklavajs";

export default new NodeBuilder("MathNode")
.addInputInterface("Number 1", "number", Options.NumberOption, 1)
.addInputInterface("Number 2", "number", Options.NumberOption, 10)
.addOption("Operation", Options.SelectOption, () => ({
selected: "Add",
items: [ "Add", "Subtract" ]
}))
.addOutputInterface("Output", "number")
.onCalculate((n) => {
const n1 = n.getInterface("Number 1").value;
const n2 = n.getInterface("Number 2").value;
const operation = n.getOptionValue("Operation").selected;
let result;
if (operation === "Add") {
result = n1 + n2;
} else if (operation === "Subtract") {
result = n1 - n2;
}
n.getInterface("Output").value = result;
})
.build();
```

> Don't forget to `build()` at the end.
### Class
If you have a more complex node, you can create a subclass of `Node`
and implement the required methods/properties yourself.
```js
import { Node, Options } from "baklavajs";

export class MathNode extends Node {

type = "MathNode";
name = this.type;

constructor() {
super();
this.addInputInterface("Number 1", "number", Options.NumberOption, 1);
this.addInputInterface("Number 2", "number", Options.NumberOption, 10);
this.addOutputInterface("Output", "number");
this.addOption("Operation", Options.SelectOption, () => ({
selected: "Add",
items: [ "Add", "Subtract" ]
}));
}

public calculate() {
const n1 = this.getInterface("Number 1").value;
const n2 = this.getInterface("Number 2").value;
const operation = this.getOptionValue("Operation").selected;
let result;
if (operation === "Add") {
result = n1 + n2;
} else if (operation === "Subtract") {
result = n1 - n2;
}
this.getInterface("Output").value = result;
}

}
```

## Calculation
Each Node class can overwrite the `calculate()` function to perform some logic.
Usually the calculation functions reads the values from the input interfaces and the options,
performs some logic and sets the values of the output interfaces with the results.

For a node, that outputs the sum of its two inputs, the calculation function could look like this:
```js
calculate() {
const a = this.getInterface("Number 1").value;
const b = this.getInterface("Number 2").value;
this.getInterface("Output").value = a + b;
}
```
31 changes: 15 additions & 16 deletions docs/editor.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
# Editor
# Editor <!-- omit in toc -->
The editor class is the main class of the model. You can do most things like adding/removing nodes and connections, loading/saving, ... from here.

> Please only use the provided functions and do not modify fields directly.
- [Editor](#editor)
- [Nodes](#nodes)
- [Adding / removing nodes](#adding--removing-nodes)
- [Connections](#connections)
- [Connection validity](#connection-validity)
- [Adding / removing connections](#adding--removing-connections)
- [Calculation](#calculation)
- [Saving / Export](#saving--export)
- [Loading / Import](#loading--import)

- [Nodes](#nodes)
- [Adding / removing nodes](#adding--removing-nodes)
- [Connections](#connections)
- [Connection validity](#connection-validity)
- [Adding / removing connections](#adding--removing-connections)
- [Calculation](#calculation)
- [Saving / Export](#saving--export)
- [Loading / Import](#loading--import)

## Nodes
> You should register all [custom node types](nodes.md) in the editor.
Expand All @@ -39,14 +37,15 @@ To prevent infinite loops in node calculation, the graph must not contain cycles
Additionally, you can allow connections only between certain interface types. By default, connections are only allowed between interfaces with the same type. If you want to change this behavior, provide a custom predicate to the [typeComparer](api.md#Editor+typeComparer) field.

The `typeComparer` is a function, that takes an `IConnection` as a parameter and returns a boolean that specifies, whether this connection is allowed or not. The default implementation is:
```ts
(c) => c.from.type === c.to.type;
```js
function compare(connection) {
connection.from.type === connection.to.type;
}
```

### Adding / removing connections
[addConnection](api.md#Editor+addConnection)

[removeConnection](api.md#Editor+removeConnection)
Use the [addConnection](api.md#Editor+addConnection) and [removeConnection()](api.md#Editor+removeConnection) methods
for adding or removing connections.

> Never remove a connection from the list yourself! This will result in the connection not being GCed.
> Always use the `removeConnection` method.
Expand Down
37 changes: 37 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Getting Started

First, you need to install the library:
```bash
# npm
npm i baklavajs

# yarn
yarn add baklavajs
```

Now you need to tell Vue to use this library. Add the following code in your application entry file (usually `index.js` or `main.js`):
```js
import BaklavaJS from "baklavajs";
Vue.use(BaklavaJS);
```

The library is now installed and ready to use.
To actually use it, you need to create an `Editor` instance, which you can provide to the editor component.
This is a minimal wrapper component:
```vue
<template>
<baklava-editor :model="editor"></baklava-editor>
</template>
<script>
import { Editor } from "baklavajs";
export default {
data() {
return {
editor: new Editor()
}
}
}
</script>
```
Binary file added docs/img/node_parts.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!-- index.html -->

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta charset="UTF-8">
<link rel="stylesheet" href="//unpkg.com/docsify/themes/vue.css">
<title>BaklavaJS</title>
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: "BaklavaJS",
loadSidebar: true,
subMaxLevel: 2
}
</script>
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
<script src="//unpkg.com/prismjs/components/prism-scss.min.js"></script>
</body>
</html>
19 changes: 0 additions & 19 deletions docs/nodeInterfaces.md

This file was deleted.

7 changes: 0 additions & 7 deletions docs/options/button.md

This file was deleted.

6 changes: 0 additions & 6 deletions docs/options/checkbox.md

This file was deleted.

6 changes: 0 additions & 6 deletions docs/options/input.md

This file was deleted.

6 changes: 0 additions & 6 deletions docs/options/number.md

This file was deleted.

11 changes: 0 additions & 11 deletions docs/options/select.md

This file was deleted.

6 changes: 0 additions & 6 deletions docs/options/text.md

This file was deleted.

Loading

0 comments on commit 18ccb2c

Please sign in to comment.