【问题标题】:Infinite zooming in force layout d3.js无限放大力布局d3.js
【发布时间】:2014-12-15 13:59:43
【问题描述】:

an example,我们可以在其中单击一个圆圈并查看内圈。
也有不同的力布局示例。

是否有可能有一个力布局,它的每个节点将/可以是一个具有内力布局的圆圈?
因此,它将作为这些圆圈的无限缩放(带有额外的数据加载)。

欢迎任何想法/示例。

【问题讨论】:

  • 是的,这是可能的。您需要结合力量和包装布局。 This tutorial 不完全是,但可能会有所帮助。
  • + 200 赏金!任何人? 哭了……
  • 对我来说,这看起来是一个相当大的项目,需要几天时间才能完成——更多的事情你会雇人来做......
  • 这对我来说似乎非常清楚:) 你不能指望他回答所有问题。需要明确的是,我对如何去做有一个相当好的想法,只是我认为这不会很快。
  • 再次感谢@LarsKotthoff。当您或其他人发布答案时,将分配 [额外] 赏金 :) 这不是超级紧急,但是...

标签: javascript d3.js force-layout


【解决方案1】:

我会这样解决问题:构建一个强制导向的布局,从其中一个教程开始(可能是this one,因为它构建了一些使用循环填充进行初始化的东西)。添加 D3 的缩放行为。

var force = d3.layout.force()
// force layout settings

var zoom = d3.behavior.zoom()
// etc.

到目前为止,一切都很好。除了力布局喜欢在[width/2, height/2] 周围闲逛,但如果你以[0, 0] 为中心,它会使缩放更容易。与geometric zooming 斗争一会儿,直到你意识到这个问题确实需要semantic zooming。实现语义缩放。去喝杯咖啡吧。

找出圆圈大小与缩放级别之间的关系,以便您判断何时需要发现下一个级别。像这样的:

// expand when this percent of the screen is covered
var coverageThreshold = 0.6;
// the circles should be scaled to this size
var maxRadius = 20;
// the size of the visualization
var width = 960;
// which means this is the magic scale factor
var scaleThreshold = maxRadius / (coverageThreshold * width)
// note: the above is probably wrong

现在,实现空间数据过滤器。当你缩小时,你基本上想要隐藏任何已经缩小到视野之外的数据点,这样你就不会浪费 gpu 时间来计算它们的表示。此外,找出一种算法来确定用户正在放大哪个节点。这很可能使用Voronoi tessalation。了解比您想象的更多的几何知识。

我们还需要解决一个数学问题。我们将让子节点代替父节点,因此我们需要根据父节点的总大小来缩放它们的大小。这会很烦人,需要一些调整才能正确,除非你知道正确的算法......我不知道。

// size of the parent node
var parentRadius = someNumberPossiblyCalculated;
// area of the parent node
var parentArea = 2 * Math.PI * parentRadius;
// percent of the the parent's area that will be covered by children
//   (here be dragons)
var childrenCoverageRatio = 0.8;
// total area covered by children
var childrenArea = parentArea * childrenCoverageArea;
// the total of the radiuses of the children
var childTotal = parent.children
    .map(radiusFn)
    .reduce(function(a, b) { return a + b; });

// the child radius function
//   use this to generate the child elements with d3
//   (optimize that divide in production!)
var childRadius = function(d) {
    return maxRadius * radiusFn(d) / childTotal;
};
// note: the above is probably wrong

好的,现在我们已经准备好制作魔法酱的部分了。在zoom 处理程序中,对照您的参考点检查d3.event.scale。如果用户已放大过去,请快速执行以下步骤:

  • 隐藏屏幕外的父元素
  • 移除被放大的父节点
  • 将该父节点的子节点添加到父节点的 x 和 y 位置的布局中
  • 明确运行 force.tick() 几次,让孩子们稍微分开
  • 可能使用循环包装布局来使此过程更清洁

好的,现在我们有了一个不错的带有缩放功能的小力布局。当您放大时,您将达到某个阈值,希望由可视化代码自动计算。当您这样做时,您正在放大的节点“爆炸”成它的所有组成节点。

现在弄清楚如何构建您的代码,以便您可以“重置”事物,让您继续放大并让它再次发生。这可能是递归的,但将比例缩小几个数量级并同时将 SVG 元素扩展成反比可能会更简洁。

现在缩小。首先,您需要为反向过程设置一个明显的缩放阈值,即控件中的滞后效应,这将有助于防止在有人骑着鼠标滚轮时出现跳跃的可视化。你放大它会扩大,然后你必须再缩小一点,然后它会再次收缩。

好的,当您达到缩小阈值时,您只需放下子元素并将父元素添加回子元素位置的质心。

var parent.x = d3.mean(parent.children, function(d) { return d.x; });
var parent.y = d3.mean(parent.children, function(d) { return d.y; });

此外,当您缩小时,开始显示您在放大时隐藏的那些节点。

正如@Lars 所说,这可能需要一点时间。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2013-08-14
    • 2013-06-25
    相关资源
    最近更新 更多