我有以下代码可以使用,但我有两个问题需要帮助。
某些节点可以有两个链接并且它们重叠。我怎么才能换掉 第二个链接上的ARC方向是为了防止这种情况发生?
var json_data = data;
var hash_lookup = [];
json_data.nodes.forEach(function (d, i) {
hash_lookup[d.id] = d;
});
json_data.links.forEach(function (d, i) {
d.source = hash_lookup[d.source];
d.target = hash_lookup[d.target];
});
var width = ($("#dependency_map").width()-10);
var height = ($("#dependency_map").height()-10);
d3.select("#dependency_map").selectAll("*").remove();
var force = d3.layout.force()
.gravity(.05)
.distance(100)
.linkStrength(.4)
.charge(-200)
.size([width, height]);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", zoomed);
var svg = d3.select("#dependency_map")
.append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-events", "all")
.append('svg:g')
.call(zoom).on("dblclick.zoom", null)
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
function dblclick(d) {
d3.select(this).classed("fixed", d.fixed = false);
}
function dragstarted(d) {
if(d3.event.sourceEvent.button == 0) {
d3.event.sourceEvent.stopPropagation();
force.start();
}
}
function dragged(d) {
if(d3.event.sourceEvent.button == 0) {
d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
}
}
function dragended(d) {
if(d3.event.sourceEvent.button == 0) {
d3.select(this).classed("fixed", d.fixed = true);
d3.select(this).classed("dragging", false);
}
}
var drag = d3.behavior.drag()
.on("dragstart", dragstarted)
.on("drag", dragged)
.on("dragend", dragended);
var nodes = json_data.nodes,
links = json_data.links;
var container = svg.append("g");
// build the arrow.
container.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");
// make an arch between nodes and a text label in the middle
var path = container.selectAll("path.link").data(links);
path.enter().append("path")
.attr("class", "link")
.attr("id",function(d,i) { return "linkId_" + i; })
.attr("marker-end", "url(#end)");
var linktext = container.append("svg:g").selectAll("g.linklabelholder").data(links);
linktext.enter().append("g").attr("class", "linklabelholder")
.append("text")
.attr("class", "linklabel")
.style("font-size", "0.5em")
.attr("dy", "-2")
.style("fill","#000")
.append("textPath")
.attr("startOffset","50%")
.style("text-anchor","middle")
.attr("xlink:href",function(d,i) { return "#linkId_" + i;})
.text(function(d) {
return d.text;
});
var node = container.selectAll("g.node")
.data(nodes)
.enter()
.append("svg:g")
.attr("class", "node")
.on("dblclick", dblclick)
.call(drag)
.on("contextmenu", function(data, index) {
console.log("Context Menu Click");
if (data.knownworkload == true)
{
d3.select('#cntxtMenu')
.style('position', 'absolute')
.style('left', data.px + 50 + "px")
.style('top', data.py + "px")
.style('display', 'block')
.on('mouseleave', function() {
d3.select('#cntxtMenu').style('display', 'none');
context = null;
});
d3.selectAll('.workload_menu').on('click' , function(d) {
var action = d3.select(this).attr("action");
var workload_id = data.guid;
if (action == "information")
{
$.ajax({
async:true,
url: "<%= url(format: :js) %>",
data: {
workload_id: workload_id
}
});
$('#cntxtMenu').hide();
}
else
{
var servicestack_id = d3.select(this).attr("guid");
$.ajax({
async:false,
url: "<%= url %>",
data: {
workload_id: workload_id,
servicestack_id: servicestack_id,
success: function (data, status, jqXHR) {
},
}
});
draw_map();
$('#cntxtMenu').hide();
}
});
}
d3.event.preventDefault();
});
function zoomed() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
nodes.forEach(function(d, i) {
d.x = width/2 + i;
d.y = height/2 + (1500 * d.depth);
});
force.nodes(nodes)
.links(links)
.start();
node.append('svg:text')
.attr('font-family', function (d) {
return d.icon.fontfamily;
})
.attr('font-size', '0.8em')
.attr('fill', function (d) {
return d.icon.color;})
.text(function (d) {return d.icon.icon;})
.attr("x", "-5px")
.attr("y", "5px");
node.append("svg:text")
.attr("y", "15px")
.attr('font-size', '0.6em')
.attr("text-anchor", "middle")
.each(function (d) {
var arr = d.name.split(" ");
if (arr != undefined) {
for (i = 0; i < arr.length; i++) {
d3.select(this).append("tspan")
.text(arr[i])
.attr("cy", (i == 0) ? 0 : 10)
.attr("text-anchor", "left")
.attr("class", "nodetext");
}
}
});
for (var i=0; i<path.length; i++) {
if (i != 0 &&
path[i].source == path[i-1].source &&
path[i].target == path[i-1].target) {
path[i].linknum = path[i-1].linknum + 1;
}
else {path[i].linknum = 1;};
};
node.append("svg:title")
.text(function (d) {
return d.tooltip;
});
force.on("tick", function(e) {
path.attr("d", function(d) {
console.log(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;
});
node.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
});
}, });