masalibの日記

システム開発、運用と猫の写真ブログです

beautiful-react-diagramsをやってみた

はてなブックマークに下記のリンクがあった

https://github.com/beautifulinteractions/beautiful-react-diagrams

ダイアグラムを簡単に作成するための軽量のReactコンポーネント

必要になる事はたぶんないと思うが気になってみたら サンプルの画像がない・・・

おいどうなっているねん!!

という事でいつもどおりcodesandboxで作ってみた

f:id:masalib:20201120084204p:plain

インストール

npm install beautiful-react-diagrams

私が作ったサンプルはver0.4.0です

ソース

クリックすると展開されます(長文なんで注意)

import React from "react";
import "beautiful-react-diagrams/styles.css";
import Diagram, { createSchema, useSchema } from "beautiful-react-diagrams";

// the diagram model
const initialSchema = createSchema({
  nodes: [
    {
      id: "node-1",
      content: "Node 1",
      coordinates: [250, 60],
      inputs: [{ id: "port-11", alignment: "left" }],
      outputs: [{ id: "port-12", alignment: "right" }]
    },
    {
      id: "node-2",
      content: "Node 2",
      coordinates: [100, 200],
      inputs: [{ id: "port-21", alignment: "left" }],
      outputs: [{ id: "port-22", alignment: "right" }]
    },
    {
      id: "node-3",
      content: "Node 3",
      coordinates: [250, 220],
      inputs: [{ id: "port-31", alignment: "left" }],
      outputs: [{ id: "port-32", alignment: "right" }]
    },
    {
      id: "node-4",
      content: "Node 4",
      coordinates: [400, 200],
      inputs: [{ id: "port-41", alignment: "left" }],
      outputs: [{ id: "port-42", alignment: "right" }]
    }
  ],
  links: [
    { input: "node-1", output: "node-2" },
    { input: "node-1", output: "node-3" },
    { input: "node-1", output: "node-4" }
  ]
});

const UncontrolledDiagram = () => {
  // create diagrams schema
  const [schema, { onChange }] = useSchema(initialSchema);

  return (
    <div style={{ height: "22.5rem" }}>
      <Diagram schema={schema} onChange={onChange} />
    </div>
  );
};

const CustomNode = (props) => {
  const { inputs } = props;

  return (
    <div onClick={test1}  style={{ background: "#717EC3", borderRadius: "10px" }}>
      <div style={{ padding: "10px", color: "white" }}>Custom Node</div>
      <div style={{ marginTop: "20px" }}>
        {inputs.map((port) =>
          React.cloneElement(port, {
            style: { width: "50px", height: "25px", background: "#1B263B" }
          })
        )}
      </div>
    </div>
  );
};

function test1(){
  console.log("test1")

}

const initialSchema2 = createSchema({
  nodes: [
    {
      id: "node-1",
      content: "Node 1",
      coordinates: [150, 60],
      inputs: [{ id: "port-11", alignment: "left" }],
      outputs: [{ id: "port-12", alignment: "right" }]
    },
    {
      id: "node-custom",
      coordinates: [250, 60],
      render: CustomNode,
      inputs: [{ id: "custom-port-1", alignment: "left" }],
      outputs: [{ id: "port-2", alignment: "right" }]
    }
  ],
  links: [{ input: "custom-port-1", output: "port-12" }]
});

const UncontrolledDiagram2 = () => {
  // create diagrams schema
  const [schema, { onChange }] = useSchema(initialSchema2);

  return (
    <div style={{ height: "22.5rem" }}>
      <Diagram schema={schema} onChange={onChange} />
    </div>
  );
};

export default function App() {
  // create diagrams schema
  return (
    <>
      <div>test1 </div>
      <UncontrolledDiagram />
      <div>test2 </div>
      <UncontrolledDiagram2 />
    </>
  );
}

結果

ソース解説

基本的にはイニシャルのノードとそれを結ぶリンクを設定するのみだった。

nodeについて

nodeはIDとタイトルと初期の場所が必須だった。 inputとoutputに関しては必須ではない

Linkを増やす事を考慮するとnodeにinputとoutputを設定しておいた方がいい。いらないのはあとで消せばいい

  nodes: [
    { id: 'node-1', content: 'Node 1', coordinates: [250, 60], inputs: [{ id: "port-11", alignment: "left" }], outputs: [{ id: "port-12", alignment: "right" }]},
    { id: 'node-2', content: 'Node 2', coordinates: [100, 200],inputs: [{ id: "port-21", alignment: "left" }], outputs: [{ id: "port-22", alignment: "right" }] },
    { id: 'node-3', content: 'Node 3', coordinates: [250, 220],inputs: [{ id: "port-31", alignment: "left" }], outputs: [{ id: "port-32", alignment: "right" }] },
    { id: 'node-4', content: 'Node 4', coordinates: [400, 200],inputs: [{ id: "port-41", alignment: "left" }], outputs: [{ id: "port-42", alignment: "right" }] },
  ],

ちなみにサンプルだとinputとoutputはなかった。

https://github.com/beautifulinteractions/beautiful-react-diagrams/blob/master/docs/basic-usage.md

微妙に気に食わない場所が気に食わないとかあった場合は ブラウザで表示させて、Nodeを動かす。その後、React DevToolsで値を調べてばプログラム側に反映すればいい感じになる

f:id:masalib:20201120084417g:plain

カスタムnodeについて

nodeの色とか形とか気に食わないなら自分でnodeを作る事ができる

const CustomNode = (props) => {
  const { inputs } = props;
  
  return (
    <div style={{ background: '#717EC3', borderRadius: '10px' }}>
      <div style={{ padding: '10px', color: 'white'  }}>
        Custom Node
      </div>
      <div style={{marginTop: '20px'}}>
        {inputs.map((port) => React.cloneElement(port, {
          style: { width: '50px', height: '25px', background: '#1B263B' }
        }))}
      </div>
    </div>
  );
};

Nodeの初期のデザインがよくないのでこの機能は必要かと思う。 クリックイベントなどは登録できなかった。

リンクについて

nodeとnodeを結ぶリンクを作る事ができる

  links: [
    { input: "node-1", output: "node-2" },
    { input: "node-1", output: "node-3" },
    { input: "node-1", output: "node-4" }
  ]

inputとoutputのIDを指定するもできる

{"input":"custom-port-1","output":"port-12"}

矢印(Arrow)みたいなものをつける機能が見つからなかった。

感想

  • う・・・・ん・・・微妙・・・もう少しバージョンアップを期待
  • 矢印やクリックイベントが登録できないのはちょっと使い勝手が悪い
  • あとデフォルトのnodeをもう少し増やしてほしい。カスタムのNodeを作るのがめんどくさい