Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node Based Editing #2

Open
rodydavis opened this issue Mar 11, 2024 · 14 comments
Open

Node Based Editing #2

rodydavis opened this issue Mar 11, 2024 · 14 comments

Comments

@rodydavis
Copy link

rodydavis commented Mar 11, 2024

I am working on a node based editor that is also aiming to be generic and an open format.

I also store the relationships in a pretty similar way, but curious if there could be some support for edges and nodes with additional metadata:

{
  "nodes": [
    {
      "id": "node-1",
      "type": "number-value",
      "x": 36,
      "y": 48,
      "width": 176,
      "height": 68,
      "inputs": {
          "source": {
             "type": "number",
             "value": "1"
          }
      },
      "outputs": {
          "result": {
             "type": "number",
             "value": "#source"
          }
      }
    },
    {
      "id": "node-2",
      "type": "number-value",
      "x": 36,
      "y": 48,
      "width": 176,
      "height": 68,
      "inputs": {
          "source": {
             "type": "number",
             "value": "2"
          }
      },
      "outputs": {
          "result": {
             "type": "number",
             "value": "#source"
          }
      }
    },
    {
      "id": "node-3",
      "type": "number-add",
      "x": 36,
      "y": 48,
      "width": 176,
      "height": 68,
      "inputs": {
          "left": {
             "type": "number",
             "value": "0"
          },
          "right": {
             "type": "number",
             "value": "0"
          }
      },
      "outputs": {
          "result": {
             "type": "number",
             "value": "#left + #right"
          }
      }
    }
  ],
  "edges": [
    {
      "id": "edge-1",
      "fromNode": "node-1",
      "fromSide": "right",
      "fromEnd": "none",
      "toNode": "node-3",
      "toSide": "left",
      "toEnd": "arrow",
      "metadata": {
          "output": "#result",
          "input": "#left"
      },
    },
    {
      "id": "edge-2",
      "fromNode": "node-2",
      "fromSide": "right",
      "fromEnd": "none",
      "toNode": "node-3",
      "toSide": "left",
      "toEnd": "arrow",
      "metadata": {
          "output": "#result",
          "input": "#right"
      },
    }
  ]
}

This could allow an expressive format for editing between applications too.

The metadata object could also be top level but might conflict with spec properties:

{
  "id": "edge-1",
  "fromNode": "node-1",
  "fromSide": "right",
  "fromEnd": "none",
  "toNode": "node-3",
  "toSide": "left",
  "toEnd": "arrow",
  "output": "#result",
  "input": "#left"
}
@rodydavis
Copy link
Author

node-demo.mov

@nqthqn
Copy link

nqthqn commented Mar 11, 2024

@rodydavis — Could you render an edge's label property inside the nodes? Maybe with the use of a delimiter to accommodate labels in fromNode and toNode?

io.canvas

{
  "nodes": [
    {
      "id": "A"
    },
    {
      "id": "B"
    },
    {
      "id": "C"
    }
  ],
  "edges": [
    {
      "id": "e1",
      "fromNode": "A",
      "toNode": "C",
      "label": "A side label :: C side label, from A"
    },
    {
      "id": "e2",
      "fromNode": "B",
      "toNode": "C",
      "label": "B side label :: C side label, from B"
    }
  ]
}

@rodydavis
Copy link
Author

Specifically the extra information is needed to connect not just to a side, but to a specific input/output.

If I used the existing schema I could probably do the following:

{
  "nodes": [
    {
      "id": "node-1",
      "type": "number-value",
      "x": 36,
      "y": 48,
      "width": 176,
      "height": 68,
      "inputs": {
          "source": {
             "type": "number",
             "value": "1"
          }
      },
      "outputs": {
          "result": {
             "type": "number",
             "value": "#source"
          }
      }
    },
    {
      "id": "node-2",
      "type": "number-value",
      "x": 36,
      "y": 48,
      "width": 176,
      "height": 68,
      "inputs": {
          "source": {
             "type": "number",
             "value": "2"
          }
      },
      "outputs": {
          "result": {
             "type": "number",
             "value": "#source"
          }
      }
    },
    {
      "id": "node-3",
      "type": "number-add",
      "x": 36,
      "y": 48,
      "width": 176,
      "height": 68,
      "inputs": {
          "left": {
             "type": "number",
             "value": "0"
          },
          "right": {
             "type": "number",
             "value": "0"
          }
      },
      "outputs": {
          "result": {
             "type": "number",
             "value": "#left + #right"
          }
      }
    }
  ],
  "edges": [
    {
      "id": "edge-1",
      "fromNode": "node-1#result",
      "fromSide": "right",
      "fromEnd": "none",
      "toNode": "node-3#left",
      "toSide": "left",
      "toEnd": "arrow"
    },
    {
      "id": "edge-2",
      "fromNode": "node-2#result",
      "fromSide": "right",
      "fromEnd": "none",
      "toNode": "node-3#right",
      "toSide": "left",
      "toEnd": "arrow"
    }
  ]
}

This would required renderers to ignore everything after the # for fromNode and toNode, but would totally work

@rodydavis
Copy link
Author

This would be a custom node type, with default edge rendering that if the editor supported it could map the edges directly to the inputs/outputs.

@rodydavis
Copy link
Author

Could also be useful for projects like unit too:
https://github.com/samuelmtimbo/unit

@rodydavis
Copy link
Author

Also good progress on flutter renderer:

Screenshot 2024-03-11 at 11 21 49 PM

@rodydavis
Copy link
Author

Also found this interesting, might be asking for ports:
https://rtsys.informatik.uni-kiel.de/confluence/display/KIELER/JSON+Graph+Format

@jg-l
Copy link
Contributor

jg-l commented Mar 22, 2024

node-demo.mov

This is super neat btw.

Can easily make custom Node, (obviously wouldn't be fully compliant to JSON Canvas spec by @kepano) with my library https://github.com/jg-l/json_canvas

The Node class is sealed right now, but easy to amend it as just an abstract class for more extensibility

class NumberNode extends Node {
  final num inValue;
  final num outValue;
  NumberNode({
    required this.inValue,
    required this.outValue,
    required super.id,
    required super.type,
    required super.x,
    required super.y,
    required super.width,
    required super.height,
    super.color,
  });
}

@rodydavis
Copy link
Author

Here is the schema I created with dart_mappable:

https://gist.github.com/rodydavis/17a0a19c8d91a08e2674a57b93ba5259

@rodydavis
Copy link
Author

I used a discriminatorKey to be able to add custom nodes in the future and support a know good fallback too

@jg-l
Copy link
Contributor

jg-l commented Mar 22, 2024

Your implementation is clean! I was hesitant to leverage a 3rd party package or build_runner in my implementation, at the cost of of more boilerplate though!

@rodydavis
Copy link
Author

I think dart_mappable is a awesome compromise because it is easy to extend and adjust overtime!

@rodydavis
Copy link
Author

The nice thing about a spec, is that there can be multiple implementations that all work together! 👍🏻

@nileshtrivedi
Copy link

I had built a SVG-based graph dataset editor: https://codeberg.org/nilesh/grapher . Here is a demo site.

image

The design constraints were ability to import and export clean data, not requiring a server or accounts etc.

Will it be useful to add support for JSONCanvas format in this tool?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants