React-diagrams: Integrating in an React Project

Created on 27 Dec 2019  路  14Comments  路  Source: projectstorm/react-diagrams

I have a strange problem
I have a react front-end with antd integrated.

I tried creating a view, by following the instructions at https://projectstorm.gitbook.io/react-diagrams/getting-started/using-the-library

  1. link.addLabel('Hello World!'); - doesn't compile . It complains saying link.addLabel is not a function

  2. So, I comment out that line.. and then it stops complaing.

But now I have a strange problem - the mounts but the node 1 and node 2 are not displayed. They are present in the DOM though! See attached image

react-storm-error

question

Most helpful comment

@renato-bohler yep this worked for me. I went the css class route, but I did have to add !important or else my changing of the position property was ovewritten.

My App.css:

.App {
  text-align: center;
}

.canvas{
  position: inherit !important;
}

also for reference for anyone else looking for a create-react-app solution here is my whole App.tsx:

import React, { Component } from 'react';
import './App.css'

import createEngine, {
  DefaultLinkModel,
  DefaultNodeModel,
  DiagramModel
} from '@projectstorm/react-diagrams';

import {
  CanvasWidget
} from '@projectstorm/react-canvas-core';

const App = () => {
  console.log('running in app!');

  // create an instance of the engine with all the defaults
  const engine = createEngine();

  // node 1
  const node1 = new DefaultNodeModel({
    name: 'Node 1',
    color: 'rgb(0,192,255)',
  });
  node1.setPosition(100, 100);
  let port1 = node1.addOutPort('Out');

  // node 2
  const node2 = new DefaultNodeModel({
    name: 'Node 2',
    color: 'rgb(192,192,255)',
  });
  node2.setPosition(200, 100);
  let port2 = node2.addInPort('In');

  // link them and add a label to the link
  const link = port1.link<DefaultLinkModel>(port2);
  //link.addLabel('Hello World!');

  const model = new DiagramModel();
  model.addAll(node1, node2, link);
  engine.setModel(model);

  return (
    <div className="app-wrapper">
      <div></div>
      <div style={{ height: "100vh", width: "90%", backgroundColor: "aliceblue"}}>
        <CanvasWidget className="canvas" engine={engine} />
      </div>

    </div>
  );
}

export default App;

All 14 comments

Give your top div (canvas) a height and width of 100%

I still have the same problem
react-storm-error-1A

Here is my code for render

`class MindmapView extends Component {
render() {
// create an instance of the engine with all the defaults
const engine = createEngine();

// node 1
const node1 = new DefaultNodeModel({
    name: 'Node 1',
    color: 'rgb(222,192,0)',
});
node1.setPosition(100, 30);
let port1 = node1.addOutPort('Out');

// node 2
const node2 = new DefaultNodeModel({
    name: 'Node 1',
    color: 'rgb(255,0,255)',
});
node2.setPosition(70, 100);
let port2 = node2.addOutPort('Out');

// link them and add a label to the link
const link = port1.link<DefaultLinkModel>(port2);
//link.addLabel('Hello World!');

const model = new DiagramModel();
model.addAll(node1, node2);
engine.setModel(model);

const styles = {
    margin: '20px',
    width: '100%',
    height: '100%',
    backgroundColor: 'yellow',
};
return (
<CanvasWidget className="hijibiji" engine={engine} style={styles}/>

);

}
}
export default MindmapView;`

Interesting though, when I add the styles inline - the nodes appear. I will check the antd documentation.

react-storm-error-1A

Any resolution of the link.addLabel function?

For the label:

Isn't it just a typescript issue? Try this:

import { DefaultLinkModel } from '@projectstorm/react-diagrams';

(link as DefaultLinkModel).addLabel('Custom label 1');

The issue is dued to "overflow: hidden" I think. I noticed something similar and had to overwrite CSS rules in my project

I found a similar problem with antd, they add overflow hidden to SVGs

const StyledCanvas = styled(CanvasWidget)`
  flex: 1 1 auto;

  /* This fixes a problem combining react-diagrams with antd */
  & svg:not(:root) {
    overflow: initial;
  }
`;

I added this to resolve it.

It looks like the root div of the "CanvasWidget" is the problem? I haven't found a way to change this css prop in the code yet.

When I uncheck position: relative in styles it shows the nodes, also you will only see one with the demo code as it stacks them on top of each other. Here is my code:

storm_issue

import React, { Component } from 'react';
import render from 'react-dom';

import createEngine, {
  DefaultLinkModel,
  DefaultNodeModel,
  DiagramModel
} from '@projectstorm/react-diagrams';

import {
  CanvasWidget
} from '@projectstorm/react-canvas-core';

const App = () => {
  console.log('running in app!');

  // create an instance of the engine with all the defaults
  const engine = createEngine();

  // node 1
  const node1 = new DefaultNodeModel({
    name: 'Node 1',
    color: 'rgb(0,192,255)',
  });
  node1.setPosition(100, 100);
  let port1 = node1.addOutPort('Out');

  // node 2
  const node2 = new DefaultNodeModel({
    name: 'Node 2',
    color: 'rgb(192,192,255)',
  });
  node2.setPosition(200, 100);
  let port2 = node2.addInPort('In');

  // link them and add a label to the link
  const link = port1.link<DefaultLinkModel>(port2);
  //link.addLabel('Hello World!');

  const model = new DiagramModel();
  model.addAll(node1, node2, link);
  engine.setModel(model);

  return (
    <div>
      <h1>HEYYYY</h1>
      <div style={{ height: "100vh", width: "90%", backgroundColor: "aliceblue"}}>
        <CanvasWidget engine={engine} />
      </div>

    </div>
  );
}

