我用D3做了一个算法来可视化一些数据。算法正在做我所期望的事情。他用Force布局分隔多个焦点中的节点,链接和节点动态地出现和消失。
问题来自于节点的标记。D3似乎做的工作,但多次为每个节点(当我看它与firebug)。
下面是我的代码:var actions = [
{"action":"arrivee","id":"001","service":1},
{"action":"arrivee","id":"002","service":1},
{"action":"arrivee","id":"003","service":1},
{"action":"arrivee","id":"004","service":1},
{"action":"arrivee","id":"005","service":1},
{"action":"arrivee","id":"006","service":3},
{"action":"arrivee","id":"007","service":3},
{"action":"arrivee","id":"008","service":3},
{"action":"arrivee","id":"009","service":3},
{"action":"arrivee","id":"010","service":2},
{"action":"arrivee","id":"011","service":2},
{"action":"arrivee","id":"012","service":2},
{"action":"arrivee","id":"013","service":2},
{"action":"arrivee","id":"014","service":4},
{"action":"arrivee","id":"015","service":4},
{"action":"arrivee","id":"016","service":4},
{"action":"arrivee","id":"017","service":4},
{"action":"contact","id":"0","source":"001","target":"017"},
{"action":"contact","id":"1","source":"016","target":"012"},
{"action":"contact","id":"2","source":"004","target":"011"},
{"action":"contact","id":"3","source":"001","target":"010"},
{"action":"fincontact","id":"0"},
{"action":"depart","id":"017"},
{"action":"arrivee","id":"018","service":2},
{"action":"arrivee","id":"019","service":1},
{"action":"arrivee","id":"020","service":1},
{"action":"arrivee","id":"021","service":0},
{"action":"arrivee","id":"022","service":0},
{"action":"arrivee","id":"023","service":0},
{"action":"arrivee","id":"024","service":0},
{"action":"arrivee","id":"025","service":0},
{"action":"arrivee","id":"026","service":0},
{"action":"arrivee","id":"027","service":3},
{"action":"arrivee","id":"028","service":2},
{"action":"arrivee","id":"029","service":2},
{"action":"arrivee","id":"030","service":2},
{"action":"arrivee","id":"031","service":2},
{"action":"arrivee","id":"032","service":4},
{"action":"arrivee","id":"033","service":4},
{"action":"arrivee","id":"034","service":4},
{"action":"arrivee","id":"035","service":4},
{"action":"contact","id":"4","source":"013","target":"002"},
{"action":"contact","id":"5","source":"009","target":"008"},
{"action":"contact","id":"6","source":"005","target":"007"},
{"action":"contact","id":"7","source":"009","target":"014"},
{"action":"fincontact","id":"7"},
{"action":"fincontact","id":"6"},
{"action":"fincontact","id":"5"},
{"action":"fincontact","id":"4"},
{"action":"fincontact","id":"3"},
{"action":"fincontact","id":"2"},
{"action":"fincontact","id":"1"},
{"action":"depart","id":"016"},
{"action":"depart","id":"015"},
{"action":"depart","id":"014"},
{"action":"depart","id":"013"},
{"action":"depart","id":"012"},
{"action":"depart","id":"011"},
{"action":"depart","id":"010"},
{"action":"depart","id":"009"},
{"action":"depart","id":"008"},
{"action":"depart","id":"007"},
{"action":"depart","id":"006"},
{"action":"depart","id":"005"},
{"action":"depart","id":"004"},
{"action":"depart","id":"003"},
{"action":"depart","id":"002"},
{"action":"depart","id":"018"},
{"action":"depart","id":"019"},
{"action":"depart","id":"020"},
{"action":"depart","id":"021"},
{"action":"depart","id":"022"},
{"action":"depart","id":"023"},
{"action":"depart","id":"024"},
{"action":"depart","id":"025"},
{"action":"depart","id":"026"},
{"action":"depart","id":"027"},
{"action":"depart","id":"028"},
{"action":"depart","id":"029"},
{"action":"depart","id":"030"},
{"action":"depart","id":"031"},
{"action":"depart","id":"032"},
{"action":"depart","id":"033"},
{"action":"depart","id":"034"},
{"action":"depart","id":"035"},
{"action":"depart","id":"001"}]
var vv = window,
w = vv.innerWidth,
h = vv.innerHeight;
var rmax = 30;
foci = [{x: 500, y: 150}, {x: 200, y: 500}, {x: 700, y: 500}, {x: 400, y: 700}, {x: 600, y: 700}];
//canevas selection
var svg = d3.select("#animviz")
.append("svg")
.attr("width", w)
.attr("height", h);
var fill = d3.scale.category10();
//link and node class creation
svg.append("g").attr("class", "links");
svg.append("g").attr("class", "nodes");
//to know if the graphs are up to date
var uptodate = true;
var nIntervId;
//containers de noeuds et liens
var nodes = [], links = [];
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([w, h])
.friction(0.9)
.charge(-50)
.gravity(0.02)
.linkDistance(50)
.charge(-500)
.on("tick", tick);
var iter = 0;
var node = svg.select(".nodes").selectAll(".node");
var link = svg.select(".links").selectAll(".link");
//repeat an action every "interval"
var interval = 0.2;
nIntervId = setInterval(function() {
var action = readData();
addData(action);
if(!uptodate){
update();
}
}, interval*1000);
function addData(action) {
uptodate = false;
switch(action.action) {
case "arrivee":
nodes.push({id: action.id, service: action.service});
break;
case "depart":
for (var i = nodes.length - 1; i >= 0; i--) {
if(nodes[i].id == action.id){
nodes.splice(i, 1);
}
};
break;
case "contact":
var source;
var target;
for (var i = nodes.length - 1; i >= 0; i--) {
if(nodes[i].id == action.source){
source = nodes[i];
}
if(nodes[i].id == action.target){
target = nodes[i];
}
};
links.push({source:source, target:target, id:action.id});
break;
case "fincontact":
for (var i = links.length - 1; i >= 0; i--) {
if(links[i].id == action.id){
links.splice(i, 1);
}
};
break;
default:
uptodate = true;
}
}
function readData(){
var n = iter;
iter++;
var data = actions[n];
return data;
}
function update() {
force.start();
link = link.data(force.links(), function(d) { return d.source.id+"-"+d.target.id; });
link.enter()
.append("line")
.attr("class", "link")
.attr("stroke", "#ccc")
.attr("stroke-width", 2);
link.exit().remove();
var r = d3.scale.sqrt()
.domain(d3.extent(force.nodes(), function(d) {return d.weight; }))
.range([15, rmax]);
node = node.data(force.nodes(), function(d) { return d.id; });
node.enter()
.append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 20)
.style("stroke-width", "10")
.style("fill", "white")//function(d, i) { return fill(d.service ); })
.style("stroke", function(d, i) { return d3.rgb(i & 1 ? "red" : "green") })
node.append("text")
.attr("text-anchor","middle")
.text(function(d) {return d.id});
node.exit().remove();
}
function tick(e) {
var k = 0.5 * e.alpha;
nodes.forEach(function(o, i) {
o.y += (foci[o.service].y - o.y) * k;
o.x += (foci[o.service].x - o.x) * k;
});
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(rmax, Math.min(w - rmax, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(rmax, Math.min(h - rmax, d.y)); });
}
readData()读取数据帧,addData()是一个大循环有动态移动和更新()是D3部分,我试图标记我的节点。
我错过了一些明显的东西。
谢谢你。
经过几天的搜索,我能够发布工作代码作为答案。
var actions = [
{"action":"arrivee","id":"001","service":1},
{"action":"arrivee","id":"002","service":1},
{"action":"arrivee","id":"003","service":1},
{"action":"arrivee","id":"004","service":1},
{"action":"arrivee","id":"005","service":1},
{"action":"arrivee","id":"006","service":3},
{"action":"arrivee","id":"007","service":3},
{"action":"arrivee","id":"008","service":3},
{"action":"arrivee","id":"009","service":3},
{"action":"arrivee","id":"010","service":2},
{"action":"arrivee","id":"011","service":2},
{"action":"arrivee","id":"012","service":2},
{"action":"arrivee","id":"013","service":2},
{"action":"arrivee","id":"014","service":4},
{"action":"arrivee","id":"015","service":4},
{"action":"arrivee","id":"016","service":4},
{"action":"arrivee","id":"017","service":4},
{"action":"contact","id":"0","source":"001","target":"017"},
{"action":"contact","id":"1","source":"016","target":"012"},
{"action":"contact","id":"2","source":"004","target":"011"},
{"action":"contact","id":"3","source":"001","target":"010"},
{"action":"fincontact","id":"0"},
{"action":"depart","id":"017"},
{"action":"arrivee","id":"018","service":2},
{"action":"arrivee","id":"019","service":1},
{"action":"arrivee","id":"020","service":1},
{"action":"arrivee","id":"021","service":0},
{"action":"arrivee","id":"022","service":0},
{"action":"arrivee","id":"023","service":0},
{"action":"arrivee","id":"024","service":0},
{"action":"arrivee","id":"025","service":0},
{"action":"arrivee","id":"026","service":0},
{"action":"arrivee","id":"027","service":3},
{"action":"arrivee","id":"028","service":2},
{"action":"arrivee","id":"029","service":2},
{"action":"arrivee","id":"030","service":2},
{"action":"arrivee","id":"031","service":2},
{"action":"arrivee","id":"032","service":4},
{"action":"arrivee","id":"033","service":4},
{"action":"arrivee","id":"034","service":4},
{"action":"arrivee","id":"035","service":4},
{"action":"contact","id":"4","source":"013","target":"002"},
{"action":"contact","id":"5","source":"009","target":"008"},
{"action":"contact","id":"6","source":"005","target":"007"},
{"action":"contact","id":"7","source":"009","target":"014"},
{"action":"fincontact","id":"7"},
{"action":"fincontact","id":"6"},
{"action":"fincontact","id":"5"},
{"action":"fincontact","id":"4"},
{"action":"fincontact","id":"3"},
{"action":"fincontact","id":"2"},
{"action":"fincontact","id":"1"},
{"action":"depart","id":"016"},
{"action":"depart","id":"015"},
{"action":"depart","id":"014"},
{"action":"depart","id":"013"},
{"action":"depart","id":"012"},
{"action":"depart","id":"011"},
{"action":"depart","id":"010"},
{"action":"depart","id":"009"},
{"action":"depart","id":"008"},
{"action":"depart","id":"007"},
{"action":"depart","id":"006"},
{"action":"depart","id":"005"},
{"action":"depart","id":"004"},
{"action":"depart","id":"003"},
{"action":"depart","id":"002"},
{"action":"depart","id":"018"},
{"action":"depart","id":"019"},
{"action":"depart","id":"020"},
{"action":"depart","id":"021"},
{"action":"depart","id":"022"},
{"action":"depart","id":"023"},
{"action":"depart","id":"024"},
{"action":"depart","id":"025"},
{"action":"depart","id":"026"},
{"action":"depart","id":"027"},
{"action":"depart","id":"028"},
{"action":"depart","id":"029"},
{"action":"depart","id":"030"},
{"action":"depart","id":"031"},
{"action":"depart","id":"032"},
{"action":"depart","id":"033"},
{"action":"depart","id":"034"},
{"action":"depart","id":"035"},
{"action":"depart","id":"001"}]
var vv = window,
w = vv.innerWidth,
h = vv.innerHeight;
foci = [{x: 500, y: 150}, {x: 200, y: 500}, {x: 700, y: 500}, {x: 400, y: 700}, {x: 600, y: 700}];
var svg = d3.select("body").append("svg")
.attr("width", w)
.attr("height", h);
var links = [], nodes = [];
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([w, h])
.friction(0.9)
.charge(-50)
.gravity(0.02)
.linkDistance(50)
.charge(-500)
.on("tick", tick);
var link;
var node;
var iter = 0;
var interval = 0.2;
var uptodate = true;
var nIntervId;
nIntervId = setInterval(function() {
//alert("je passe");
var action = readData();
addData(action);
if(!uptodate){
update();
}
}, interval*1000);
function addData(action) {
uptodate = false;
switch(action.action) {
case "arrivee":
nodes.push({id: action.id, service: action.service});
break;
case "depart":
for (var i = nodes.length - 1; i >= 0; i--) {
if(nodes[i].id == action.id){
nodes.splice(i, 1);
}
};
break;
case "contact":
var source;
var target;
for (var i = nodes.length - 1; i >= 0; i--) {
if(nodes[i].id == action.source){
source = nodes[i];
}
if(nodes[i].id == action.target){
target = nodes[i];
}
};
links.push({source:source, target:target, id:action.id});
break;
case "fincontact":
for (var i = links.length - 1; i >= 0; i--) {
if(links[i].id == action.id){
links.splice(i, 1);
}
};
break;
default:
uptodate = true;
}
}
function readData(){
var n = iter;
iter++;
var data = actions[n];
return data;
}
function update(){
force.start();
link = svg.selectAll(".link")
.data(force.links());
link.enter().append("line")
.attr("class", "link");
link.exit().remove();
node = svg.selectAll(".node")
.data(force.nodes());
node.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", 20)
.style("stroke-width", "10")
.style("fill", "white")//function(d, i) { return fill(d.service ); })
.style("stroke", function(d, i) { return d3.rgb(i & 1 ? "red" : "green") });
node.append("text")
.attr("text-anchor","middle")
.text(function(d) { return d.id });
node.exit().remove();
}
function tick(e) {
var k = 0.5 * e.alpha;
nodes.forEach(function(o, i) {
o.y += (foci[o.service].y - o.y) * k;
o.x += (foci[o.service].x - o.x) * k;
});
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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
};
谢谢你的帮助