github.com/jbendotnet/noms@v0.0.0-20190904222105-c43e4293ea92/cmd/noms/splore/src/layout.js (about)

     1  // Copyright 2017 Attic Labs, Inc. All rights reserved.
     2  // Licensed under the Apache License, version 2.0:
     3  // http://www.apache.org/licenses/LICENSE-2.0
     4  
     5  // @flow
     6  
     7  import React, {Element} from 'react';
     8  import {TreeNode} from './buchheim.js';
     9  import Node from './node.js';
    10  import type {NodeGraph} from './types.js';
    11  
    12  type Props = {
    13    data: NodeGraph,
    14    onNodeClick: (e: MouseEvent, s: string) => any,
    15    tree: TreeNode,
    16  };
    17  
    18  export default function Layout(props: Props): Element<any> {
    19    const {data, onNodeClick, tree} = props;
    20  
    21    const layoutChildren = [];
    22    const edges = [];
    23    const keyEdges = [];
    24    const lookup = {};
    25  
    26    const spaceX = 100;
    27    const spaceY = 20;
    28    const paddingRight = 250;
    29    const getX = d => d.y * spaceX;
    30    const getY = d => d.x * spaceY;
    31    let maxX = 0;
    32    let minY = 0;
    33    let maxY = 0;
    34  
    35    const process = (treeNode: TreeNode, fromX: number, fromY: number) => {
    36      const {children, id, isOpen, node} = treeNode;
    37      const x = getX(treeNode);
    38      const y = getY(treeNode);
    39  
    40      maxX = Math.max(x + spaceX, maxX);
    41      minY = Math.min(y, minY);
    42      maxY = Math.max(y + spaceY, maxY);
    43  
    44      const n = (
    45        <Node
    46          fromX={fromX}
    47          fromY={fromY}
    48          hasChildren={node.hasChildren}
    49          isOpen={isOpen}
    50          key={'node$' + id}
    51          onClick={e => onNodeClick(e, id)}
    52          spaceX={spaceX}
    53          text={node.name}
    54          x={x}
    55          y={y}
    56        />
    57      );
    58  
    59      layoutChildren.push(n);
    60      lookup[id] = treeNode;
    61  
    62      children.forEach(c => {
    63        process(c, x, y);
    64      });
    65  
    66      // Only show links if the tree is open.
    67      if (isOpen) {
    68        data.links[id].forEach(lid => {
    69          edges.push([id, lid]);
    70        });
    71      }
    72  
    73      // Always show key links (key -> value and label -> value) even if the tree
    74      // is closed.
    75      data.keyLinks[id].forEach(lid => {
    76        keyEdges.push([id, lid]);
    77      });
    78    };
    79  
    80    process(tree, 0, 0, true);
    81  
    82    const edgeStyle = {
    83      stroke: '#ccc',
    84      strokeWidth: '1.5px',
    85    };
    86  
    87    edges.forEach(e => {
    88      const from = lookup[e[0]];
    89      const to = lookup[e[1]];
    90      layoutChildren.push(
    91        <path
    92          key={'edge$' + e[0] + '-' + e[1]}
    93          style={edgeStyle}
    94          d={`M${getX(from)},${getY(from)}L${getX(to)},${getY(to)}`}
    95        />,
    96      );
    97    });
    98  
    99    const keyEdgeStyle = {
   100      ...edgeStyle,
   101      stroke: 'steelblue',
   102    };
   103  
   104    keyEdges.forEach(e => {
   105      const from = lookup[e[0]];
   106      const to = lookup[e[1]];
   107      layoutChildren.push(
   108        <path
   109          key={'keyEdge$' + e[0] + '-' + e[1]}
   110          style={keyEdgeStyle}
   111          d={`M${getX(from)},${getY(from)}L${getX(to)},${getY(to)}`}
   112        />,
   113      );
   114    });
   115  
   116    const sortOrder = elm => (elm.type === 'path' ? 0 : 1);
   117    layoutChildren.sort((a, b) => sortOrder(a) - sortOrder(b));
   118  
   119    let translateY = spaceY;
   120    if (minY < 0) {
   121      translateY -= minY;
   122      maxY -= minY;
   123    }
   124  
   125    return (
   126      <svg width={maxX + spaceX + paddingRight} height={maxY + spaceY}>
   127        <g transform={`translate(${spaceX}, ${translateY})`}>
   128          {layoutChildren}
   129        </g>
   130      </svg>
   131    );
   132  }