export default function LayoutConnectionBehavior()

in saga/seata-saga-statemachine-designer/src/layout/behavior/LayoutConnectionBehavior.js [173:317]


export default function LayoutConnectionBehavior(injector, layouter, modeling) {
  injector.invoke(CommandInterceptor, this);

  // specify connection start and end on connection create
  this.preExecute([
    'connection.create',
    'connection.reconnect',
  ], (context) => {
    const source = context.newSource || context.source;
    const target = context.newTarget || context.target;

    const orientation = getOrientation(source, target);

    if (!context.hints) {
      context.hints = {};
    }

    assign(context.hints, getConnectionHints(source, target, orientation));
  }, true);

  /**
   * Update incoming connections.
   *
   * @param {djs.model.Shape} target
   * @param {Array<djs.model.Connection>} [connection]
   * @param {string} [orientation]
   */
  function updateConnections(target, connection, orientation) {
    // (1) get connection
    if (!connection) {
      connection = target.incoming;
    }

    let incomingConnectionsByOrientation = {};

    // (2) get connections per orientation
    if (orientation) {
      incomingConnectionsByOrientation[orientation] = connection;
    } else {
      incomingConnectionsByOrientation = getConnectionByOrientation(target, connection);
    }

    // (3) update connections per orientation
    forEach(
      incomingConnectionsByOrientation,
      (connections, ot) => {
        // (3.1) sort connections
        connections = sortConnections(connections, ot);

        // (3.2) get new connection start and end
        const connectionStartEnd = getConnectionsStartEnd(connections, target, ot);

        // (3.3) update connections
        connections.forEach((conn, index) => {
          const connectionStart = connectionStartEnd[index].start;
          const connectionEnd = connectionStartEnd[index].end;

          const waypoints = layouter.layoutConnection(conn, {
            connectionStart,
            connectionEnd,
          });

          modeling.updateWaypoints(conn, waypoints);
        });
      },
    );
  }

  // update connections on connection create and delete
  // update connections of new target on connection reconnect
  this.postExecuted([
    'connection.create',
    'connection.delete',
    'connection.reconnect',
  ], (context) => {
    const { connection } = context;
    const source = connection.source || context.source;
    const target = connection.target || context.target;

    const orientation = getOrientation(source, target);

    // update all connections with same orientation
    const connections = target.incoming.filter((incoming) => {
      const incomingOrientation = getOrientation(incoming.source, incoming.target);

      return isSameOrientation(incomingOrientation, orientation);
    });

    if (!connections.length) {
      return;
    }

    updateConnections(target, connections, orientation);
  }, true);

  // update connections of old target on connection reconnect
  this.preExecute('connection.reconnect', (context) => {
    const { connection } = context;
    const { source } = connection;
    const { target } = connection;

    const orientation = getOrientation(source, target);

    // update all connections with same orientation except reconnected
    const connections = target.incoming.filter((incoming) => {
      const incomingOrientation = getOrientation(incoming.source, incoming.target);

      return incoming !== connection
        && isSameOrientation(incomingOrientation, orientation);
    });

    if (!connections.length) {
      return;
    }

    updateConnections(target, connections, orientation);
  }, true);

  // update connections on elements move
  this.postExecuted('elements.move', LOW_PRIORITY, (context) => {
    const { shapes } = context;
    const { closure } = context;
    const { enclosedConnections } = closure;

    shapes.forEach((shape) => {
      // (1) update incoming connections
      const incomingConnections = shape.incoming.filter((incoming) => {
        return !enclosedConnections[incoming.id];
      });

      if (incomingConnections.length) {
        updateConnections(shape, incomingConnections);
      }

      // (2) update outgoing connections
      shape.outgoing.forEach((outgoing) => {
        if (enclosedConnections[outgoing.id]) {
          return;
        }

        updateConnections(outgoing.target);
      });
    });
  }, true);
}