Direct Force Layout 自定义 - d3.js
Direct Force Layout customization - d3.js
关于 Stack Overflow 的第一个问题,请多多包涵!我是 d3.js 的新手,但一直对其他人能够用它完成的事情感到惊讶……而且几乎同样惊讶于我自己用它取得的进展如此之小!显然我不是在摸索什么,所以我希望这里的好心人能为我指明方向。
我的目的是根据CSV数据制作一个连通图。我的 CSV 数据有不同的信息,其中一些需要表示为节点,其中一些需要用作 ltool-tip 的信息。我可以使用这段代码从 CSV 中读取数据:
d3.csv("data/project.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem);
});
这会将节点 P1 连接到三个节点问题 (URLs)。
问题来了,我在选中的节点上看不到标签,如何使用"Date, Summary, URL"等CSV文件中的提取信息。有什么方法可以使用鼠标单击,当我单击节点时我需要它的信息出现在 SVG 板上以用于进一步分析,例如显示 URL、摘要的短文本,以及当用户单击时在板上它应该显示完整的信息。
这是我在 this link
中使用的代码
var width = 800,
height = 600;
var svg = d3.select("#visualization")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("svg:g");
var force = d3.layout.force()
.gravity(0.2)
.distance(200)
.charge(-1500)
.size([width, height]);
var container = svg.append("g")
.attr("id", "container");
d3.csv("data/project.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem);
});
// Extract the array of nodes from the map by name.
var nodes = d3.values(nodesByName);
//define a scale for color mapping
var colormapping = d3.scale.ordinal()
.domain([0,nodes.length])
.range(['#A700E6','#D95B96','#F4DA88','#22C1BE','#F24957','#DBEF91','#CF8EE8','#FF9B58','#B8FFC4','#91AEFF','#E873D3','#CCB298']);
//create label node tooltip
var labeltooltip = d3.select("body").append("div")
.attr("class", "labeltooltip")
.style("opacity", 1e-6);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", function() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
});
svg.call(zoom);
//links
var link = container.selectAll(".line")
.data(links)
.enter()
.append("line")
.attr("stroke-width",4)
// .attr("stroke-width",function (d) { return linethickness(d.value); })
.style("stroke", "gray");
// Create the node circles.
var node = container.selectAll(".node")
.data(nodes)
.enter()
.append("circle")
.attr("class", "node")
.attr("r", 20)
.attr("fill", function (d,i) {return d3.rgb(colormapping(i)); })
.call(force.drag);
// Start the force layout.
force
.nodes(nodes)
.links(links)
.on("tick", tick)
.start();
node.on("mousemove", function(d) {
labeltooltip.selectAll("p").remove();
labeltooltip.style("left", (d3.event.pageX+15) + "px").style("top", (d3.event.pageY-10) + "px");
labeltooltip.append("p").attr("class", "tooltiptext").html("<span>Id: </span>" + d.Score );
labeltooltip.append("p").attr("class", "tooltiptext").html("<span>Score: </span>" + d.Score);
});
node.on("mouseover", function(d) {
labeltooltip.transition()
.duration(500)
.style("opacity", 1);
link.style('stroke', function(l) {
if (d === l.source || d === l.target)
return d3.rgb('#C20606');
else
return 'gray';
});
link.style('opacity', function(o) {
return o.source === d || o.target === d ? 1 : 0;
});
node.style("opacity", function(o) {
if (o.id != d.id)
return neighboring(d.id, o.id) ? 1 : 0;
});
});
node.on("mouseout", function(d) {
labeltooltip.transition()
.duration(500)
.style("opacity", 1e-6);
link.style('stroke', 'gray');
link.style('opacity', 1);
node.style("opacity", 1);
});
var circletext = node.append("svg:text")
.text(function(d) {return d.name;})
.attr("class","labelText");
function tick() {
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; })
.attr("cy", function(d) { return d.y; });
circletext.attr("x", function(d) { return d.x-25; });
circletext.attr("y", function(d) { return d.y-25;});
}
function nodeByName(name) {
return nodesByName[name] || (nodesByName[name] = {name: name});
}
addZoomMoveIcon("#labelgraph");
});
更新
我的 CSV 数据
Project,Problem, Score,Data,Summary,id
p1,Problem1,10,2014-09-04T13:55:05.623-04:00, text text text text, 1
p1,Problem2,5,2014-09-04T13:55:05.623-04:00, text text text text,2
p1,Problem3,11,2014-09-04T13:55:05.623-04:00, text text text text,3
我想要的最终结果如下图所示:
单击 "problem" 节点时黄色框应出现在 SVG 上的位置。
您需要解决的第一个问题是 where 以正确添加节点文本。现在您将文本嵌套在圆圈内,但文本标签需要是圆圈的兄弟姐妹(它们甚至不需要紧挨着每个圆圈)。您可以替换为:
var circletext = node.append("svg:text")
.text(function(d) {return d.name;})
.attr("class","labelText");
有:
var circletext = container.selectAll("g")
.data(nodes)
.enter()
.append("text").text(function(d) {return d.name})
.attr("class", "labelText");
(参考:https://www.dashingd3js.com/svg-text-element)
接下来,如果您想显示 Score/Data/Summary,请注意这些附加到 link,而不是节点(只有三个,而不是四个)。但是,在创建节点时,您可以将此信息从 link 传递到节点。修改 nodeByName 函数以添加节点的新属性:
function nodeByName(name,score,data,summary) {
return nodesByName[name] || (nodesByName[name] = {name: name, score: score, data: data, summary: summary});
}
然后在创建 link 时修改对此函数的调用:
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem,link.Score,link.Data,link.Summary);
});
要让 labeltooltip 显示在固定位置,而不是节点旁边,您需要删除节点鼠标悬停和鼠标移出事件上的位,这些事件会移动 div,并且可能只需将 div 添加到 html 而不是动态添加它。
关于 Stack Overflow 的第一个问题,请多多包涵!我是 d3.js 的新手,但一直对其他人能够用它完成的事情感到惊讶……而且几乎同样惊讶于我自己用它取得的进展如此之小!显然我不是在摸索什么,所以我希望这里的好心人能为我指明方向。
我的目的是根据CSV数据制作一个连通图。我的 CSV 数据有不同的信息,其中一些需要表示为节点,其中一些需要用作 ltool-tip 的信息。我可以使用这段代码从 CSV 中读取数据:
d3.csv("data/project.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem);
});
这会将节点 P1 连接到三个节点问题 (URLs)。 问题来了,我在选中的节点上看不到标签,如何使用"Date, Summary, URL"等CSV文件中的提取信息。有什么方法可以使用鼠标单击,当我单击节点时我需要它的信息出现在 SVG 板上以用于进一步分析,例如显示 URL、摘要的短文本,以及当用户单击时在板上它应该显示完整的信息。
这是我在 this link
中使用的代码 var width = 800,
height = 600;
var svg = d3.select("#visualization")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("svg:g");
var force = d3.layout.force()
.gravity(0.2)
.distance(200)
.charge(-1500)
.size([width, height]);
var container = svg.append("g")
.attr("id", "container");
d3.csv("data/project.csv", function(links) {
var nodesByName = {};
// Create nodes for each unique source and target.
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem);
});
// Extract the array of nodes from the map by name.
var nodes = d3.values(nodesByName);
//define a scale for color mapping
var colormapping = d3.scale.ordinal()
.domain([0,nodes.length])
.range(['#A700E6','#D95B96','#F4DA88','#22C1BE','#F24957','#DBEF91','#CF8EE8','#FF9B58','#B8FFC4','#91AEFF','#E873D3','#CCB298']);
//create label node tooltip
var labeltooltip = d3.select("body").append("div")
.attr("class", "labeltooltip")
.style("opacity", 1e-6);
var zoom = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", function() {
container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
});
svg.call(zoom);
//links
var link = container.selectAll(".line")
.data(links)
.enter()
.append("line")
.attr("stroke-width",4)
// .attr("stroke-width",function (d) { return linethickness(d.value); })
.style("stroke", "gray");
// Create the node circles.
var node = container.selectAll(".node")
.data(nodes)
.enter()
.append("circle")
.attr("class", "node")
.attr("r", 20)
.attr("fill", function (d,i) {return d3.rgb(colormapping(i)); })
.call(force.drag);
// Start the force layout.
force
.nodes(nodes)
.links(links)
.on("tick", tick)
.start();
node.on("mousemove", function(d) {
labeltooltip.selectAll("p").remove();
labeltooltip.style("left", (d3.event.pageX+15) + "px").style("top", (d3.event.pageY-10) + "px");
labeltooltip.append("p").attr("class", "tooltiptext").html("<span>Id: </span>" + d.Score );
labeltooltip.append("p").attr("class", "tooltiptext").html("<span>Score: </span>" + d.Score);
});
node.on("mouseover", function(d) {
labeltooltip.transition()
.duration(500)
.style("opacity", 1);
link.style('stroke', function(l) {
if (d === l.source || d === l.target)
return d3.rgb('#C20606');
else
return 'gray';
});
link.style('opacity', function(o) {
return o.source === d || o.target === d ? 1 : 0;
});
node.style("opacity", function(o) {
if (o.id != d.id)
return neighboring(d.id, o.id) ? 1 : 0;
});
});
node.on("mouseout", function(d) {
labeltooltip.transition()
.duration(500)
.style("opacity", 1e-6);
link.style('stroke', 'gray');
link.style('opacity', 1);
node.style("opacity", 1);
});
var circletext = node.append("svg:text")
.text(function(d) {return d.name;})
.attr("class","labelText");
function tick() {
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; })
.attr("cy", function(d) { return d.y; });
circletext.attr("x", function(d) { return d.x-25; });
circletext.attr("y", function(d) { return d.y-25;});
}
function nodeByName(name) {
return nodesByName[name] || (nodesByName[name] = {name: name});
}
addZoomMoveIcon("#labelgraph");
});
更新 我的 CSV 数据
Project,Problem, Score,Data,Summary,id
p1,Problem1,10,2014-09-04T13:55:05.623-04:00, text text text text, 1
p1,Problem2,5,2014-09-04T13:55:05.623-04:00, text text text text,2
p1,Problem3,11,2014-09-04T13:55:05.623-04:00, text text text text,3
我想要的最终结果如下图所示:
单击 "problem" 节点时黄色框应出现在 SVG 上的位置。
您需要解决的第一个问题是 where 以正确添加节点文本。现在您将文本嵌套在圆圈内,但文本标签需要是圆圈的兄弟姐妹(它们甚至不需要紧挨着每个圆圈)。您可以替换为:
var circletext = node.append("svg:text")
.text(function(d) {return d.name;})
.attr("class","labelText");
有:
var circletext = container.selectAll("g")
.data(nodes)
.enter()
.append("text").text(function(d) {return d.name})
.attr("class", "labelText");
(参考:https://www.dashingd3js.com/svg-text-element)
接下来,如果您想显示 Score/Data/Summary,请注意这些附加到 link,而不是节点(只有三个,而不是四个)。但是,在创建节点时,您可以将此信息从 link 传递到节点。修改 nodeByName 函数以添加节点的新属性:
function nodeByName(name,score,data,summary) {
return nodesByName[name] || (nodesByName[name] = {name: name, score: score, data: data, summary: summary});
}
然后在创建 link 时修改对此函数的调用:
links.forEach(function(link) {
link.source = nodeByName(link.Project);
link.target = nodeByName(link.Problem,link.Score,link.Data,link.Summary);
});
要让 labeltooltip 显示在固定位置,而不是节点旁边,您需要删除节点鼠标悬停和鼠标移出事件上的位,这些事件会移动 div,并且可能只需将 div 添加到 html 而不是动态添加它。