我想用d3在围绕力的有向图构建中绘制一个船体。
我已经用圆圈建立了图表。但是我现在想将圆形的交点与路径(船体)连接起来。如果不加入交点,则在圆组周围绘制船体就足够了。我尝试了Force-Directed Layout with Convex Hull示例。但是我有覆盖文本的文本和圆圈以及连接文本的链接。
var vertices = new Array();
var width = 960,
height = 500;
var color = d3.scale.category10();
var r = 6;
var force = d3.layout.force().size([width, height]);
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height).attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
$(function() {
var json = "{\"nodes\":[{\"name\":\"language\",\"group\":1,\"fontsize\":\"45px\",\"title\":null},{\"name\":\"english\",\"group\":1,\"fontsize\":\"35px\",\"title\":null},{\"name\":\"languages\",\"group\":1,\"fontsize\":\"21px\",\"title\":null},{\"name\":\"speak\",\"group\":1,\"fontsize\":\"16px\",\"title\":null},{\"name\":\"religion\",\"group\":1,\"fontsize\":\"16px\",\"title\":null},{\"name\":\"words\",\"group\":1,\"fontsize\":\"16px\",\"title\":null},{\"name\":\"living\",\"group\":1,\"fontsize\":\"16px\",\"title\":null},{\"name\":\"adobe\",\"group\":2,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"malayalam\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"learn\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"multilanguage\",\"group\":3,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"different\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"sarcasm\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"linkedin\",\"group\":4,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"hindi\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"indesign\",\"group\":5,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"city\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"spanish\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"religious\",\"group\":1,\"fontsize\":\"15px\",\"title\":null},{\"name\":\"real\",\"group\":1,\"fontsize\":\"15px\",\"title\":null}],\"links\":[{\"source\":0,\"target\":1,\"value\":1},{\"source\":0,\"target\":2,\"value\":1},{\"source\":0,\"target\":3,\"value\":1},{\"source\":0,\"target\":4,\"value\":1},{\"source\":0,\"target\":5,\"value\":1},{\"source\":1,\"target\":2,\"value\":1},{\"source\":1,\"target\":3,\"value\":1},{\"source\":1,\"target\":5,\"value\":1},{\"source\":1,\"target\":6,\"value\":1},{\"source\":2,\"target\":3,\"value\":1},{\"source\":2,\"target\":4,\"value\":1},{\"source\":2,\"target\":5,\"value\":1},{\"source\":3,\"target\":5,\"value\":1},{\"source\":3,\"target\":8,\"value\":1},{\"source\":4,\"target\":5,\"value\":1},{\"source\":4,\"target\":6,\"value\":1},{\"source\":4,\"target\":11,\"value\":1},{\"source\":5,\"target\":6,\"value\":1},{\"source\":6,\"target\":2,\"value\":1},{\"source\":6,\"target\":11,\"value\":1},{\"source\":6,\"target\":18,\"value\":1},{\"source\":8,\"target\":0,\"value\":1},{\"source\":8,\"target\":2,\"value\":1},{\"source\":8,\"target\":14,\"value\":1},{\"source\":9,\"target\":0,\"value\":1},{\"source\":9,\"target\":1,\"value\":1},{\"source\":9,\"target\":2,\"value\":1},{\"source\":9,\"target\":3,\"value\":1},{\"source\":9,\"target\":8,\"value\":1},{\"source\":11,\"target\":0,\"value\":1},{\"source\":11,\"target\":1,\"value\":1},{\"source\":11,\"target\":2,\"value\":1},{\"source\":11,\"target\":3,\"value\":1},{\"source\":12,\"target\":0,\"value\":1},{\"source\":12,\"target\":1,\"value\":1},{\"source\":12,\"target\":2,\"value\":1},{\"source\":12,\"target\":3,\"value\":1},{\"source\":12,\"target\":14,\"value\":1},{\"source\":14,\"target\":0,\"value\":1},{\"source\":14,\"target\":1,\"value\":1},{\"source\":14,\"target\":2,\"value\":1},{\"source\":14,\"target\":3,\"value\":1},{\"source\":14,\"target\":5,\"value\":1},{\"source\":16,\"target\":0,\"value\":1},{\"source\":16,\"target\":1,\"value\":1},{\"source\":16,\"target\":2,\"value\":1},{\"source\":16,\"target\":9,\"value\":1},{\"source\":16,\"target\":11,\"value\":1},{\"source\":17,\"target\":0,\"value\":1},{\"source\":17,\"target\":1,\"value\":1},{\"source\":17,\"target\":2,\"value\":1},{\"source\":17,\"target\":3,\"value\":1},{\"source\":18,\"target\":2,\"value\":1},{\"source\":18,\"target\":4,\"value\":1},{\"source\":18,\"target\":5,\"value\":1},{\"source\":18,\"target\":11,\"value\":1},{\"source\":19,\"target\":0,\"value\":1},{\"source\":19,\"target\":1,\"value\":1},{\"source\":19,\"target\":2,\"value\":1},{\"source\":19,\"target\":3,\"value\":1},{\"source\":19,\"target\":5,\"value\":1}]}";
json = htmlDecode(json);
json = $.parseJSON(json);
svg.append("svg:rect").attr("width", width).attr("height", height).style("stroke", "#fff").style("fill", "#fff");
force.nodes(json.nodes).links(json.links).gravity(0.05).linkDistance(120).charge(-200).start();
var node = svg.selectAll(".node").data(json.nodes).enter().append("g").attr("class", "node");
var link = svg.selectAll(".link").data(json.links).enter().append("line").attr("class", "link").style("stroke-opacity", "0.2");
node.append('circle').attr('r', function(d) {
var tmprad = parseInt(d.fontsize.replace('px', '')) * (d.name.length / 3);
if (tmprad > r) r = tmprad;
return tmprad;
}).style('fill', '#ffffff').style('stroke', function(d) {
return color(d.group)
});
node.selectAll('text').data(json.nodes).enter().append("text").attr("text-anchor", "middle").attr("dx", 2).attr("dy", ".35em").attr('original-title', function(d) {
return d.title
}).attr("style", function(d) {
return "font-size:" + d.fontsize
}).text(function(d) {
return d.name
}).attr("style", function(d) {
return "font-size:" + d.fontsize
}).style('fill', function(d) {
return color(d.group)
}).style("cursor", "pointer").call(force.drag);
var cx = new Array();
var cy = new Array();
node.attr("cx", function(d) {
cx.push(d.x);
}).attr("cy", function(d) {
cy.push(d.y);
});
cx.forEach(function(o, i) {
vertices.push(new Array(cx[i], cy[i]));
});
var nodes = vertices.map(Object);
var groups = d3.nest().key(function(d) {
return d;
}).entries(nodes);
var groupPath = function(d) {
return "M" + d3.geom.hull(d.values.map(function(i) {
return [i.x, i.y];
})).join("L") + "Z";
};
var groupFill = function(d, i) {
return color(i & 3);
};
svg.style("opacity", 1e-6).transition().duration(1000).style("opacity", 1);
force.on("tick", function() {
link.attr("x1", function(d) {
return d.source.x;
}).attr("y1", function(d) {
return d.source.y;
}).attr("x2", function(d) {
return d.target.x;
}).attr("y2", function(d) {
return d.target.y;
});
node.attr("cx", function(d) {
return d.x = Math.max(r, Math.min(width - r, d.x));
}).attr("cy", function(d) {
return d.y = Math.max(r, Math.min(height - r, d.y));
});
node.selectAll('circle').attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
});
// reposition text
node.selectAll('text').attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
});
});
});
function htmlEncode(value) {
return $('<div/>').text(value).html();
}
function htmlDecode(value) {
return $('<div/>').html(value).text();
}
function move() {
vertices[0] = d3.svg.mouse(this);
update();
}
function click() {
vertices.push(d3.svg.mouse(this));
update();
}
function update() {
svg.selectAll("path")
.data([d3.geom.hull(vertices)])
.attr("d", function(d) {
return "M" + d.join("L") + "Z";
})
.enter()
.append("svg:path")
.attr("d", function(d) {
return "M" + d.join("L") + "Z";
});
svg.selectAll("nodes")
.data(vertices.slice(1))
.enter()
.append("svg:circle")
.attr("transform", function(d) {
return "translate(" + d + ")";
});
}
您可以在JsFiddle上查看此代码的示例:
最佳答案
我和您的JsFiddle一起玩了一点,最后得到了这个:JsFiddle Example。
我刚刚添加
svg.selectAll("path")
.data(groups)
.attr("d", groupPath)
.enter().insert("path", "g")
.style("fill", groupFill)
.style("stroke", groupFill)
.style("stroke-width", 100)
.style("stroke-linejoin", "round")
.style("opacity", .2)
.attr("d", groupPath);
绘制船体,并扭曲了您定义的功能(groupPath,groupFill)。另外,我定义了组来标识图的不同组。
它是您发布的其他链接的肮脏端口,并且船体并未完全覆盖较大的圆圈。您将必须获得一个具有可变笔触宽度的路径,具体取决于圆的大小。不知道该怎么做。
不过,您可以在路径的笔划宽度上稍作调整,以使船体更大/更小。
希望对您有所帮助。
编辑:我通过一些数学改进了我的示例。您可以看到Here,它可以处理少量气泡。
它仍然是糟糕/笨拙的代码(我只是为了好玩而已),但是您可以找到我使用的三角函数。诀窍是要求d3使用d3.geom.hull来计算组的船体,这将返回有趣节点的坐标列表。您可以想象在每个角节点处绘制一个正确大小的圆。然后,您必须找到这些圆和连接它们的线段之间的交点。我使用了一张纸,Thales定理和一些三角函数来找出这些点的坐标。在特定情况下,该计算有些偏离,但是我不知道d3.geom.hull的实际工作原理,也不知道d3通常如何工作,因此我无法为您提供更多帮助。