newcat / baklavajs Goto Github PK
View Code? Open in Web Editor NEWGraph / node editor in the browser using VueJS
Home Page: http://baklava.tech
License: MIT License
Graph / node editor in the browser using VueJS
Home Page: http://baklava.tech
License: MIT License
Since my system is more about flow of execution rather than math, the ability for certain types of ports to accept multiple connections would be wonderful.
In Firefox, clicking on a number or integer option to change its value doesn't work. Need to prevent user select in editor to fix this.
export default class PrintNode extends Node {
constructor() {
super();
this.type = "PrintNode";
this.name = this.type;
this.addInputInterface("Value");
this.addOption("input_field","InputOption");
this.addOption("Text_field", "TextOption", "empty");
}
load(state) {
super.load(state);
}
calculate() {
let asd = "Nothing";
**this.getOptionValue("Text_field") = asd;**
console.log(asd);
}
}
So I am trying to pass a string from one Node to this Print node. And I just noticed that I can really jus pass string to text_field option value to change it. Could you help me?
I kinda went around this problem and used InputOption and then used setOptionValue.
Also could you please provide any examples on how to save all nodes and then load them? There are not much information in documentation (examples)
When using BaklavaJS in a native js environment is it still possible to use the sidebar?
Is there any way I can emulate a Vue component to register as an option?
I can only imagine VueJS is attempting to redraw the entire scene when moving a node around, because serious lag starts to occur on my machine at around 30 nodes. Only the node in question and the connections on it should be moved/redrawn, however I'm pretty sure the entire graph is.
It may be useful to include a CSS class named node-<category >
in the parent node div, so that similar nodes can be styled differently. For example: render math nodes with a blue title, smaller in width, or no border radius at all.
Hello, I'm using this example code from BaklavaJS docs (https://newcat.github.io/baklavajs/#/custom-nodes?id=class) and my select option looks like this https://imgur.com/TzcKsm3 and I can't select any option. I'm doing something wrong?
Vue 2.6.11
Electron 8.2.3
In order to allow better styling for ports, perhaps add a style to it depending on their type. For example: adding the "string" type to a port will add the CSS class "__port-string." This would allow, for example, square or triangle ports for ease of recognition in extra special port types.
I'm working on an app and i need to have two nodes (a start and an end) on application load.
is there a way to add a node programatically?, i'm kinda confused with the documentation. should i save the whole state and load it on application start?.
i found this method addNode but i cant seem to find which parameters receives to add the node.
could you please provide an example?
Hi
Can anybody provide me with an example of how it could/should work together with Electron? I really have no idea how it's supposed to work together
Thanks
I downloaded newcat/ledmusic3 to make sure it isn't a problem on my end. If you have the BaklavaJS canvas and you open devtools, the menus for right clicking and creating new nodes are thrown off.
Hi!
I would like to use this library inside a Vue application.
As far as I understand, I need to create custom node types (I used the nodeBuilder for this) and registering them inside the created() Vue lifecycle hook. After that I have an editor instance and I can select my custom node types from the context menu. The engine needs for calculation and it could be automatic. It is ok and clear I think.
But after that, how could I access these calculated results/values outside typscript nodes to access them for later using in my Vue app?
Should I use for this: the engine? subscribing events? or how?
How could I pass some params from the Vue app to my custom nodes? (I want to use my own dynamic values as the rootNode value).
Thanks
It look like a perfect editor node. But the documentation still very hard to follow . Can you put a simple example code to help us understand the basic for the library.
Thanks
When I use the mouse to drag a block or the whole view around it moves at twice the speed.
I'm using the native version with angular.
Here is it recorded
https://streamable.com/ll0wpc
I just updated BaklavaJS to the latest version and now nothing builds. I think something is wrong with the build/dependency configuration, especially with regards to @baklavajs/events
. A reproducer that shows the same error has been attached. repro.zip
This is my package.json.
{
"name": "vision_frontend_vue",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"profile": "vue-cli-service build --report"
},
"dependencies": {
"@baklavajs/core": "~1.5.2",
"@baklavajs/plugin-interface-types": "~1.5.2",
"@baklavajs/plugin-renderer-vue": "~1.5.2",
"core-js": "^3.6.4",
"vue": "^2.6.11",
"vue-class-component": "^7.2.3",
"vue-property-decorator": "^8.4.1",
"vue-router": "^3.1.6",
"vuetify": "^2.2.21"
},
"devDependencies": {
"@mdi/font": "^5.0.45",
"@vue/cli": "^4.3.1",
"@vue/cli-plugin-babel": "^4.3.1",
"@vue/cli-plugin-typescript": "^4.3.1",
"@vue/cli-service": "^4.3.1",
"sass": "^1.26.3",
"sass-loader": "^8.0.2",
"typescript": "^3.8.3",
"vue-cli-plugin-vuetify": "^2.0.5",
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.4.3"
}
}
Error Message:
> [email protected] build /home/steven/vision_frontend_vue
> vue-cli-service build
Starting type checking and linting service...
Using 1 worker with 2048MB memory limit
ERROR Failed to compile with 10 errors4:59:52 PM
error in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/connection.d.ts
ERROR in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/connection.d.ts(2,30):
2:30 Cannot find module '@baklavajs/events'.
1 | import { NodeInterface } from "./nodeInterface";
> 2 | import { BaklavaEvent } from "@baklavajs/events";
| ^
3 | import { IConnection, ITransferConnection } from "../types/connection";
4 | export declare class Connection implements ITransferConnection {
5 | id: string;
error in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/editor.d.ts
ERROR in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/editor.d.ts(5,71):
5:71 Cannot find module '@baklavajs/events'.
3 | import { Connection, DummyConnection } from "./connection";
4 | import { IState } from "../types/state";
> 5 | import { PreventableBaklavaEvent, BaklavaEvent, SequentialHook } from "@baklavajs/events";
| ^
6 | import { IEditor, IPlugin, IConnection, NodeConstructor, INode, IAddConnectionEventData, IAddNodeTypeEventData } from "../types";
7 | /** The main model class for BaklavaJS */
8 | export declare class Editor implements IEditor {
error in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/node.d.ts
ERROR in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/node.d.ts(4,71):
4:71 Cannot find module '@baklavajs/events'.
2 | import { INodeState } from "../types/state";
3 | import { Editor } from "./editor";
> 4 | import { PreventableBaklavaEvent, BaklavaEvent, SequentialHook } from "@baklavajs/events";
| ^
5 | import { NodeOption } from "./nodeOption";
6 | import { INode, IAddInterfaceEventData, IAddOptionEventData, IOptionEventData, INodeUpdateEventData } from "../types";
7 | export interface IInterfaceCreateOptions {
error in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/nodeInterface.d.ts
ERROR in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/nodeInterface.d.ts(2,71):
2:71 Cannot find module '@baklavajs/events'.
1 | import { IInterfaceState } from "../types/state";
> 2 | import { BaklavaEvent, PreventableBaklavaEvent, SequentialHook } from "@baklavajs/events";
| ^
3 | import { INodeInterface, INode } from "../types";
4 | export declare class NodeInterface implements INodeInterface {
5 | id: string;
error in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/nodeOption.d.ts
ERROR in /home/steven/vision_frontend_vue/node_modules/@baklavajs/core/dist/baklavajs-core/src/nodeOption.d.ts(2,55):
2:55 Cannot find module '@baklavajs/events'.
1 | import { INodeOption } from "../types/nodeOption";
> 2 | import { PreventableBaklavaEvent, BaklavaEvent } from "@baklavajs/events";
| ^
3 | export declare class NodeOption implements INodeOption {
4 | /** Name of the component that should be displayed for the option */
5 | optionComponent: string;
error in /home/steven/vision_frontend_vue/node_modules/@baklavajs/plugin-renderer-vue/dist/baklavajs-plugin-renderer-vue/src/viewPlugin.d.ts
ERROR in /home/steven/vision_frontend_vue/node_modules/@baklavajs/plugin-renderer-vue/dist/baklavajs-plugin-renderer-vue/src/viewPlugin.d.ts(3,32):
3:32 Cannot find module '@baklavajs/events'.
1 | import { VueConstructor } from "vue";
2 | import { IPlugin, IEditor } from "../../baklavajs-core/types";
> 3 | import { SequentialHook } from "@baklavajs/events";
| ^
4 | import { IViewPlugin } from "../types";
5 | import NodeView from "./components/node/Node.vue";
6 | import NodeOptionView from "./components/node/NodeOption.vue";
error in /home/steven/vision_frontend_vue/src/options/CheckboxOption.vue
ERROR in /home/steven/vision_frontend_vue/src/options/CheckboxOption.vue(16,29):
16:29 Cannot find module '@baklavajs/core/dist/types'.
14 | <script lang="ts">
15 | import { Component, Vue, Prop } from "vue-property-decorator";
> 16 | import { INodeOption } from "@baklavajs/core/dist/types";
| ^
17 |
18 | @Component
19 | export default class NumberOption extends Vue {
error in /home/steven/vision_frontend_vue/src/options/NumberOption.vue
ERROR in /home/steven/vision_frontend_vue/src/options/NumberOption.vue(37,29):
37:29 Cannot find module '@baklavajs/core/dist/types'.
35 | <script lang="ts">
36 | import { Component, Vue, Prop } from "vue-property-decorator";
> 37 | import { INodeOption } from "@baklavajs/core/dist/types";
| ^
38 |
39 | @Component
40 | export default class NumberOption extends Vue {
error in /home/steven/vision_frontend_vue/src/options/RangeOption.vue
ERROR in /home/steven/vision_frontend_vue/src/options/RangeOption.vue(49,29):
49:29 Cannot find module '@baklavajs/core/dist/types'.
47 | <script lang="ts">
48 | import { Component, Vue, Prop } from "vue-property-decorator";
> 49 | import { INodeOption } from "@baklavajs/core/dist/types";
| ^
50 |
51 | @Component
52 | export default class NumberOption extends Vue {
error in /home/steven/vision_frontend_vue/src/options/TextOption.vue
ERROR in /home/steven/vision_frontend_vue/src/options/TextOption.vue(18,29):
18:29 Cannot find module '@baklavajs/core/dist/types'.
16 | <script lang="ts">
17 | import { Component, Vue, Prop } from "vue-property-decorator";
> 18 | import { INodeOption } from "@baklavajs/core/dist/types";
| ^
19 |
20 | @Component
21 | export default class TextOption extends Vue {
Hi, blur event on html elements isn't called when I start dragging baklavajs nodes. Any ideas how to fix this?
Hi, @newcat thank you for your work. Any plans to make Baklava.js working on mobile devices?
Currently it does not pan. Nodes dragging does not work also...
Hi @newcat What you have done is really awesome! I am using it with Vuetify for a new project. Is there a way to create a thumbnail with current node editor? So that the diagram could be selected by the thumbnail. Also, is it possible to have minimap support? It's really useful for navigating when there're many nodes in the editor.
Thanks!
Not exactly an issue, but a feature request. I'm using this library in an attempt to build a sort of visual programmer for my quest system, however the lack of a way to make a nice looking "execution input/output" is a bit annoying.
I'm hoping this is something that you'll consider adding, as this is the only library that I can get to reliably work within VueJS. Thanks in advance! ^^
If not, if you could perhaps point me in the right direction to the location in which I can add the feature myself, that would be great!
Also, if you could also consider having an option to move the options below the inputs and outputs, that would also be great!
While I can sort of understand why, you use one Object for interfaces, however this seems very limiting and unnecessary.
(this is less of an issue and more of a discussion question around the Engine, apologies it's a bit long)
I've been wondering if the Engine can/should be changed to abort and/or restart a calculation if a new one is requested while a previous one is in progress. I ended up running into a small issue with the Engine's calculateOnChange
behavior due to some event ordering triggering an onChange(false) immediately before an onChange(true), in which case the onChange(true) essentially gets dropped (and the node ordering does not get recalculated) because the calculation started by the onChange(false) was still in progress. I was able to work around that by making some of my code asynchronous to ensure the onChange(true) fires before the onChange(false) (see https://github.com/skipscooters/mapgraphs/blob/e4795f877b250f5facb4ffc1fb92a1a58226a12d/app/src/nodes/DynamicInputsNodeBase.ts#L42 for the actual implementation if you're curious), but that's what initially prompted my thinking about how concurrent calculation requests are/should be handled by an Engine.
The second related concern I ran into was with calculations that take a while. Since calculate is async, it's easy to have instances where the user is changing the graph while a calculation is in progress, and right now that doesn't play too well with calculateOnChange (since a change during a calculation doesn't trigger a new calculation, it's just dropped).
So one idea I had would be to make the Engine restart a new calculation once the first one completes if a change occurred during that calculation (and potentially looping repeatedly if there continue to be changes during the restarted calculations). Then a potential improvement on top of that could be to allow calculations to be aborted, so that if the graph is changed during a calculation the Engine doesn't need to finish calculating all the nodes before starting a new calculation (this has some potential issues if node calculations aren't pure functions, but there are always going to be potential race conditions as long as graph changes are allowed to happen concurrently with calculations, so the calculations kind of need to be pure functions regardless).
One other topic I was also thinking about was the fact that Engine.calculate doesn't have any mutual exclusion (except for internal onChange-triggered calculations), which could be problematic if multiple long-running calculations are triggered concurrently with different data, since the intermediate calculation results are stored on the shared graph (nodes and interface values) during a calculation. You could imagine a case where a node's calculate method is async and takes a nondeterministic amount of time (e.g. making a network request), which could result in a second concurrent calculate() actually "passing" the first as it makes its way through the graph, resulting in potentially inconsistent/corrupt data throughout the graph. I don't really see a good way to prevent this other than mutual exclusion, unless each calculation operated on a cloned graph or something.
I'm happy to jump in and try making some of these changes to see how they work out, but wanted to check if you already had any thoughts on the topic first.
Hi, thanks for your outstanding work. I would like to try to use baklavajs for data model editor. Where use has something alike tables and can create relations in between.
Question. Is that possible to make connection clickable? I would like to display a dialog with connection options.
Any suggestions maybe how to use baklavajs for such purposes as mine?
Thanks.
Is there an easy way to inject the min and max of a number into a custom option? I don't see such a thing being possible currently.
Setting up the environment to contribute to this project has proven itself more challenging than I anticipated. It would be useful to include a guide for new contributors to make their lives easier.
After some experimentation I came up with these commands, though I didn't end up setting up a webpack watcher to automatically rebuild the projects on changes. From my digging it doesn't seem this repo includes a quick way of doing that.
# Install Lerna (https://lerna.js.org/)
npm install -g lerna
# Download and setup the repo
git clone [email protected]:newcat/baklavajs.git
cd baklavajs
lerna bootstrap --npm-client=npm
# Build all the packages
lerna run build
# Run the playground (with npm)
cd packages/baklavajs-playground
npm run serve
# Run the playground (with yarn, from project's root directory)
yarn run playground
As evident in this line of Editor.vue
, the node's positions are only updated once the addNode hooks are called. This however, prevents me from saving the nodetree to an API every time the nodetree updates, such as with:
this.editor.events.addNode.addListener({}, async (node) => {
node.events.update.addListener(this, async () => {
await this.save();
});
await this.save();
});
Is there a workaround for this?
I tried to write this myself but ran into stumbling blocks with the SCSS and private interfaces - this would help to let people choose a range of values they want something filtered on.
If the min and the max is 0 and 1 - then the user can choose a range such as [0.5, 0.9] or [0, 1].
When you create a node with a class (like here) and you call this.addOption(...)
not in the constructor but afterward, no option visible gets added. The data still changes but the view doesn't display the new option.
Core Version: 1.5.4
Options Version: 1.5.4
Renderer Version: 1.6.0
Perhaps include category-<id>
and item-<node type>
CSS classes in context menus, so, for example, list items can inherit the color of the node itself. I'd make a PR, but it seems the context menu doesn't get passed any node data, so I'll leave that decision up to you.
Also, hide the divider if no categories or no default nodes exist
When moving a node in Chrome, it moves at a different speed compared to the cursor.
In the event that the context menu has many many items, it can regularly go off screen. Perhaps bump the menu up when it's displayed, and if it's excessively long, make a scroll bar?
Add boxes for comments, and a system for grouping multiple nodes together.
Is this intended? I mean, I guess if you wish to retain renaming, it makes sense, however unless a user has renamed a node, it should be updated on next load to the internal name, don't you think?
Hello, is it possible? If yes, how?
Is there a way to access Node state within option?
Great library! But documentation is kinda sparse. I would love to contribute to the doc after I gain a better understanding of the library ๐โโ๏ธ
Is it possible to set which side will be used for output or input?
I would like to have outputs and inputs positioned on the same side for some of my nodes.
Thanks.
Apparently, Firefox has a different deltaY
value per mouse wheel event. Currently, the deltaY
value is divided by a constant of 3000 in the Editor.vue. This probably needs to be changed for Firefox.
The exception for -moz-user-select
also needs to include textarea
(and maybe other elements? Maybe also add a special class to this exception that users can apply to their controls/options?) https://github.com/newcat/baklavajs/blob/master/packages/baklavajs-plugin-renderer-vue/src/styles/node-editor/node-editor.scss#L17
In the event a connection port is styled a different color, it would be very useful to be able to make a distinction between connection lines by styling the line the same color as the ports they connect between.
The current NodeBuilder
API reuses a single argument for both the node type and name. This makes it unnecessarily difficult to set a more user friendly display name for the node. It also completely removes the ability to translate names of nodes created with NodeBuilder
.
I've been building some nodes with dynamic interfaces (similar to AdvancedNode in the playground), and when testing the editor.load()
behavior to make sure I restore nodes correctly, I noticed some odd behavior with load()
that seems like a bug. Apologies if I'm misunderstanding something, as I'm new to both Vue and baklavajs.
Video: https://www.dropbox.com/s/1nho08p4trd6vdg/baklavajsBugReport.mov?dl=0
{"nodes":[{"type":"AdvancedNode","id":"node_15859890385070","name":"AdvancedNode","options":[["Add Input",null],["Remove Input",null]],"state":{},"interfaces":[["Input 1",{"id":"ni_15859890416291"}],["Input 2",{"id":"ni_15859890422752"}],["Input 3",{"id":"ni_15859890428753"}],["Input 4",{"id":"ni_15859890466834"}]],"position":{"x":414,"y":128},"width":200,"twoColumn":false}],"connections":[],"panning":{"x":0,"y":0},"scaling":1}
I suspect the issue stems from the fact that nodes (and their corresponding Vue components) are getting torn down and recreated during the load(), and when they're recreated their id
is also being restored (as expected, so that their state can be restored as well).
It looks like normally changes to a Node's interfaces trigger updates of the Vue component via the Node's events, which are subscribed to in mounted()
(
However, when I inspect the Node that was created by the load()
, it doesn't have any listeners registered on its addInterface/removeInterface events, unlike the original Node. That seems to match the observed behavior -- changes to the interfaces don't trigger the DOM to update, since there's no listener registered to trigger a forceUpdate, but taking another action like clicking/moving the node modifies some other reactive state and causes Vue to update with the latest data.
I'm not familiar with Vue's caching/reuse strategy, but my hunch is that this behavior could be due to Vue caching the old Node.vue
component instance, and then reusing that instance for the new Node. The new Node would have the same .id
value that's used as the v-for
:key
attribute (
If my assumptions are correct, then it seems like one potential fix would be to change the :key
value so it's a truly unique id per Node instance, rather than the .id
which gets restored when a Node is load()
ed from saved state.
Hopefully this makes sense and is helpful! And thanks so much for building this project, I've really enjoyed working with it so far!
I can't find anything useful about this in the docs. Right now I have this code called on button click (data is string):
editor.load(data);
but it causes
Uncaught TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
.
Thanks for help!
See title.
Node.addOption has a default parameter defaultValue that defaults to null
, but NodeBuilder.addOption has an optional parameter defaultValue which therefore is undefined
if not set. However, you can't set null
as the defaultValue with a NodeBuilder (to match the Node behavior) because it checks typeof
the value and throws because typeof(null)
is "object"
.
Not a major issue, but it did catch me off-guard
Ok, I have an educational project where I need to create a bot using a nonSQL DB (firebase, mongodb etc).
I'll try my best to explain what I'm trying to do:
So, I have a chat bot, where it's structure is object oriented, where the object names matters, and each object is composed by,
A Text and it's next steps.
All object steps are structured the same way.
example of S Objects (S is just a prefix for the object name):
s0: {
text: "Hello and welcome to botchat."
nextStep: {
"1": { description: "show Website link", target: "s1"}
"2": { description: "end chat", target: ""}
}
}
s1: {
text: "some website here."
nextStep: {}
}
I have a backend to treat it, so don't really mind so much how it works,
So, what I am trying to do is create a Node where it acts like these S Objects.
Is it possible make the bot flow using baklavajs? is Yes, how hard will it be?
P.S. I'm coding with Angular 9 framework
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.