今天在做网络图(d3.layout.force())遇到这个3个问题:
- zomm的drag事件与force.drag发生冲突。由于我的SVG布置是这样的:
<svg>
<g class="gNet">
<rect fill="transparent"></rect>
<g transform="scale(0.5)translate(170,211)">
<path d="" >
<g class="node">
<circle>
<text>
</g>
</g>
</g>
</svg>
g.gNet
设有一个zoom
行为控制其下属g
的transform
特性以达到拖拽和缩放效果。
因此我在每个g.node
节点上均设有force.drag,但是在dragstart
状态时使用了d3.event.sourceEvent.stopPropagation()
,使得这个drag事件不会上升到g.gNet
,这样避免了当拉拽网络节点时也拽动整个图形。
.call(force.drag().on("dragstart", function(){
d3.event.sourceEvent.stopPropagation();
}))
- 在设置zoom效果时,图形在平移拽动时出现抖动现象。最终在 stackoverflow 找到问题原因:
var zoom = d3.behavior.zoom()
.on("zoom", function(){
d3.select(this)
.attr(
"transform", "scale(" +
d3.event.scale + ")translate(" +
d3.event.translate + ")"
);
});
selection.call(zoom)
问题在于鼠标在拖拽是总是查找鼠标相对于当前点击的对象的父对象的相对坐标(我的这个示例即为查找相对于g.gNet
的坐标, rect
是透明的就是为了可以点击),而我每次修改的都是g.gNet
的transform特性导致了跳动显现。解决思路是将修改对象改为其底下的g
元素:
var zoom = d3.behavior.zoom()
.on("zoom", function(){
d3.select(this)
.select("g") // add line
.attr(
"transform", "scale(" +
d3.event.scale + ")translate(" +
d3.event.translate + ")"
);
});
通常的force layout图形(network)会有links和nodes参数设置,但是这里有一个问题是:如果这两个值同时存在,node之间用link连线绑着产生了相互间的力道,这样的图形最终呈现出来不能够完全均布在一个圆圈内。而我这次的任务是需要所有的node在一个圈圈内。我的做法是不传入link值,而是传入nodes值后启动force layout,再通过force.nodes()获取新的带有坐标值的所有node。之所以这样行得通是因为link获取的node值都指向同一个对象值。
// Extract data and update force layout force .size([netWidth, netHeight]) .nodes(opt.nodes.map(function(d){ return { label : d.label, category: d.category, r : radiusScale(d.size), fill : opt.monoColor ? opt.monoColor : opt.categoryColor[d.category] }; })) .start(); // This is the interesting part newLinks = opt.links.map(function(d){ return { source : force.nodes()[d.source], target : force.nodes()[d.target], stroke : d.strokeWidth > 0 ? "red" : "green", "stroke-width": strokeScale(Math.abs(d.strokeWidth)) }; });