i want to put an arrow on one end of the link. i have managed links but unable to draw arrows. here is my code that works properly but the problem i have mentioned above just help me out how can i draw arrows. thanks.
keep in mind that i want arrow on targeted side.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="D3js_demo.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<title>Weighted Citation Graph</title>
<style>
path.link {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}
circle {
fill: #ccc;
stroke: #333;
stroke-width: 1.5px;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
text.shadow {
stroke: #fff;
stroke-width: 3px;
stroke-opacity: .8;
}
body {
background-color: white;
margin: 0px;
}
.graphContainer {
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
$(function () {
var color = d3.scale.category20();
var data = {
"nodes": [
{ "id": 0, "name": "paper1", "citation": 5, "group": 1 },
{ "id": 1, "name": "paper2", "citation": 8, "group": 2 },
{ "id": 2, "name": "paper3", "citation": 12, "group": 3 },
{ "id": 3, "name": "paper4", "citation": 25, "group": 4 },
{ "id": 4, "name": "paper5", "citation": 15, "group": 5 },
{ "id": 5, "name": "paper6", "citation": 5, "group": 1 },
{ "id": 6, "name": "paper7", "citation": 8, "group": 2 },
{ "id": 7, "name": "paper8", "citation": 12, "group": 3 },
{ "id": 8, "name": "paper9", "citation": 25, "group": 4 },
{ "id": 9, "name": "paper10", "citation": 15, "group": 5 }
],
"links": [
{ "source": 0, "target": 1, "name": "A-B-1", "value": 0 , "grouo": 1},
{ "source": 0, "target": 1, "name": "A-B-2", "value": 24, "grouo": 2 },
{ "source": 0, "target": 2, "name": "A-C-1", "value": 100, "grouo": 1 },
{ "source": 0, "target": 2, "name": "A-C-3", "value": 44, "grouo": 2 },
{ "source": 2, "target": 3, "name": "A-D-1", "value": 169, "grouo": 1 },
{ "source": 2, "target": 3, "name": "A-D-2", "value": 80, "grouo": 2 },
{ "source": 2, "target": 4, "name": "A-E-1", "value": 16, "grouo": 1 },
{ "source": 2, "target": 4, "name": "A-E-5", "value": 200, "grouo": 2 },
{ "source": 4, "target": 5, "name": "A-B-1", "value": 8, "grouo": 1 },
{ "source": 4, "target": 5, "name": "A-B-2", "value": 24, "grouo": 2 },
{ "source": 5, "target": 6, "name": "A-C-1", "value": 12, "grouo": 1 },
{ "source": 5, "target": 6, "name": "A-C-3", "value": 44, "grouo": 2 },
{ "source": 5, "target": 7, "name": "A-D-1", "value": 125, "grouo": 1 },
{ "source": 5, "target": 7, "name": "A-D-2", "value": 225, "grouo": 2 },
{ "source": 7, "target": 8, "name": "A-E-1", "value": 36, "grouo": 1 },
{ "source": 7, "target": 8, "name": "A-E-5", "value": 81, "grouo": 2 },
{ "source": 8, "target": 3, "name": "A-C-1", "value": 9, "grouo": 1 },
{ "source": 8, "target": 3, "name": "A-C-3", "value": 16, "grouo": 2 },
{ "source": 8, "target": 9, "name": "A-D-1", "value": 50, "grouo": 1 },
{ "source": 8, "target": 9, "name": "A-D-2", "value": 100, "grouo": 2 }
]
};
// used to store the number of links between two nodes.
// mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex;
var mLinkNum = {};
// sort links first
sortLinks();
// set up linkIndex and linkNumer, because it may possible multiple links share the same source and target node
setLinkIndexAndNum();
var w = 960,
h = 500;
var force = d3.layout.force()
.nodes(d3.values(data.nodes))
.links(data.links)
.size([w, h])
.linkDistance(200)
.charge(-1000)
.on("tick", tick)
.start();
var svg = d3.select(".graphContainer").append("svg:svg")
.attr("width", w)
.attr("height", h);
var path = svg.append("svg:g")
.selectAll("line")
.data(force.links())
.enter().append("svg:path")
.attr("class", "link")
.style("stroke-width", function (d) { return Math.sqrt(d.value)})
.style("stroke", function (d) { return color(d.grouo)});
var circle = svg.append("svg:g")
.selectAll("circle")
.data(force.nodes())
.enter().append("svg:circle")
.attr("r", function (d) { return (d.citation); })
.style("fill", function (d) { return color(d.group); })
.call(force.drag);
var text = svg.append("svg:g")
.selectAll("g")
.data(force.nodes())
.enter().append("svg:g");
// A copy of the text with a thick white stroke for legibility.
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.attr("class", "shadow")
.text(function (d) { return d.name; });
text.append("svg:text")
.attr("x", 8)
.attr("y", ".31em")
.text(function (d) { return d.name; });
// Use elliptical arc path segments to doubly-encode directionality.
function tick() {
path.attr("d", function (d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
// get the total link numbers between source and target node
var lTotalLinkNum = mLinkNum[d.source.id + "," + d.target.id] || mLinkNum[d.target.id + "," + d.source.id];
if (lTotalLinkNum > 1) {
// if there are multiple links between these two nodes, we need generate different dr for each path
dr = dr / (1 + (1 / lTotalLinkNum) * (d.linkindex - 1));
}
// generate svg path
return "M" + d.source.x + "," + d.source.y +
"A" + dr + "," + dr + " 0 0 1," + d.target.x + "," + d.target.y +
"A" + dr + "," + dr + " 0 0 0," + d.source.x + "," + d.source.y;
});
// Add tooltip to the connection path
path.append("svg:title")
.text(function (d, i) { return d.name; });
circle.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
text.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
// sort the links by source, then target
function sortLinks() {
data.links.sort(function (a, b) {
if (a.source > b.source) {
return 1;
}
else if (a.source < b.source) {
return -1;
}
else {
if (a.target > b.target) {
return 1;
}
if (a.target < b.target) {
return -1;
}
else {
return 0;
}
}
});
}
//any links with duplicate source and target get an incremented 'linknum'
function setLinkIndexAndNum() {
for (var i = 0; i < data.links.length; i++) {
if (i != 0 &&
data.links[i].source == data.links[i - 1].source &&
data.links[i].target == data.links[i - 1].target) {
data.links[i].linkindex = data.links[i - 1].linkindex + 1;
}
else {
data.links[i].linkindex = 1;
}
// save the total number of links between two nodes
if (mLinkNum[data.links[i].target + "," + data.links[i].source] !== undefined) {
mLinkNum[data.links[i].target + "," + data.links[i].source] = data.links[i].linkindex;
}
else {
mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex;
}
}
}
});
</script>
</div>
<div id="graphContainer" class="graphContainer"></div>
</form>
</body>
</html>
I've made a fiddle with the basic arrow head example: https://jsfiddle.net/4xt5v51m/3/
I defined the arrow head:
svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 15)
.attr("refY", 0.5)
.attr("markerWidth", 2)
.attr("markerHeight", 2)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
and then set your link attribute to this marker:
.attr("marker-end", "url(#end)");
You can change the color, size, shape and position by playing with the attributes of the marker.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With