Mason
Mason

Reputation: 45

Creating bidirectional graphs in D3.js

I am building a web app that allows a user to interact with a bidirectional graph and play games to explore graph theory.

I am working off of this Graph Editor:

http://bl.ocks.org/rkirsling/5001347

Two problems:

  1. I've found no information on how to display a bidirectional arrow with SVG

  2. I want to be able to run computations on these nodes and reference their adjacent nodes and change attributes of them. Therefore, I don't just want it to appear that the edges are bidirectional, I want them represented as bi/undirectional in their code so I can manipulate them.

I want this functionality to be accessible from the web. I first started this project using Python with NetworkX and Bokeh, but ran into some display problems and found it much less intuitive to deploy as a web app.

D3.js is powerful, pretty, and well documented. But for some reason, no one has done anything with undirectional force graphs. Is this because it isn't possible?

P.S. I've thought about just adding an arrow in each direction, but this seems inelegant and may have display and referential issues.

Thanks in advance!

Upvotes: 0

Views: 880

Answers (1)

i alarmed alien
i alarmed alien

Reputation: 9520

You can display a bidirectional arrow using the marker-start and marker-end path attributes. Define one or more marker elements in the defs of your SVG containing the arrow head shape you want to use, give each an ID, and then apply them to your paths using either css or directly using a style attribute. e.g.

<svg width="200" height="200">
 <defs>
  <marker id="start-arrow" viewBox="0 -5 10 10" refX="4" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M10,-5L0,0L10,5" fill="#000"></path>
  </marker>
  <marker id="end-arrow" viewBox="0 -5 10 10" refX="6" markerWidth="5" markerHeight="5" orient="auto">
   <path d="M0,-5L10,0L0,5" fill="#000"></path> 
  </marker>
 </defs>

To use them:

 // apply directly using the style attribute
 <path style="marker-start: url('#start-arrow'); marker-end: url('#end-arrow');" d="M0,0L100,100" />

or

// in your css
.arrowed {
  marker-start: url(#arrow-start);
  marker-end: url(#arrow-end);
}

// in your SVG
<path class="arrowed" d="M0,0L100,100" />

There is also a marker-mid to apply shapes to the middle of paths.

Working demo:

.link {
  stroke: black;
  stroke-width: 3px;
  fill: none;
}

.arrowed {
  marker-start: url(#start-arrow);
  marker-end: url(#end-arrow);
}
<svg width="200" height="200">
 <defs>
  <marker id="big-arrow" markerWidth="13" markerHeight="13" refX="2" refY="6" orient="auto">
   <path d="M2,2 L2,11 L10,6 L2,2" style="fill: #000000;" />
  </marker>
  <marker id="start-arrow" viewBox="0 -5 10 10" refX="4" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M10,-5L0,0L10,5" fill="#000"></path>
  </marker>
  <marker id="end-arrow" viewBox="0 -5 10 10" refX="6" markerWidth="5" markerHeight="5" orient="auto">
   <path d="M0,-5L10,0L0,5" fill="#000"></path> 
  </marker>
  <marker id="blob" markerWidth="8" markerHeight="8" refX="5" refY="5">
    <circle cx="5" cy="5" r="3" style="stroke: none; fill: #000;" />
   </marker>
  </defs>
 <g>
  <path class="link" style="marker-start: url('#blob'); marker-end: url('#big-arrow');" d="M150,50L50,150" markerUnits="strokeWidth"></path>
  <path class="link arrowed" d="M150,150L50,50"></path>
 </g>
</svg>

As for Q2, d3 allows you to bind data to DOM elements or calculate layouts using established algorithms, but it doesn't really handle much beyond simple graph traversal and it doesn't hold internal representations of networks that can be reasoned over or used for computations. It can't be used for the same kinds of analyses as the likes of networkx. I know of at least one JS library, KeyLines, that can do network analysis, but it is proprietary software; I am sure there are others out there.

Upvotes: 1

Related Questions