进入-更新-退出模式后节点的 x 和 y 属性丢失
x and y attributes of nodes lost after enter-update-exit pattern
我正在尝试在 D3v4 中转换力模拟的节点。使用鲨鱼家族聚合的节点正确绘制了原始力,我想单击 "Greenland shark" 按钮,因此只有名称为 'greenland shark' 的节点可见(这是有效的),并且我希望如果用户点击 "sharks by family" 按钮,力会回到原来的位置。但是,如果我在单击 "Greenland shark" 之后单击 "sharks by family",则只有两个节点可见,因为除了直接从 greenland shark 节点更新的节点外,其余节点没有 cx 和 cy所以它们都在默认位置 0,0 处相互堆叠。我不确定为什么 cx 和 cy 属性丢失,这可能是我的输入、更新、退出模式中的错误吗?
下面是相关代码,这里是可视化 + 代码的 Plunker link
https://plnkr.co/edit/rvbOJT2fIgxBlsqOtXR4
仅可视化
https://run.plnkr.co/plunks/rvbOJT2fIgxBlsqOtXR4/
// Original force simulation by family
var simulation = d3.forceSimulation();
simulation.force('x', d3.forceX(function(d) {
var i = mapIndex(d.family);
return xposition(i)
}).strength(0.03))
.force('y', d3.forceY(function(d) {
var i = mapIndex(d.family);
return yposition(i)
}).strength((0.03)))
.force('collide', d3.forceCollide(function(d) {
return radiusScale(+d.size)
})).velocityDecay(0.1).alphaDecay(0.001);
var circles = g.selectAll(".sharks")
.data(nodes)
.enter().append("circle")
.attr("class", "sharks")
.attr("r", function(d) {
return radiusScale(+d.size)
})
.attr("fill", function(d) {
return colorScale(d.family)
})
.attr('stroke', '')
simulation.nodes(nodes)
.on('tick', ticked);
nodes.forEach(function(d) {
d.x = familyXScale(d.family)
d.y = yPositionScale(sharks.indexOf(d.name))
})
function ticked() {
circles
.attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
})
}
function charge(d) {
return -Math.pow(d.radius, 2.0) * forceStrength;
}
// function for only showing one node (greenland shark)
function greenlandShark() {
console.log('greenlandShark');
console.log(nodes);
var newNodes = filterNodes('common_name', 'Greenland shark');
circles = g.selectAll(".sharks").data(newNodes);
circles.exit()
.transition()
.duration(1000)
.attr("r", 0)
.remove();
circles
.attr('r', function(d) {
return radiusScale(+d.size)
})
.attr('fill', function(d) {
return colorScale(d.family)
});
simulation.nodes(newNodes)
.on('tick', ticked);
simulation.force('x', d3.forceX().strength(0.03).x(center.x))
.force('y', d3.forceY(function(d) {
return height / 2
}).strength((0.03)));
simulation.alpha(1).restart();
}
function filterNodes(key, group) {
var newnodes = nodes.filter(function(d) {
return d[key] == group;
});
return newnodes;;
}
// function for visualizing all nodes again organized by family
function sharksByFamily() {
circles = g.selectAll(".sharks").data(nodes);
circles.exit().transition().duration(750)
.attr("r", 0)
.remove();
circles.transition().duration(750)
.attr("fill", function(d) {
return colorScale(d.family)
}).attr("r", function(d) {
return radiusScale(+d.size);
})
circles.enter().append("circle").attr("class", "sharks")
.attr("fill", function(d) {
return colorScale(d.family)
}).attr("r", function(d) {
return radiusScale(+d.size);
})
.attr('stroke', '')
simulation.force('x', d3.forceX(function(d) {
var i = mapIndex(d.family);
return xposition(i)
}).strength(0.03))
.force('y', d3.forceY(function(d) {
var i = mapIndex(d.family);
return yposition(i)
}).strength((0.03)))
.force('collide', d3.forceCollide(function(d) {
return radiusScale(+d.size)
})).velocityDecay(0.1).alphaDecay(0.001);
// cx cy not showing up for nodes
simulation.nodes(nodes)
.on('tick', ticked);
simulation.alpha(1).restart();
}
属性在那里,那不是问题。问题只是 ticked
函数中 circles
的定义。
例如,如果您这样做:
function ticked() {
g.selectAll("circle").attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
})
};
它会起作用的。这是你的分叉插件:https://plnkr.co/edit/szhg8eUYQUMxHcLmBF8N?p=preview
但是,这里惯用的解决方案是合并 sharksByFamilyRev
函数内的选择:
circles = circles.enter().append("circle").attr("class", "sharks")
.attr("fill", function(d) {
return colorScale(d.family)
}).attr("r", function(d) {
return radiusScale(+d.size);
})
.attr('stroke', '')
.merge(circles);
这是进行了更改的 plunker:https://plnkr.co/edit/pBPJUhEKQIPnB0ammGDd?p=preview
PS:您在该代码中还有其他问题,这些问题与当前问题无关(例如混合 jQuery 和 D3,重复代码等...)。
我正在尝试在 D3v4 中转换力模拟的节点。使用鲨鱼家族聚合的节点正确绘制了原始力,我想单击 "Greenland shark" 按钮,因此只有名称为 'greenland shark' 的节点可见(这是有效的),并且我希望如果用户点击 "sharks by family" 按钮,力会回到原来的位置。但是,如果我在单击 "Greenland shark" 之后单击 "sharks by family",则只有两个节点可见,因为除了直接从 greenland shark 节点更新的节点外,其余节点没有 cx 和 cy所以它们都在默认位置 0,0 处相互堆叠。我不确定为什么 cx 和 cy 属性丢失,这可能是我的输入、更新、退出模式中的错误吗?
下面是相关代码,这里是可视化 + 代码的 Plunker link https://plnkr.co/edit/rvbOJT2fIgxBlsqOtXR4 仅可视化 https://run.plnkr.co/plunks/rvbOJT2fIgxBlsqOtXR4/
// Original force simulation by family
var simulation = d3.forceSimulation();
simulation.force('x', d3.forceX(function(d) {
var i = mapIndex(d.family);
return xposition(i)
}).strength(0.03))
.force('y', d3.forceY(function(d) {
var i = mapIndex(d.family);
return yposition(i)
}).strength((0.03)))
.force('collide', d3.forceCollide(function(d) {
return radiusScale(+d.size)
})).velocityDecay(0.1).alphaDecay(0.001);
var circles = g.selectAll(".sharks")
.data(nodes)
.enter().append("circle")
.attr("class", "sharks")
.attr("r", function(d) {
return radiusScale(+d.size)
})
.attr("fill", function(d) {
return colorScale(d.family)
})
.attr('stroke', '')
simulation.nodes(nodes)
.on('tick', ticked);
nodes.forEach(function(d) {
d.x = familyXScale(d.family)
d.y = yPositionScale(sharks.indexOf(d.name))
})
function ticked() {
circles
.attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
})
}
function charge(d) {
return -Math.pow(d.radius, 2.0) * forceStrength;
}
// function for only showing one node (greenland shark)
function greenlandShark() {
console.log('greenlandShark');
console.log(nodes);
var newNodes = filterNodes('common_name', 'Greenland shark');
circles = g.selectAll(".sharks").data(newNodes);
circles.exit()
.transition()
.duration(1000)
.attr("r", 0)
.remove();
circles
.attr('r', function(d) {
return radiusScale(+d.size)
})
.attr('fill', function(d) {
return colorScale(d.family)
});
simulation.nodes(newNodes)
.on('tick', ticked);
simulation.force('x', d3.forceX().strength(0.03).x(center.x))
.force('y', d3.forceY(function(d) {
return height / 2
}).strength((0.03)));
simulation.alpha(1).restart();
}
function filterNodes(key, group) {
var newnodes = nodes.filter(function(d) {
return d[key] == group;
});
return newnodes;;
}
// function for visualizing all nodes again organized by family
function sharksByFamily() {
circles = g.selectAll(".sharks").data(nodes);
circles.exit().transition().duration(750)
.attr("r", 0)
.remove();
circles.transition().duration(750)
.attr("fill", function(d) {
return colorScale(d.family)
}).attr("r", function(d) {
return radiusScale(+d.size);
})
circles.enter().append("circle").attr("class", "sharks")
.attr("fill", function(d) {
return colorScale(d.family)
}).attr("r", function(d) {
return radiusScale(+d.size);
})
.attr('stroke', '')
simulation.force('x', d3.forceX(function(d) {
var i = mapIndex(d.family);
return xposition(i)
}).strength(0.03))
.force('y', d3.forceY(function(d) {
var i = mapIndex(d.family);
return yposition(i)
}).strength((0.03)))
.force('collide', d3.forceCollide(function(d) {
return radiusScale(+d.size)
})).velocityDecay(0.1).alphaDecay(0.001);
// cx cy not showing up for nodes
simulation.nodes(nodes)
.on('tick', ticked);
simulation.alpha(1).restart();
}
属性在那里,那不是问题。问题只是 ticked
函数中 circles
的定义。
例如,如果您这样做:
function ticked() {
g.selectAll("circle").attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
})
};
它会起作用的。这是你的分叉插件:https://plnkr.co/edit/szhg8eUYQUMxHcLmBF8N?p=preview
但是,这里惯用的解决方案是合并 sharksByFamilyRev
函数内的选择:
circles = circles.enter().append("circle").attr("class", "sharks")
.attr("fill", function(d) {
return colorScale(d.family)
}).attr("r", function(d) {
return radiusScale(+d.size);
})
.attr('stroke', '')
.merge(circles);
这是进行了更改的 plunker:https://plnkr.co/edit/pBPJUhEKQIPnB0ammGDd?p=preview
PS:您在该代码中还有其他问题,这些问题与当前问题无关(例如混合 jQuery 和 D3,重复代码等...)。