我有一个多焦点布局,无法找到动态设置焦点的方法。
在下面的代码中使用数据子集,我希望能够在id-group和熟悉度之间切换,这会将图表从3个气泡簇更改为5个气泡簇。目前的焦点是硬编码的,可防止切换工作。
var data = [
{"id": 0, "name": "AngularJS", "familiarity":0,"r": 50 },
{"id": 0, "name": "HTML5", "familiarity":1,"r": 40 },
{"id": 0, "name": "Javascript", "familiarity":2,"r": 30 },
{"id": 1, "name": "Actionscript","familiarity":0, "r": 50 },
{"id": 1, "name": "Flash", "familiarity":4, "r": 32 },
{"id": 2, "name": "Node Webkit", "familiarity":3,"r": 40 },
{"id": 2, "name": "Chrome App", "familiarity":3,"r": 30 },
{"id": 2, "name": "Cordova", "familiarity":0,"r": 45 },
];
var width = window.innerWidth,
height = 450;
var fill = d3.scale.category10();
var nodes = [], labels = [],
foci = [{x: 0, y: 150}, {x: 400, y: 150}, {x: 200, y: 150}];
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", height)
//.attr("domflag", '');
var force = d3.layout.force()
.nodes(nodes)
.links([])
.charge(-200)
.gravity(0.1)
.friction(0.8)
.size([width, height])
.on("tick", tick);
var node = svg.selectAll("g");
var counter = 0;
function tick(e) {
var k = .3 * e.alpha;
// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
o.y += (foci[o.id].y - o.y) * k;
o.x += (foci[o.id].x - o.x) * k;
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
var timer = setInterval(function(){
if (nodes.length > data.length-1) { clearInterval(timer); return;}
var item = data[counter];
nodes.push({id: item.id, r: item.r, name: item.name});
force.start();
node = node.data(nodes);
var n = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style('cursor', 'pointer')
.on('mousedown', function() {
var sel = d3.select(this);
sel.moveToFront();
})
.call(force.drag);
n.append("circle")
.attr("r", function(d) { return d.r/2; })
.style("fill", function(d) { return fill(d.id); })
n.append("text")
.text(function(d){
return d.name;
})
.style("font-size", function(d) {
return Math.min(2 * d.r, (2 * d.r - 8) / this.getComputedTextLength() * 16) + "px";
})
.attr("dy", ".35em")
counter++;
}, 100);
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
function resize() {
width = window.innerWidth;
force.size([width, height]);
force.start();
}
d3.select(window).on('resize', resize);

circle {
stroke: #fff;
}

<script src="//d3js.org/d3.v3.min.js"></script>
&#13;
如何动态设置焦点的坐标,如果它只有3-4个簇,则将其对齐成一行,但如果它是10个簇,则将其设为3行小倍数?
感谢。
答案 0 :(得分:2)
您最重要的变化是修改刻度功能,以便选择一组焦点或另一组。
然而,首先,我们需要跟踪当前正在使用的焦点。所有这一切都需要在&#34; family&#34;之间切换。和#34;熟悉&#34;或者不太直观的东西,如你想要的真假。我在下面的代码中使用了变量current
。
现在我们可以通过添加某种检查来添加到您现有的tick功能,以查看应该使用哪些焦点集:
function tick(e) {
var k = .3 * e.alpha;
// nudge nodes to proper foci:
if(current == "family" ) {
nodes.forEach(function(o, i) {
o.y += (familyFoci[o.id].y - o.y) * k;
o.x += (familyFoci[o.id].x - o.x) * k;
});
}
else {
nodes.forEach(function(o, i) {
o.y += (familiarityFoci[o.familiarity].y - o.y) * k;
o.x += (familiarityFoci[o.familiarity].x - o.x) * k;
});
}
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
我将数组焦点重命名为familyFoci,因为两个焦点都可以描述任一个数组,我还确保您的节点在下面的片段中具有熟悉属性
此修改允许我们轻松指定用于在一组焦点中设置特定焦点的属性,并指定我们想要的焦点集。
现在我们可以创建第二组焦点:
var familyFoci = [{x: 0, y: 150}, {x: 400, y: 150}, {x: 200, y: 150}];
var familiarityFoci = [{x:0,y:200},{x:100,y:100},{x:200,y:200},{x:300,y:100},{x:400,y:200}];
为了完整起见,我添加了一组基本按钮,这些按钮使用onclick功能来检查所需的焦点集是什么。
以下是快速摘录中的所有内容:
var data = [
{"id": 0, "name": "AngularJS", "familiarity":0,"r": 50 },
{"id": 0, "name": "HTML5", "familiarity":1,"r": 40 },
{"id": 0, "name": "Javascript", "familiarity":2,"r": 30 },
{"id": 1, "name": "Actionscript","familiarity":0, "r": 50 },
{"id": 1, "name": "Flash", "familiarity":4, "r": 32 },
{"id": 2, "name": "Node Webkit", "familiarity":3,"r": 40 },
{"id": 2, "name": "Chrome App", "familiarity":3,"r": 30 },
{"id": 2, "name": "Cordova", "familiarity":0,"r": 45 },
];
var width = window.innerWidth,
height = 450;
var fill = d3.scale.category10();
var nodes = [], labels = [];
// two sets of foci:
var familyFoci = [{x: 0, y: 150}, {x: 400, y: 150}, {x: 200, y: 150}];
var familiarityFoci = [{x:0,y:200},{x:100,y:100},{x:200,y:200},{x:300,y:100},{x:400,y:200}];
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", height)
var force = d3.layout.force()
.nodes(nodes)
.links([])
.charge(-200)
.gravity(0.1)
.friction(0.8)
.size([width, height])
.on("tick", tick);
//var node = svg.selectAll("circle");
var node = svg.selectAll("g");
var counter = 0;
//
// Create a basic interface:
//
var current = "family";
var buttons = svg.selectAll(null)
.data(["family","familiarity"])
.enter()
.append("g")
.attr("transform",function(d,i) { return "translate("+(i*120+50)+","+50+")"; })
.on("click", function(d) {
if(d != current) {
current = d;
}
})
.style("cursor","pointer")
buttons.append("rect")
.attr("width",100)
.attr("height",50)
.attr("fill","lightgrey")
buttons.append("text")
.text(function(d) { return d; })
.attr("dy", 30)
.attr("dx", 50)
.style("text-anchor","middle");
function tick(e) {
var k = .3 * e.alpha;
//
// Check to see what foci set we should gravitate to:
//
if(current == "family") {
// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
o.y += (familyFoci[o.id].y - o.y) * k;
o.x += (familyFoci[o.id].x - o.x) * k;
});
}
else {
nodes.forEach(function(o, i) {
o.y += (familiarityFoci[o.familiarity].y - o.y) * k;
o.x += (familiarityFoci[o.familiarity].x - o.x) * k;
});
}
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
var timer = setInterval(function(){
if (nodes.length > data.length-1) { clearInterval(timer); return;}
var item = data[counter];
nodes.push({id: item.id, r: item.r, name: item.name, familiarity: item.familiarity});
force.start();
node = node.data(nodes);
var n = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style('cursor', 'pointer')
.on('mousedown', function() {
var sel = d3.select(this);
sel.moveToFront();
})
.call(force.drag);
n.append("circle")
.attr("r", function(d) { return d.r/2; })
.style("fill", function(d) { return fill(d.id); })
n.append("text")
.text(function(d){
return d.name;
})
.style("font-size", function(d) {
return Math.min(2 * d.r, (2 * d.r - 8) / this.getComputedTextLength() * 16) + "px";
})
.attr("dy", ".35em")
counter++;
}, 100);
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
function resize() {
width = window.innerWidth;
force.size([width, height]);
force.start();
}
d3.select(window).on('resize', resize);
&#13;
circle {
stroke: #fff;
}
&#13;
<script src="https://d3js.org/d3.v3.min.js"></script>
&#13;
单击一个选项,如果它不是当前选定的焦点,则力会改变它正在使用的焦点。
但是,这里有一个问题,图表继续降温,因为你转移焦点直到它最终停止。当我们点击其中一个按钮时,我们可以稍微润滑一些轮子并用另外一行代码重置温度(alpha):
.on("click", function(d) {
if(d != current) {
current = d;
force.alpha(0.228); // reset the alpha
}
})
这是一个演示:
var data = [
{"id": 0, "name": "AngularJS", "familiarity":0,"r": 50 },
{"id": 0, "name": "HTML5", "familiarity":1,"r": 40 },
{"id": 0, "name": "Javascript", "familiarity":2,"r": 30 },
{"id": 1, "name": "Actionscript","familiarity":0, "r": 50 },
{"id": 1, "name": "Flash", "familiarity":4, "r": 32 },
{"id": 2, "name": "Node Webkit", "familiarity":3,"r": 40 },
{"id": 2, "name": "Chrome App", "familiarity":3,"r": 30 },
{"id": 2, "name": "Cordova", "familiarity":0,"r": 45 },
];
var width = window.innerWidth,
height = 450;
var fill = d3.scale.category10();
var nodes = [], labels = [];
// two sets of foci:
var familyFoci = [{x: 0, y: 150}, {x: 400, y: 150}, {x: 200, y: 150}];
var familiarityFoci = [{x:0,y:200},{x:100,y:100},{x:200,y:200},{x:300,y:100},{x:400,y:200}];
var svg = d3.select("body").append("svg")
.attr("width", "100%")
.attr("height", height)
var force = d3.layout.force()
.nodes(nodes)
.links([])
.charge(-200)
.gravity(0.1)
.friction(0.8)
.size([width, height])
.on("tick", tick);
var node = svg.selectAll("g");
var counter = 0;
//
// Create a basic interface:
//
var current = "family";
var buttons = svg.selectAll(null)
.data(["family","familiarity"])
.enter()
.append("g")
.attr("transform",function(d,i) { return "translate("+(i*120+50)+","+50+")"; })
.on("click", function(d) {
if(d != current) {
current = d;
force.alpha(0.228);
}
})
.style("cursor","pointer")
buttons.append("rect")
.attr("width",100)
.attr("height",50)
.attr("fill","lightgrey")
buttons.append("text")
.text(function(d) { return d; })
.attr("dy", 30)
.attr("dx", 50)
.style("text-anchor","middle");
function tick(e) {
var k = .3 * e.alpha;
//
// Check to see what foci set we should gravitate to:
//
if(current == "family") {
// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
o.y += (familyFoci[o.id].y - o.y) * k;
o.x += (familyFoci[o.id].x - o.x) * k;
});
}
else {
nodes.forEach(function(o, i) {
o.y += (familiarityFoci[o.familiarity].y - o.y) * k;
o.x += (familiarityFoci[o.familiarity].x - o.x) * k;
});
}
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}
var timer = setInterval(function(){
if (nodes.length > data.length-1) { clearInterval(timer); return;}
var item = data[counter];
nodes.push({id: item.id, r: item.r, name: item.name, familiarity: item.familiarity});
force.start();
node = node.data(nodes);
var n = node.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
.style('cursor', 'pointer')
.on('mousedown', function() {
var sel = d3.select(this);
sel.moveToFront();
})
.call(force.drag);
n.append("circle")
.attr("r", function(d) { return d.r/2; })
.style("fill", function(d) { return fill(d.id); })
n.append("text")
.text(function(d){
return d.name;
})
.style("font-size", function(d) {
return Math.min(2 * d.r, (2 * d.r - 8) / this.getComputedTextLength() * 16) + "px";
})
.attr("dy", ".35em")
counter++;
}, 100);
d3.selection.prototype.moveToFront = function() {
return this.each(function(){
this.parentNode.appendChild(this);
});
};
function resize() {
width = window.innerWidth;
force.size([width, height]);
force.start();
}
d3.select(window).on('resize', resize);
&#13;
circle {
stroke: #fff;
}
&#13;
<script src="https://d3js.org/d3.v3.min.js"></script>
&#13;