examples/experimental/bezier/src/bezier-graph-layer.js
function layoutGraph(graph) {
  // create a map for referencing node position by node id.
  const nodePositionMap = graph.nodes.reduce((res, node) => {
    res[node.id] = node.position;
    return res;
  }, {});
  // bucket edges between the same source/target node pairs.
  const nodePairs = graph.edges.reduce((res, edge) => {
    const nodes = [edge.sourceId, edge.targetId];
    // sort the node ids to count the edges with the same pair
    // but different direction (a -> b or b -> a)
    const pairId = nodes.sort().toString();
    // push this edge into the bucket
    if (!res[pairId]) {
      res[pairId] = [edge];
    } else {
      res[pairId].push(edge);
    }
    return res;
  }, {});
  // start to create curved edges
  const unitOffset = 30;
  const layoutEdges = Object.keys(nodePairs).reduce((res, pairId) => {
    const edges = nodePairs[pairId];
    const curved = edges.length > 1;
    // curve line is directional, pairId is a list of sorted node ids.
    const nodeIds = pairId.split(',');
    const curveSourceId = nodeIds[0];
    const curveTargetId = nodeIds[1];
    // generate new edges with layout information
    const newEdges = edges.map((e, idx) => {
      // curve direction (1 or -1)
      const direction = idx % 2 ? 1 : -1;
      // straight line if there's only one edge between this two nodes.
      const offset = curved ? (1 + Math.floor(idx / 2)) * unitOffset : 0;
      return {
        ...e,
        source: nodePositionMap[e.sourceId],
        target: nodePositionMap[e.targetId],
        controlPoint: computeControlPoint(
          nodePositionMap[curveSourceId],
          nodePositionMap[curveTargetId],
          direction,
          offset
        )
      };
    });
    return res.concat(newEdges);
  }, []);
  return {
    nodes: graph.nodes,
    edges: layoutEdges
  };
}
function layoutGraph(graph) {
  // create a map for referencing node position by node id.
  const nodePositionMap = graph.nodes.reduce((res, node) => {
    res[node.id] = node.position;
    return res;
  }, {});
  // bucket edges between the same source/target node pairs.
  const nodePairs = graph.edges.reduce((res, edge) => {
    const nodes = [edge.sourceId, edge.targetId];
    // sort the node ids to count the edges with the same pair
    // but different direction (a -> b or b -> a)
    const pairId = nodes.sort().toString();
    // push this edge into the bucket
    if (!res[pairId]) {
      res[pairId] = [edge];
    } else {
      res[pairId].push(edge);
    }
    return res;
  }, {});
  // start to create curved edges
  const unitOffset = 30;
  const layoutEdges = Object.keys(nodePairs).reduce((res, pairId) => {
    const edges = nodePairs[pairId];
    const curved = edges.length > 1;
    // curve line is directional, pairId is a list of sorted node ids.
    const nodeIds = pairId.split(',');
    const curveSourceId = nodeIds[0];
    const curveTargetId = nodeIds[1];
    // generate new edges with layout information
    const newEdges = edges.map((e, idx) => {
      // curve direction (1 or -1)
      const direction = idx % 2 ? 1 : -1;
      // straight line if there's only one edge between this two nodes.
      const offset = curved ? (1 + Math.floor(idx / 2)) * unitOffset : 0;
      return {
        ...e,
        source: nodePositionMap[e.sourceId],
        target: nodePositionMap[e.targetId],
        controlPoint: computeControlPoint(
          nodePositionMap[curveSourceId],
          nodePositionMap[curveTargetId],
          direction,
          offset
        )
      };
    });
    return res.concat(newEdges);
  }, []);
  return {
    nodes: graph.nodes,
    edges: layoutEdges
  };
}
function layoutGraph ( graph ) { // create a map for referencing node position by node id. const nodePositionMap = graph . nodes . reduce ( ( res , node ) => { res [ node . id ] = node . position ; return res ; } , { } ) ; // bucket edges between the same source/target node pairs. const nodePairs = graph . edges . reduce ( ( res , edge ) => { const nodes = [ edge . sourceId , edge . targetId ] ; // sort the node ids to count the edges with the same pair // but different direction (a -> b or b -> a) const pairId = nodes . sort ( ) . toString ( ) ; // push this edge into the bucket if ( ! res [ pairId ] ) { res [ pairId ] = [ edge ] ; } else { res [ pairId ] . push ( edge ) ; } return res ; } , { } ) ; // start to create curved edges const unitOffset = 30 ; const layoutEdges = Object . keys ( nodePairs ) . reduce ( ( res , pairId ) => { const edges = nodePairs [ pairId ] ; const curved = edges . length > 1 ; // curve line is directional, pairId is a list of sorted node ids. const nodeIds = pairId . split ( ',' ) ; const curveSourceId = nodeIds [ 0 ] ; const curveTargetId = nodeIds [ 1 ] ; // generate new edges with layout information const newEdges = edges . map ( ( e , idx ) => { // curve direction (1 or -1) const direction = idx % 2 ? 1 : - 1 ; // straight line if there's only one edge between this two nodes. const offset = curved ? ( 1 + Math . floor ( idx / 2 ) ) * unitOffset : 0 ; return { ... e , source : nodePositionMap [ e . sourceId ] , target : nodePositionMap [ e . targetId ] , controlPoint : computeControlPoint ( nodePositionMap [ curveSourceId ] , nodePositionMap [ curveTargetId ] , direction , offset ) } ; } ) ; return res . concat ( newEdges ) ; } , [ ] ) ; return { nodes : graph . nodes , edges : layoutEdges } ; }
A helper function to generate a graph with curved edges.
@param  {Object} graph - {nodes: [], edges: []}
expected input format: {
nodes: [{id: 'a', position: [0, -100]}, {id: 'b', position: [0, 100]}, ...],
edges: [{id: '1', sourceId: 'a',, targetId: 'b',}, ...]
}
@return {Object} Return new graph with curved edges.
expected output format: {
nodes: [{id: 'a', position: [0, -100]}, {id: 'b', position: [0, 100]}, ...],
edges: [{id: '1', sourceId: 'a', source: [0, -100], targetId: 'b', target: [0, 100], controlPoint: [50, 0]}, ...]
}
A helper function to generate a graph with curved edges .