block by emeeks aaa995cde6621745e906

d3_glyphEdge

Full Screen

Various edge types available in d3_glyphEdges.

index.html


<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="utf-8" />
<title>Glyph Edges</title>
<style>
  
 body {
   overflow: hidden;
  }
.node rect {
  cursor: move;
  fill-opacity: .9;
  shape-rendering: crispEdges;
}

.node text {
  pointer-events: none;
  text-shadow: 0 1px 0 #fff;
}

.link {
  fill: none;
  stroke: #000;
  stroke-opacity: .05;
}

.link:hover {
  stroke-opacity: .25;
}

svg {
  position: absolute;
}

canvas {
  position: absolute;
}


</style>
</head>
<body>
<svg width="1500" height="1500" ></svg>

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js" charset="utf-8" type="text/javascript"></script>
<script src="d3-glyphEdge.js" charset="utf-8" type="text/javascript"></script>

    <script type="text/javascript">

set3 = ["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"];

d3.json("network.json", makeViz)

function makeViz(data) {

  overallFrequency = 0.5;

data.links.forEach(function (d) {
  //These edge properties are necessary for particles
  d.particles = [];
  d.frequency = overallFrequency;
})

  force = d3.layout.force().links(data.links).nodes(data.nodes)
  .charge(function (d) {return (d.weight + 1) * -400})
  .linkDistance(5)
  .size([400,400])
  .gravity(2)
    .on("tick", tick)

  edgeTypes = ["ribbon", "arrowhead", "halfarrow", "taffy", "comet", "particle", "offset", "nail"]

  edgeDemo = d3.select("svg").selectAll("edgeDemo")
  .data(edgeTypes)
  .enter()
  .append("g")
  .attr("class", function (d) {return "edgeDemo " + d})
  .attr("transform", function (d, i) {return "translate(" + (i%3 * 350) + "," + (250 + (parseInt(i/3) * 350)) + ")"});

  edgeDemo.selectAll("g.edge").data(data.links)
    .enter()
    .append("g")
    .attr("class", "edge")
    .append("path")
    .attr("class", "edge")
    .style("fill", "darkgreen")
    .style("stroke", "black")
    .style("stroke-width", 1)
    .style("opacity", 0.75)

  edgeDemo.selectAll("g.node").data(data.nodes)
    .enter()
    .append("g")
    .attr("class", "node")
    .call(force.drag);

  edgeDemo.append("text")
    .attr("x", 100)
    .attr("y", 190)
    .style("text-anchor", "middle")
    .style("stroke", "white")
    .style("stroke-width", "2px")
    .style("stroke-opacity", .75)
    .style("font-size", "24px")
    .text(function (d) {return d})

  edgeDemo.append("text")
    .attr("x", 100)
    .attr("y", 190)
    .style("text-anchor", "middle")
    .style("font-size", "24px")
    .text(function (d) {return d})

    d3.selectAll("g.node")
    .append("circle")
    .attr("class", "node")
    .style("fill", function (d) {return set3[d.module]})
    .style("fill-opacity", 1)
    .style("stroke", "darkgray")

    force.start();

  function tick(e) {
    d3.selectAll("circle.node")
    .attr("r", function (d) {return (d.weight + 1)});

    d3.selectAll("g.node")
      .attr("transform", function (d) {return "translate(" + d.x + "," + d.y + ")"});

    d3.select("g.ribbon").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.ribbon(d, 2)})
      .style("fill", "darkred")


    d3.select("g.halfarrow").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.halfArrow(d, d.target.weight + 2, 1, 2)})
      .style("fill", "#9B817A")

    d3.select("g.arrowhead").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.arrowhead(d, d.target.weight + 2, 1, 2)})
      .style("fill", "#9B817A")

    d3.select("g.taffy").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.taffy(d, d.source.weight, d.target.weight, (d.source.weight + d.target.weight) / 8)})
      .style("fill", "pink")

    d3.select("g.comet").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.comet(d, d.target.weight)})
      .style("fill", "gold")

    d3.select("g.nail").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.nail(d, d.source.weight)})
      .style("fill", "silver")

    d3.select("g.offset").selectAll("path.edge")
      .attr("d", function (d) {return d3_glyphEdge.d.arrowhead(d3_glyphEdge.project.offset(d, d.source.weight, d.target.weight), d.target.weight, 0.5, 1)})
      .style("opacity", 0.25)

    d3.select("g.particle").selectAll("g.edge")
      .each(function (d, i) {

          d3_glyphEdge.mutate.particle(d, d3.select(this).select("path").node(), 3, 2);
          d3.select(this).selectAll("circle")
            .data(d.particles)
            .enter()
            .append("circle")
            .style("fill-opacity", .25)
            .attr("r", 1);

          d3.select(this).selectAll("circle")
            .data(d.particles)
            .exit()
            .remove();

          d3.select(this).selectAll("circle")
            .attr("cx", function (p) {return p.x})
            .attr("cy", function (p) {return p.y});
      })
      .select("path")
      .attr("d", d3_glyphEdge.d.lineArc)
      .style("fill", "none")
      .style("stroke-opacity", 0.1)
      .style("stroke-width", 3)
  }


}

    </script>
