projectstorm / react-diagrams

a super simple, no-nonsense diagramming library written in react that just works
https://projectstorm.cloud/react-diagrams
MIT License
8.61k stars 1.17k forks source link

Why not react? #1039

Open mastir opened 3 weeks ago

mastir commented 3 weeks ago

Hey! Thanks for this lib, i have used it in my project and its pretty good, but after some time i started asking myself "why?". And after few days i can not find answer.

  1. We create engine as global context for our elements, state machine, factories. And same do createContext in react.
  2. We use action based state machine for action processing and useReducer in react do absolutly the same and more.
  3. We use serialization to convert our elements into json representation and deserialization with factories to recreate and display our elements. And thats what react components do: take our data and render it.

So we can have something like:

let node = {
    x: 10,
    y: 10,
    ports: [
        {name: 'First port'},
        {name: 'Second port'},
    ]
}
return <Engine>
    <StateMachine>
        <DefaultState>
            <SelectingState />
        </DefaultSate>
        <DragNodeState />
        <CreateLinkState allowLooseLinks={false} />
    </StateMachine>
    <Canvas>
        <LinksLayer />
        <Node model={node}>
            <h1>Hello world!</h1>

            {node.ports.map( port =>  <div>
                <Port align={"left"} model={port}>
                    <div style={{background:'#00F',width:16,height:16,display:'inline-block'}}></div>
                </Port>
                {port.name}
            </div>)}
        </Node>
    </Canvas>

With absolutly same result, but simple

So is there any real reason not to do so?

mastir commented 2 weeks ago

After some development i have something usable. Took some time to handle zoom correctly with transform and scroll. Also thinking about change coordinat grid to put [0,0] point in the center of canvas.


    const engine = useMemo(() => {
        const engine = new EngineModel();
        engine.state.addStateHandler(new DefaultState());
        engine.state.addStateHandler(new CreateLinkState());
        engine.state.addStateHandler(new DragNodeState());
        engine.state.actions.push(new ZoomHandler(engine));
        window.engine = engine;
        return engine;
    }, []);

    let node = {
        x: 2000-85,
        y: 2000-60,
        ports: [
          {name: 'First port!'},
          {name: 'Second port'},
        ]
    }

    return <Diagram engine={engine} style={{minHeight:'100vh'}} size={[4000,4000]}>
          <Node node={node}>
              <h1>Hello world!</h1>

              {node.ports.map( (port,i) =>  <div key={i}>
                  <Port
                      key={i}
                      port={port}
                      canConnect={()=>true}
                      onConnect={port2 => {console.log('connected', port, port2)}}
                  >
                      <div style={{background:'#00F',width:16,height:16,display:'inline-block'}}/>
                  </Port>
                  {port.name}
              </div>)}
          </Node>
  </Diagram>;

Знімок екрана з 2024-08-27 09-59-54

mastir commented 2 weeks ago

Made a simple demo.

https://codesandbox.io/p/sandbox/react-diagram-sv4743

Same concept, but simple react implementation. There is minor zoom bug i found today and probably will find mach more later. But for starter looks just fine, probably i will do some rendering optimisations later.

Any ccollaboration is welcomed. https://github.com/mastir/react-diagram