export default App;

Heyyyy @mkellogg91 :smiley:

If you use styled-components you can style it like that:

import styled from 'styled-components';
import { CanvasWidget } from '@projectstorm/react-canvas-core';

// ...

const StyledCanvas = styled(CanvasWidget)`
  // Your CSS changes here
`;

// ...

<StyledCanvas />

Otherwise, you can define a CSS class somewhere in the application and pass it to the className prop:

import { CanvasWidget } from '@projectstorm/react-canvas-core';
import './styles.css'; // the CSS file which defines .myCanvasClass

// ...

<CanvasWidget className="myCanvasClass" />

@renato-bohler yep this worked for me. I went the css class route, but I did have to add !important or else my changing of the position property was ovewritten.

My App.css:

.App {
  text-align: center;
}

.canvas{
  position: inherit !important;
}

also for reference for anyone else looking for a create-react-app solution here is my whole App.tsx:

import React, { Component } from 'react';
import './App.css'

import createEngine, {
  DefaultLinkModel,
  DefaultNodeModel,
  DiagramModel
} from '@projectstorm/react-diagrams';

import {
  CanvasWidget
} from '@projectstorm/react-canvas-core';

const App = () => {
  console.log('running in app!');

  // create an instance of the engine with all the defaults
  const engine = createEngine();

  // node 1
  const node1 = new DefaultNodeModel({
    name: 'Node 1',
    color: 'rgb(0,192,255)',
  });
  node1.setPosition(100, 100);
  let port1 = node1.addOutPort('Out');

  // node 2
  const node2 = new DefaultNodeModel({
    name: 'Node 2',
    color: 'rgb(192,192,255)',
  });
  node2.setPosition(200, 100);
  let port2 = node2.addInPort('In');

  // link them and add a label to the link
  const link = port1.link<DefaultLinkModel>(port2);
  //link.addLabel('Hello World!');

  const model = new DiagramModel();
  model.addAll(node1, node2, link);
  engine.setModel(model);

  return (
    <div className="app-wrapper">
      <div></div>
      <div style={{ height: "100vh", width: "90%", backgroundColor: "aliceblue"}}>
        <CanvasWidget className="canvas" engine={engine} />
      </div>

    </div>
  );
}

export default App;

@renato-bohler do you know where a good redux implementation exists for react-diagrams? I'll have to figure that out too

Hmm I'm not sure if plugging react-diagrams into redux is a good idea... so it would really depend on your use case.

Probably the best option (if you really need it - you probably don't) is to save the serialized diagram on the store when the user click a "Save" or "Send" button, because if you dispatch an action for every change made on the diagram, this would have a considerable impact on performance.

Indeed. It is not recommended at all because Redux objects should be serializable, which the Engine and Model aren't...

@renato-bohler @Letrab
I have a use case where I will have a drag and drop option from a sidebar. I'm going to look into the drag and drop code used in the demos here: http://projectstorm.cloud/react-diagrams/?path=/story/advanced-techniques--drag-and-drop

However, for my use case, we want to be able to drag a "project" onto the canvas which represents many nodes instead of one. I wasn't sure how I would add new nodes to the canvas from a child sidebar component other than redux. Redux has been my solution to those kinds of problems in the past. Any suggestions?

Well, with little adjustments you can achieve that.

  1. Where TrayItemWidget is called, change the prop model to a data structure that contains all nodes and links you want this "project" to add to the diagram, Example:
<TrayItemWidget
  model={{
    nodes: [
      // Serialized nodes goes here
    ],
    links: [
      // Serialized links goes here
    ]
  }} />

These serialized nodes and links could be on the Redux store... they already need to be serialized to be transferred via event.dataTransfer anyway.

  1. Change the onDrop method, which now receives an array of serialized nodes and an array of serialized links, to add those nodes and links to the diagram. Something like that (very, very roughly):
onDrop={event => {
  var data = JSON.parse(event.dataTransfer.getData('storm-diagram-node'));

  var point = this.props.app.getDiagramEngine().getRelativeMousePoint(event);

  // Adds all nodes to the diagram
  data.nodes.forEach(node => {
    // If you have multiple node types, you'll need to find the correct factory
    const add = new YourNodeModel();

    // Adjust the position
    add.setPosition(point.x + node.position.x, point.y + node.position.y)

    // If there's anything else to adjust the node, do it here...

    // Add the node to the diagram
    this.props.app
      .getDiagramEngine()
      .getModel()
      .addNode(add);  
  });

  // Adds all links to the diagram, and connect them to the correct ports
  data.links.forEach(link => {
    // If you have multiple link types, you'll need to find the correct factory
    const add = new LinkModel();

    // Connect them to the correct ports
    /**
     * TODO: logic to find the source and target ports on the diagram which this
     * link is connected to
     * 
     * Something like
     * this.props.app.getDiagramEngine().getModel().getNodes().filter(...)
     */
    const sourcePort = null;// TODO...
    sourcePort.addLink(add);
    add.setSourcePort(sourcePort);

    const targetPort = null;// TODO...
    targetPort.addLink(add);
    add.setTargetPort(targetPort);

    // If there's anything else to adjust the link, do it here...

    // Add the node to the diagram
    this.props.app
      .getDiagramEngine()
      .getModel()
      .addLink(add);  
  });

  this.forceUpdate();
}}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

shortwavedave picture shortwavedave  路  3Comments

Naveenraj006 picture Naveenraj006  路  3Comments

jardg picture jardg  路  3Comments

schecter22107 picture schecter22107  路  3Comments

kmannislands picture kmannislands  路  3Comments