</body>
</html>

d3-glyphEdge.js

(function (global, factory) {
        typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
        typeof define === 'function' && define.amd ? define('d3-glyphEdge', ['exports'], factory) :
        factory((global.d3_glyphEdge = {}));
}(this, function (exports) { 'use strict';

        function halfArrow(d, nodeTargetSize, bodySize, headSize) {
            var diffX = d.target.y - d.source.y;
            var diffY = d.target.x - d.source.x;

            var headDistance = headSize * 3;

            var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
            var angle1 = angle0 - ( Math.PI / 2 );
            var angle2 = angle0 + ( Math.PI / 2 );

            var x1 = d.source.x + (headSize * Math.cos(angle1));
            var y1 = d.source.y - (headSize * Math.sin(angle1));
            var x2 = d.source.x + (headSize * Math.cos(angle2));
            var y2 = d.source.y - (headSize * Math.sin(angle2));
            
            var x3 = d.target.x - (headSize * Math.cos(angle1));
            var y3 = d.target.y + (headSize * Math.sin(angle1));

            var mx1 = d.source.x + (bodySize * Math.cos(angle1));
            var my1 = d.source.y - (bodySize * Math.sin(angle1));
            var mx2 = d.source.x + (bodySize * Math.cos(angle2));
            var my2 = d.source.y - (bodySize * Math.sin(angle2));

            var mx3 = d.target.x + (bodySize * Math.cos(angle1));
            var my3 = d.target.y - (bodySize * Math.sin(angle1));

            var dY = d.source.y - d.target.y;
            var dX = d.source.x - d.target.x;

            var midDiffY1 = my1 - my3;
            var midDiffX1 = mx1 - mx3;

            var diffY1 = y1 - y3;
            var diffX1 = x1 - x3;

            var pythag = Math.sqrt((midDiffX1 * midDiffX1) + (midDiffY1 * midDiffY1));
            var pythag2 = Math.sqrt((dX * dX) + (dY * dY));

            var adjX1 = mx2 - ((midDiffX1 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var adjY1 = my2 - ((midDiffY1 * (pythag - headDistance - nodeTargetSize)) / pythag);

            var headX1 = x2 - ((diffX1 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var headY1 = y2 - ((diffY1 * (pythag - headDistance - nodeTargetSize)) / pythag);

            var tipX = d.source.x - ((dX * (pythag2 - nodeTargetSize)) / pythag2);
            var tipY = d.source.y - ((dY * (pythag2 - nodeTargetSize)) / pythag2);

            return "M" + d.source.x + "," + d.source.y + "L" + mx2 + "," + my2 + "L" + adjX1 + "," + adjY1 + "L" + headX1 + "," + headY1 + "L" + tipX + "," + tipY + "L" + d.source.x + "," + d.source.y + "z";
        };

        function lineArc(d) {
          var dx = d.target.x - d.source.x,
              dy = d.target.y - d.source.y,
              dr = Math.sqrt(dx * dx + dy * dy);
          return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
        };

        function ribbon(d, bodySize) {
                var diffX = d.target.y - d.source.y;
                var diffY = d.target.x - d.source.x;

                var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
                var angle1 = angle0 - ( Math.PI / 2 );
                var angle2 = angle0 + ( Math.PI / 2 );

                var mx1 = d.source.x + (bodySize * Math.cos(angle1));
                var my1 = d.source.y - (bodySize * Math.sin(angle1));
                var mx2 = d.source.x + (bodySize * Math.cos(angle2));
                var my2 = d.source.y - (bodySize * Math.sin(angle2));

                var mx3 = d.target.x - (bodySize * Math.cos(angle1));
                var my3 = d.target.y + (bodySize * Math.sin(angle1));
                var mx4 = d.target.x - (bodySize * Math.cos(angle2));
                var my4 = d.target.y + (bodySize * Math.sin(angle2));

                return "M" + mx1 + "," + my1 + "L" + mx2 + "," + my2 + "L" + mx3 + "," + my3 + "L" + mx4 + "," + my4 + "z";
        }

        function taffy(d, nodeSourceSize, nodeTargetSize, midpointSize) {
            var diffX = d.target.y - d.source.y;
            var diffY = d.target.x - d.source.x;

            var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
            var angle1 = angle0 - ( Math.PI / 2 );
            var angle2 = angle0 + ( Math.PI / 2 );

            var x1 = d.source.x + (nodeSourceSize * Math.cos(angle1));
            var y1 = d.source.y - (nodeSourceSize * Math.sin(angle1));
            var x2 = d.source.x + (nodeSourceSize * Math.cos(angle2));
            var y2 = d.source.y - (nodeSourceSize * Math.sin(angle2));

            var x3 = d.target.x + (nodeTargetSize * Math.cos(angle2));
            var y3 = d.target.y - (nodeTargetSize * Math.sin(angle2));
            var x4 = d.target.x + (nodeTargetSize * Math.cos(angle1));
            var y4 = d.target.y - (nodeTargetSize * Math.sin(angle1));

            var mx1 = d.source.x + (midpointSize * Math.cos(angle1));
            var my1 = d.source.y - (midpointSize * Math.sin(angle1));
            var mx2 = d.source.x + (midpointSize * Math.cos(angle2));
            var my2 = d.source.y - (midpointSize * Math.sin(angle2));

            var mx3 = d.target.x + (midpointSize * Math.cos(angle1));
            var my3 = d.target.y - (midpointSize * Math.sin(angle1));
            var mx4 = d.target.x + (midpointSize * Math.cos(angle2));
            var my4 = d.target.y - (midpointSize * Math.sin(angle2));

            var midY2 = (my1 + my3) / 2;
            var midX2 = (mx1 + mx3) / 2;
            var midY1 = (my2 + my4) / 2;
            var midX1 = (mx2 + mx4) / 2;

            return "M" + x1 + "," + y1 + "L" + x2 + "," + y2 + " L " + midX1 + "," + midY1 + " L " + x3 + "," + y3 + " L " + x4 + "," + y4 + " L " + midX2 + "," + midY2 + "z";
        };

        function nail(d, nodeSize) {
            var diffX = d.target.y - d.source.y;
            var diffY = d.target.x - d.source.x;

            var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
            var angle1 = angle0 - ( Math.PI / 2 );
            var angle2 = angle0 + ( Math.PI / 2 );

            var x1 = d.source.x + (nodeSize * Math.cos(angle1));
            var y1 = d.source.y - (nodeSize * Math.sin(angle1));
            var x2 = d.source.x + (nodeSize * Math.cos(angle2));
            var y2 = d.source.y - (nodeSize * Math.sin(angle2));

            return "M" + x1 + "," + y1 + "L" + x2 + "," + y2 + " L " + d.target.x + "," + d.target.y + "z";
        };

        function comet(d, nodeSize) {
            var diffX = d.target.y - d.source.y;
            var diffY = d.target.x - d.source.x;

            var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
            var angle1 = angle0 - ( Math.PI / 2 );
            var angle2 = angle0 + ( Math.PI / 2 );

            var x1 = d.target.x + (nodeSize * Math.cos(angle1));
            var y1 = d.target.y - (nodeSize * Math.sin(angle1));
            var x2 = d.target.x + (nodeSize * Math.cos(angle2));
            var y2 = d.target.y - (nodeSize * Math.sin(angle2));

            return "M" + x1 + "," + y1 + "L" + x2 + "," + y2 + " L " + d.source.x + "," + d.source.y + "z";
        };

        function arrowhead(d, nodeTargetSize, bodySize, headSize) {
            var diffX = d.target.y - d.source.y;
            var diffY = d.target.x - d.source.x;

            var headDistance = headSize * 3;

            var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
            var angle1 = angle0 - ( Math.PI / 2 );
            var angle2 = angle0 + ( Math.PI / 2 );

            var x1 = d.source.x + (headSize * Math.cos(angle1));
            var y1 = d.source.y - (headSize * Math.sin(angle1));
            var x2 = d.source.x + (headSize * Math.cos(angle2));
            var y2 = d.source.y - (headSize * Math.sin(angle2));

            var x3 = d.target.x - (headSize * Math.cos(angle1));
            var y3 = d.target.y + (headSize * Math.sin(angle1));
            var x4 = d.target.x - (headSize * Math.cos(angle2));
            var y4 = d.target.y + (headSize * Math.sin(angle2));

            var mx1 = d.source.x + (bodySize * Math.cos(angle1));
            var my1 = d.source.y - (bodySize * Math.sin(angle1));
            var mx2 = d.source.x + (bodySize * Math.cos(angle2));
            var my2 = d.source.y - (bodySize * Math.sin(angle2));

            var mx3 = d.target.x + (bodySize * Math.cos(angle1));
            var my3 = d.target.y - (bodySize * Math.sin(angle1));
            var mx4 = d.target.x + (bodySize * Math.cos(angle2));
            var my4 = d.target.y - (bodySize * Math.sin(angle2));

            var dY = d.source.y - d.target.y;
            var dX = d.source.x - d.target.x;

            var midDiffY1 = my1 - my3;
            var midDiffX1 = mx1 - mx3;
            var midDiffY2 = my2 - my4;
            var midDiffX2 = mx2 - mx4;

            var diffY1 = y1 - y3;
            var diffX1 = x1 - x3;
            var diffY2 = y2 - y4;
            var diffX2 = x2 - x4;

            var pythag = Math.sqrt((midDiffX1 * midDiffX1) + (midDiffY1 * midDiffY1));
            var pythag2 = Math.sqrt((dX * dX) + (dY * dY));

            var adjX1 = mx2 - ((midDiffX1 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var adjY1 = my2 - ((midDiffY1 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var adjX2 = mx1 - ((midDiffX2 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var adjY2 = my1 - ((midDiffY2 * (pythag - headDistance - nodeTargetSize)) / pythag);

            var headX2 = x1 - ((diffX2 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var headY2 = y1 - ((diffY2 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var headX1 = x2 - ((diffX1 * (pythag - headDistance - nodeTargetSize)) / pythag);
            var headY1 = y2 - ((diffY1 * (pythag - headDistance - nodeTargetSize)) / pythag);

            var tipX = d.source.x - ((dX * (pythag2 - nodeTargetSize)) / pythag2);
            var tipY = d.source.y - ((dY * (pythag2 - nodeTargetSize)) / pythag2);

            return "M" + mx2 + "," + my2 + "L" + adjX1 + "," + adjY1 + "L" + headX1 + "," + headY1 + "L" + tipX + "," + tipY + "L" + headX2 + "," + headY2 + "L" + adjX2 + "," + adjY2 + "L" + mx1 + "," + my1 + "z";
        };

        function parallel(d, sourceSize, targetSize, edgeNumber) {

          var diffX = d.target.y - d.source.y;
          var diffY = d.target.x - d.source.x;

          var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
          var angle1 = angle0 + ( (Math.PI * 0.75) + (edgeNumber * 0.25) );
          var angle2 = angle0 + ( (Math.PI * 0.25) - (edgeNumber * 0.25) );

          var x1 = d.source.x + (sourceSize * Math.cos(angle1));
          var y1 = d.source.y - (sourceSize * Math.sin(angle1));
          var x2 = d.target.x + (targetSize * Math.cos(angle2));
          var y2 = d.target.y - (targetSize * Math.sin(angle2));

          return {source: {x: x1, y: y1}, target: {x: x2, y: y2}};

        }

        function offset(d, nodeSize) {
          var diffX = d.target.y - d.source.y;
          var diffY = d.target.x - d.source.x;

          var angle0 = ( Math.atan2( diffY, diffX ) + ( Math.PI / 2 ) );
          var angle1 = angle0 + ( Math.PI * 0.75 );
          var angle2 = angle0 + ( Math.PI * 0.25 );

          var x1 = d.source.x + (nodeSize * Math.cos(angle1));
          var y1 = d.source.y - (nodeSize * Math.sin(angle1));
          var x2 = d.target.x + (nodeSize * Math.cos(angle2));
          var y2 = d.target.y - (nodeSize * Math.sin(angle2));

          return {source: {x: x1, y: y1}, target: {x: x2, y: y2}};

        }

        function particle(d, path, pathWidth, speed) {
            pathWidth = pathWidth / 2;

            d.particles = d.particles.filter(function (d) {return d.current < path.getTotalLength()});

            if (d.frequency < 1) {
                if (Math.random() < d.frequency) {
                    pushParticle();
                }
            } else {
                for (var x = 0; x < d.frequency; x++) {
                    pushParticle();
                }
            }

            function pushParticle() {
                d.particles.push({current: 0, xOffset: pathWidth - (pathWidth * Math.random() * 2), yOffset: pathWidth - (pathWidth * Math.random() * 2)});
            }

            d.particles.forEach(function (particle) {
                particle.current = particle.current + speed;
                var currentPosition = path.getPointAtLength(particle.current);
                particle.x = currentPosition.x + particle.xOffset;
                particle.y = currentPosition.y + particle.yOffset;
            });
        };

        var d = {
            arrowhead: arrowhead,
            comet: comet,
            nail: nail,
            taffy: taffy,
            ribbon: ribbon,
            lineArc: lineArc,
            halfArrow: halfArrow
        };

        var project = {
            offset: offset,
            parallel: parallel
        }

        var mutate = {
            particle: particle
        }

        var version = "1.0.0";

        exports.version = version;
        exports.d = d;
        exports.project = project;
        exports.mutate = mutate;

}));

network.json

{
	"nodes": [{"id":0,"module":0},{"id":1,"module":1},{"id":2,"module":0},{"id":3,"module":0},{"id":4,"module":2},{"id":5,"module":3},{"id":6,"module":1},{"id":7,"module":0},{"id":8,"module":0},{"id":9,"module":0},{"id":10,"module":3},{"id":11,"module":0},{"id":12,"module":1},{"id":13,"module":1},{"id":14,"module":4},{"id":15,"module":5},{"id":16,"module":2},{"id":17,"module":1},{"id":18,"module":3},{"id":19,"module":1},{"id":20,"module":2},{"id":21,"module":0},{"id":22,"module":2},{"id":23,"module":6},{"id":24,"module":3},{"id":25,"module":2},{"id":26,"module":1},{"id":27,"module":2},{"id":28,"module":1},{"id":29,"module":7},{"id":30,"module":8},{"id":31,"module":0},{"id":32,"module":9},{"id":33,"module":9},{"id":34,"module":1},{"id":35,"module":2},{"id":36,"module":10},{"id":37,"module":1},{"id":38,"module":2},{"id":39,"module":11},{"id":40,"module":1},{"id":41,"module":9},{"id":42,"module":12},{"id":43,"module":2},{"id":44,"module":3},{"id":45,"module":0}],
	"links": [{
		"source": 1,
		"target": 7
	}, {
		"source": 1,
		"target": 12
	}, {
		"source": 1,
		"target": 13
	}, {
		"source": 1,
		"target": 26
	}, {
		"source": 2,
		"target": 0
	}, {
		"source": 2,
		"target": 8
	}, {
		"source": 2,
		"target": 11
	}, {
		"source": 2,
		"target": 45
	}, {
		"source": 4,
		"target": 38
	}, {
		"source": 5,
		"target": 18
	}, {
		"source": 5,
		"target": 44
	}, {
		"source": 6,
		"target": 19
	}, {
		"source": 6,
		"target": 28
	}, {
		"source": 6,
		"target": 33
	}, {
		"source": 7,
		"target": 0
	}, {
		"source": 7,
		"target": 3
	}, {
		"source": 7,
		"target": 11
	}, {
		"source": 7,
		"target": 21
	}, {
		"source": 7,
		"target": 31
	}, {
		"source": 9,
		"target": 7
	}, {
		"source": 10,
		"target": 44
	}, {
		"source": 13,
		"target": 1
	}, {
		"source": 16,
		"target": 22
	}, {
		"source": 17,
		"target": 19
	}, {
		"source": 19,
		"target": 17
	}, {
		"source": 19,
		"target": 26
	}, {
		"source": 20,
		"target": 16
	}, {
		"source": 20,
		"target": 44
	}, {
		"source": 21,
		"target": 37
	}, {
		"source": 22,
		"target": 16
	}, {
		"source": 22,
		"target": 28
	}, {
		"source": 22,
		"target": 38
	}, {
		"source": 24,
		"target": 18
	}, {
		"source": 25,
		"target": 16
	}, {
		"source": 25,
		"target": 27
	}, {
		"source": 26,
		"target": 1
	}, {
		"source": 26,
		"target": 19
	}, {
		"source": 26,
		"target": 28
	}, {
		"source": 27,
		"target": 16
	}, {
		"source": 28,
		"target": 6
	}, {
		"source": 28,
		"target": 19
	}, {
		"source": 28,
		"target": 22
	}, {
		"source": 33,
		"target": 32
	}, {
		"source": 34,
		"target": 26
	}, {
		"source": 35,
		"target": 27
	}, {
		"source": 37,
		"target": 6
	}, {
		"source": 37,
		"target": 13
	}, {
		"source": 37,
		"target": 40
	}, {
		"source": 38,
		"target": 22
	}, {
		"source": 38,
		"target": 25
	}, {
		"source": 38,
		"target": 43
	}, {
		"source": 41,
		"target": 33
	}, {
		"source": 43,
		"target": 25
	}, {
		"source": 43,
		"target": 38
	}, {
		"source": 44,
		"target": 16
	}, {
		"source": 44,
		"target": 18
	}, {
		"source": 44,
		"target": 24
	}, {
		"source": 44,
		"target": 43
	}, {
		"source": 45,
		"target": 2
	}]
}