block by nitaku 6354551

Flowlines

Full Screen

An experiment that shows a possible way to visually encode link directionality in node-link diagrams as animation: Some kind of “flow” moves according to the direction.

More or less related to a Mike Bostock example.

For a comparison of different methods for representing link directionality (including animated dashed lines), see Holten et al. 2010

index.js

(function() {

  window.main = function() {
    var ex1, ex2, height, svg, width;
    width = 960;
    height = 500;
    svg = d3.select('body').append('svg').attr('width', width).attr('height', height);
    /* first example
    */
    ex1 = svg.append('g').attr('transform', 'translate(50 50)');
    /* draw links
    */
    ex1.append('path').attr('class', 'flowline').attr('d', 'M100 100 L300 100');
    ex1.append('path').attr('class', 'flowline').attr('d', 'M200 300 L300 100');
    ex1.append('path').attr('class', 'flowline').attr('d', 'M200 300 L300 250');
    ex1.append('path').attr('class', 'flowline').attr('d', 'M300 250 L100 100');
    /* draw nodes
    */
    ex1.append('circle').attr('class', 'node').attr('cx', 100).attr('cy', 100).attr('r', 20);
    ex1.append('circle').attr('class', 'node').attr('cx', 300).attr('cy', 100).attr('r', 20);
    ex1.append('circle').attr('class', 'node').attr('cx', 200).attr('cy', 300).attr('r', 20);
    ex1.append('circle').attr('class', 'node').attr('cx', 300).attr('cy', 250).attr('r', 20);
    /* second example
    */
    ex2 = svg.append('g').attr('transform', 'translate(450 50)');
    /* draw links
    */
    ex2.append('path').attr('class', 'flowline').attr('d', 'M100 100 S200 0 300 100');
    ex2.append('path').attr('class', 'flowline').attr('d', 'M200 300 S200 200 300 100');
    ex2.append('path').attr('class', 'flowline').attr('d', 'M200 300 S300 350 300 250');
    ex2.append('path').attr('class', 'flowline').attr('d', 'M300 250 L100 100');
    /* draw nodes
    */
    ex2.append('circle').attr('class', 'node').attr('cx', 100).attr('cy', 100).attr('r', 20);
    ex2.append('circle').attr('class', 'node').attr('cx', 300).attr('cy', 100).attr('r', 20);
    ex2.append('circle').attr('class', 'node').attr('cx', 200).attr('cy', 300).attr('r', 20);
    return ex2.append('circle').attr('class', 'node').attr('cx', 300).attr('cy', 250).attr('r', 20);
  };

}).call(this);

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Flowlines</title>
        <link type="text/css" href="index.css" rel="stylesheet"/>
        <script src="//d3js.org/d3.v3.min.js"></script>
        <script src="index.js"></script>
    </head>
    <body onload="main()"></body>
</html>

index.coffee

window.main = () ->
    width = 960
    height = 500
    
    svg = d3.select('body').append('svg')
        .attr('width', width)
        .attr('height', height)
        
    ### first example ###
    ex1 = svg.append('g')
        .attr('transform', 'translate(50 50)')
        
    ### draw links ###
    ex1.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M100 100 L300 100')
        
    ex1.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M200 300 L300 100')
        
    ex1.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M200 300 L300 250')
        
    ex1.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M300 250 L100 100')
        
    ### draw nodes ###
    ex1.append('circle')
        .attr('class', 'node')
        .attr('cx', 100)
        .attr('cy', 100)
        .attr('r', 20)
        
    ex1.append('circle')
        .attr('class', 'node')
        .attr('cx', 300)
        .attr('cy', 100)
        .attr('r', 20)
        
    ex1.append('circle')
        .attr('class', 'node')
        .attr('cx', 200)
        .attr('cy', 300)
        .attr('r', 20)
        
    ex1.append('circle')
        .attr('class', 'node')
        .attr('cx', 300)
        .attr('cy', 250)
        .attr('r', 20)
        
    ### second example ###
    ex2 = svg.append('g')
        .attr('transform', 'translate(450 50)')
    
    ### draw links ###
    ex2.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M100 100 S200 0 300 100')
        
    ex2.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M200 300 S200 200 300 100')
        
    ex2.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M200 300 S300 350 300 250')
        
    ex2.append('path')
        .attr('class', 'flowline')
        .attr('d', 'M300 250 L100 100')
        
    ### draw nodes ###
    ex2.append('circle')
        .attr('class', 'node')
        .attr('cx', 100)
        .attr('cy', 100)
        .attr('r', 20)
        
    ex2.append('circle')
        .attr('class', 'node')
        .attr('cx', 300)
        .attr('cy', 100)
        .attr('r', 20)
        
    ex2.append('circle')
        .attr('class', 'node')
        .attr('cx', 200)
        .attr('cy', 300)
        .attr('r', 20)
        
    ex2.append('circle')
        .attr('class', 'node')
        .attr('cx', 300)
        .attr('cy', 250)
        .attr('r', 20)
        

index.css

.node {
  fill: #dddddd;
  stroke: gray;
  stroke-width: 4;
}

.flowline {
  fill: none;
  stroke: black;
  opacity: 0.5;
  stroke-width: 4;
  stroke-dasharray: 10, 4;
  animation: flow 1s linear infinite;
  -webkit-animation: flow 1s linear infinite;
}

@keyframes flow {
  from {
    stroke-dashoffset: 14;
  }

  to {
    stroke-dashoffset: 0;
  }
}

@-webkit-keyframes flow {
  from {
    stroke-dashoffset: 14;
  }

  to {
    stroke-dashoffset: 0;
  }
}

index.sass

.node
    fill: #DDD
    stroke: gray
    stroke-width: 4

.flowline
    fill: none
    stroke: black
    opacity: 0.5
    stroke-width: 4
    stroke-dasharray: 10,4
    animation: flow 1s linear infinite
    -webkit-animation: flow 1s linear infinite
    
@keyframes flow
    from
        stroke-dashoffset: 14
    to
        stroke-dashoffset: 0
        
@-webkit-keyframes flow
    from
        stroke-dashoffset: 14
    to
        stroke-dashoffset: 0