gpt4 book ai didi

javascript - 在版本 4 中动态添加节点到 D3 Force Layout

转载 作者:数据小太阳 更新时间:2023-10-29 05:25:07 26 4
gpt4 key购买 nike

我正在尝试实现一个简单的力布局,其中可以动态添加和删除节点(没有链接)。我成功地在 D3 版本 3 中实现了这个概念,但我无法将其转换为版本 4。添加和更新节点后,模拟卡住并且传入的圆圈绘制在 svg 的左上角。有人知道为什么会这样吗?感谢您的帮助:)

我的概念是基于这个解决方案: Adding new nodes to Force-directed layout

JSFiddle: working code in d3 v3

/* Define class */
class Planet {
constructor(selector) {
this.w = $(selector).innerWidth();
this.h = $(selector).innerHeight();

this.svg = d3.select(selector)
.append('svg')
.attr('width', this.w)
.attr('height', this.h);

this.force = d3.layout.force()
.gravity(0.05)
.charge(-100)
.size([this.w, this.h]);

this.nodes = this.force.nodes();
}

/* Methods (are called on object) */
update() {
/* Join selection to data array -> results in three new selections enter, update and exit */
const circles = this.svg.selectAll('circle')
.data(this.nodes, d => d.id); // arrow function, function(d) { return d.y;}

/* Add missing elements by calling append on enter selection */
circles.enter()
.append('circle')
.attr('r', 10)
.style('fill', 'steelblue')
.call(this.force.drag);

/* Remove surplus elements from exit selection */
circles.exit()
.remove();

this.force.on('tick', () => {
circles.attr('cx', d => d.x)
.attr('cy', d => d.y);
});

/* Restart the force layout */
this.force.start();
}

addThought(content) {
this.nodes.push({ id: content });
this.update();
}

findThoughtIndex(content) {
return this.nodes.findIndex(node => node.id === content);
}

removeThought(content) {
const index = this.findThoughtIndex(content);
if (index !== -1) {
this.nodes.splice(index, 1);
this.update();
}
}
}

/* Instantiate class planet with selector and initial data*/
const planet = new Planet('.planet');
planet.addThought('Hallo');
planet.addThought('Ballo');
planet.addThought('Yallo');

这是我将代码翻译成 v4 的意图:

/* Define class */
class Planet {
constructor(selector) {
this.w = $(selector).innerWidth();
this.h = $(selector).innerHeight();

this.svg = d3.select(selector)
.append('svg')
.attr('width', this.w)
.attr('height', this.h);

this.simulation = d3.forceSimulation()
.force('charge', d3.forceManyBody())
.force('center', d3.forceCenter(this.w / 2, this.h / 2));

this.nodes = this.simulation.nodes();
}

/* Methods (are called on object) */
update() {
/* Join selection to data array -> results in three new selections enter, update and exit */
let circles = this.svg.selectAll('circle')
.data(this.nodes, d => d.id); // arrow function, function(d) { return d.y;}

/* Add missing elements by calling append on enter selection */
const circlesEnter = circles.enter()
.append('circle')
.attr('r', 10)
.style('fill', 'steelblue');

circles = circlesEnter.merge(circles);

/* Remove surplus elements from exit selection */
circles.exit()
.remove();

this.simulation.on('tick', () => {
circles.attr('cx', d => d.x)
.attr('cy', d => d.y);
});

/* Assign nodes to simulation */
this.simulation.nodes(this.nodes);

/* Restart the force layout */
this.simulation.restart();
}

addThought(content) {
this.nodes.push({ id: content });
this.update();
}

findThoughtIndex(content) {
return this.nodes.findIndex(node => node.id === content);
}

removeThought(content) {
const index = this.findThoughtIndex(content);
if (index !== -1) {
this.nodes.splice(index, 1);
this.update();
}
}
}

最佳答案

see plunkr example

我使用的是 Canvas ,但原理是一样的:

在将它们添加到原始数组之前,您必须先将节点数组和指向 D3 核心函数的链接提供给它们。

drawData: function(graph){
var countExtent = d3.extent(graph.nodes,function(d){return d.connections}),
radiusScale = d3.scalePow().exponent(2).domain(countExtent).range(this.nodes.sizeRange);

// Let D3 figure out the forces
for(var i=0,ii=graph.nodes.length;i<ii;i++) {
var node = graph.nodes[i];

node.r = radiusScale(node.connections);
node.force = this.forceScale(node);
};

// Concat new and old data
this.graph.nodes = this.graph.nodes.concat(graph.nodes);
this.graph.links = this.graph.links.concat(graph.links);

// Feed to simulation
this.simulation
.nodes(this.graph.nodes);

this.simulation.force("link")
.links(this.graph.links);

this.simulation.alpha(0.3).restart();
}

然后,告诉 D3 使用新数据重新启动。

当 D3 调用您的 tick() 函数时,它已经知道您需要将什么坐标应用于 SVG 元素。

ticked: function(){
if(!this.graph) {
return false;
}

this.context.clearRect(0,0,this.width,this.height);
this.context.save();
this.context.translate(this.width / 2, this.height / 2);

this.context.beginPath();
this.graph.links.forEach((d)=>{
this.context.moveTo(d.source.x, d.source.y);
this.context.lineTo(d.target.x, d.target.y);
});
this.context.strokeStyle = this.lines.stroke.color;
this.context.lineWidth = this.lines.stroke.thickness;

this.context.stroke();

this.graph.nodes.forEach((d)=>{
this.context.beginPath();

this.context.moveTo(d.x + d.r, d.y);
this.context.arc(d.x, d.y, d.r, 0, 2 * Math.PI);

this.context.fillStyle = d.colour;
this.context.strokeStyle =this.nodes.stroke.color;
this.context.lineWidth = this.nodes.stroke.thickness;
this.context.fill();
this.context.stroke();
});

this.context.restore();
}

Plunkr example

关于javascript - 在版本 4 中动态添加节点到 D3 Force Layout,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39191683/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com