1

I'm attempting to create a crude database diagram generator using D3, but I can't figure out how to get connectors between fields. I can get straight lines going from two points, but I wanted it to be rounded and like a path I guess.

I've tried to put together an example of just that specific issue, linking two text fields:

https://codesandbox.io/s/gifted-bardeen-5hbw2?fontsize=14&hidenavigation=1&theme=dark

Here's an example from dbdiagram.io of what I'm referring to:

Example from another site

I've been reading up on the d attribute and the various commands, but nothing seems even close. I suspect the forceSimulation method, especially the forceCenter function might be messing up the relative positioning when I use the lower-cased commands. But not 100% on that.

Ewan Valentine
  • 3,741
  • 7
  • 43
  • 68
  • [This](https://stackoverflow.com/q/60293272/7106086) might be useful (*note: the snippets use a tree diagram that is rotated by swapping x coordinates for y coordinates and vice versa, which may be slightly confusing at first*) – Andrew Reid Mar 16 '21 at 17:08

1 Answers1

1

You can compute a connector path between 2 points by connectorPath routine:

const source = {x: 200, y: 120};
const target = {x: 50, y: 20};
const MAX_RADIUS = 15;

const connectorPath = (from, to) => {
    if (from.y === to.y || from.x === to.x) 
    return `M ${from.x},${from.y} L ${to.x},${to.y}`;
    
    const middle = (from.x + to.x) / 2;
  const xFlag = from.x < to.x ? 1 : -1;
  const yFlag = from.y < to.y ? 1 : -1;
  const dX = Math.abs(from.x - to.x);
  const dY = Math.abs(from.y - to.y);
  const radius = Math.min(dX / 2, dY / 2, MAX_RADIUS);
  return `M ${from.x},${from.y} H ${middle - radius * xFlag} Q ${middle},${from.y} ${middle},${from.y + radius * yFlag} V ${to.y - radius * yFlag} Q ${middle},${to.y} ${middle + radius * xFlag},${to.y} H ${to.x}`;
};

d3.select('#source').attr('cx', source.x).attr('cy', source.y);
d3.select('#target').attr('cx', target.x).attr('cy', target.y);
d3.select('#connector').attr('d', connectorPath(source, target));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="300" height="200">
  <path id="connector" stroke="blue" fill="none" />
  <circle id="source" fill="red" r="5"/>
  <circle id="target" fill="green" r="5"/>
</svg>
Michael Rovinsky
  • 6,807
  • 7
  • 15
  • 30