Reputation: 1817
Here I'm working with D3 Network chart, in my fiddle, you can see arrow head pointing towards target node (right side), see the below screenshot:
But what i need is the opposite, like shown below:
Does anybody know how I can accomplish this?
Here is my code:
var width = 500
height = 550;
var cluster = d3.layout.cluster()
.size([height - height * 0, width - width * 0.5]);
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.y, d.x];
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.attr("style", "padding-left:5%")
.attr("pointer-events", "all")
.call(d3.behavior.zoom().on("zoom", redraw));
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var vis = svg
.append("svg:g");
vis.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("fill", 'white');
function redraw() {
vis.attr("transform",
"translate(" + d3.event.translate + ")" +
" scale(" + d3.event.scale + ")");
}
var root = {
"name": "output",
"children": [{
"name": "sum",
"children": [{
"name": "Base",
"children": [],
"weight": 1.0000002576768052
}, {
"name": "H0",
"children": [],
"weight": 2.5767680512326025e-7
}]
}]
};
var nodes = cluster.nodes(root),
links = cluster.links(nodes);
vis.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", -1.5)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var link = vis.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("marker-end", "url(#end)")
.attr("d", diagonal);
var node = vis.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
node.append("circle")
.attr("r", 4.5)
.style("fill", "#3182bd");
node.append("svg:text")
.attr("dx", function(d) {
return d.children ? -8 : 8;
})
.attr("dy", 3)
.style("text-anchor", function(d) {
return d.children ? "end" : "start";
})
.style("fill", "#3182bd")
.text(function(d) {
return d.name;
});
function mouseover() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 9)
d3.select(this).select("text").transition()
.duration(750)
.style("stroke-width", ".5px")
.style("font", "22.8px serif")
.style("opacity", 1);
}
function mouseout() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 4.5)
d3.select(this).select("text").transition()
.duration(750)
.style("font", "12px serif")
.style("opacity", 0.8);
}
d3.select(self.frameElement).style("height", height + "px");
Upvotes: 0
Views: 945
Reputation: 4876
You can achieve this in two simple steps
.attr("marker-start", "url(#end)")
.attr("orient", 180)
There was not enough info on MDN about the attributes of the marker however this page has more than enough :)
var width = 500
height = 550;
var cluster = d3.layout.cluster()
.size([height - height * 0, width - width * 0.5]);
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.y, d.x];
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.attr("style", "padding-left:5%")
.attr("pointer-events", "all")
.call(d3.behavior.zoom().on("zoom", redraw));
// Define the div for the tooltip
var div = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var vis = svg
.append("svg:g");
vis.append("svg:rect")
.attr("width", width)
.attr("height", height)
.attr("fill", 'white');
function redraw() {
vis.attr("transform",
"translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}
//var root = {"name":"Canada","children":[{"name":"Newfoundland","children":[{"name":"St. John's"}]},{"name":"PEI","children":[{"name":"Charlottetown"}]},{"name":"Nova Scotia","children":[{"name":"Halifax"}]},{"name":"New Brunswick","children":[{"name":"Fredericton"}]},{"name":"Quebec","children":[{"name":"Montreal"},{"name":"Quebec City"}]},{"name":"Ontario","children":[{"name":"Toronto"},{"name":"Ottawa"}]},{"name":"Manitoba","children":[{"name":"Winnipeg"}]},{"name":"Saskatchewan","children":[{"name":"Regina"}]},{"name":"Nunavuet","children":[{"name":"Iqaluit"}]},{"name":"NWT","children":[{"name":"Yellowknife"}]},{"name":"Alberta","children":[{"name":"Edmonton"}]},{"name":"British Columbia","children":[{"name":"Victoria"},{"name":"Vancouver"}]},{"name":"Yukon","children":[{"name":"Whitehorse"}]}]} ;
var root = {
"name": "output",
"children": [{
"name": "sum",
"children": [{
"name": "Base",
"children": [],
"weight": 1.0000002576768052
}, {
"name": "H0",
"children": [],
"weight": 2.5767680512326025e-7
}]
}]
};
var nodes = cluster.nodes(root),
links = cluster.links(nodes);
vis.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)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", 180)
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5");
var link = vis.selectAll(".link")
.data(links)
.enter().append("path")
.attr("class", "link")
.attr("marker-start", "url(#end)")
.attr("d", diagonal);
/*.on("mouseover", function(d) {
//console.log(d.children.weight);
div.transition()
.duration(200)
.style("opacity", .9);
div .html(d.y)
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
})
.on("mouseout", function(d) {
div.transition()
.duration(500)
.style("opacity", 0);
});*/
var node = vis.selectAll(".node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
})
.on("mouseover", mouseover)
.on("mouseout", mouseout);
node.append("circle")
.attr("r", 4.5)
.style("fill", "#3182bd");
node.append("svg:text")
.attr("dx", function(d) {
return d.children ? -8 : 8;
})
.attr("dy", 3)
.style("text-anchor", function(d) {
return d.children ? "end" : "start";
})
.style("fill", "#3182bd")
.text(function(d) {
return d.name;
});
/*var linktext = vis.append("svg:g").selectAll("g.linklabelholder").data(links);
linktext.enter().append("g").attr("class", "linklabelholder")
.append("text")
.attr("class", "linklabel")
.style("font-size", "13px")
.attr("x", "50")
.attr("y", "-20")
.attr("text-anchor", "start")
.style("fill","#000")
.append("textPath")
.attr("xlink:href",function(d,i) { return "#linkId_" + i;})
.text(function(d) {
return d.type;
});*/
function mouseover() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 9)
d3.select(this).select("text").transition()
.duration(750)
.style("stroke-width", ".5px")
.style("font", "22.8px serif")
.style("opacity", 1);
}
function mouseout() {
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", 4.5)
d3.select(this).select("text").transition()
.duration(750)
.style("font", "12px serif")
.style("opacity", 0.8);
}
d3.select(self.frameElement).style("height", height + "px");
.link {
fill: none;
stroke: #ccc;
opacity: 0.4;
stroke-width: 1.5px;
}
.node circle {
stroke: #fff;
opacity: 0.8;
stroke-width: 1.5px;
}
.node:not(:hover) .nodetext {
display: none;
}
text {
font: 12px serif;
opacity: 0.8;
pointer-events: none;
}
div.tooltip {
position: absolute;
text-align: center;
width: 60px;
height: 28px;
color: black;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 2
Reputation: 901
Perhaps you could use the attr marker-start
where you mark arrow at line
.attr("marker-end", "url(#end)")
.attr("marker-start", "url(#end)")
IIRC, the hash id is tied to some CSS defined path (ie, the arrow). This would put the shape at the start. You may have to tweak the path if the arrow is 'backwards'
Upvotes: 2