2016-12-10 114 views
0

我正在尝试在散点图上重叠标签,如图片中的标签。D3:散点图上的标签布局

我使用d3fc,它确实很好地定位标签,但是即使点数少(> 100)也很慢,但实际要求通常> 1000点。建立图表需要很长时间,缩放/填充几乎是不可能的。

有没有什么我做错了d3fc?如果没有,有没有其他稳定的方法可用于自动标签布局?

我用贪婪策略:

贪心的策略是减少标签重叠的非常快速的方式。它 按顺序添加每个标签,选择标签 与已添加的矩形重叠最低的位置,并位于 容器内。

fc.layoutGreedy()

这里是简化重复性代码的jsfiddle(虽然它不会加载d3fs LIB) - https://jsfiddle.net/f5oxcyg7/

enter image description here

+0

你能提供一个更完整和可运行的例子来展示你的问题吗? – ColinE

+0

Hi @ColinE - 我无法发布实际的代码,因为它嵌入到一个更大的Sencha ExtJS UI系统中,但我试图展示代码的简化版本以显示我如何使用d3fs。感谢您的帮助! –

+0

我认为这需要一些工作来解决 - 布局计算大约需要100ms,这总是会让你的变焦变得“跳跃”。我在这里提出了一个问题(https://github.com/d3fc/d3fc-label-layout/issues/24),并会尝试找到一个体面的解决方案。 – ColinE

回答

1

与您的代码的问题是,布局战略正在重新评估每次图表呈现。通常情况下,当第一次渲染图表时,渲染时间为〜100ms并不成问题,但如果您需要平滑的平移/缩放,则会成为问题。

我想出的解决方案是'缓存'布局的结果,以便在图表放大时不重新评估。但是,缩放操作完成后,将重新评估布局以消除冲突。

首先,缩放事件的处理以开启缓存行为/关:

var returnCachedLayout = false; 
var zoomBeh = d3.behavior.zoom() 
    .x(x) 
    .y(y) 
    .scaleExtent([0, 500]) 
    .on("zoomstart", function() { 
     returnCachedLayout = true; 
     zoom() 
    }) 
    .on("zoom", zoom) 
    .on("zoomend", function() { 
     returnCachedLayout = false; 
     zoom() 
    }) 

则该策略适用于使用缓存:

var strategyCache = function (strategy) { 
    var cachedLayout; 

    var cache = function(layout) { 
    if (!returnCachedLayout) { 
     cachedLayout = strategy(layout); 
     // determine the offset applied by the layout 
     for (var i = 0; i< layout.length; i++) { 
     cachedLayout[i].dx = layout[i].x - cachedLayout[i].x; 
     cachedLayout[i].dy = layout[i].y - cachedLayout[i].y; 
     } 
    } else { 
     // update the location of each label, including the offset 
     for (var i = 0; i< layout.length; i++) { 
     cachedLayout[i].x = layout[i].x - cachedLayout[i].dx; 
     cachedLayout[i].y = layout[i].y - cachedLayout[i].dy; 
     } 
    } 
    return cachedLayout; 
    }; 
    return cache; 
}; 

// construct a strategy that uses the "greedy" algorithm for layout, wrapped 
// by a strategy that removes overlapping rectangles. 
var strategy = strategyCache(fc.layout.strategy.removeOverlaps(fc.layout.strategy.greedy())); 

这是一个有点棘手因为您不能仅仅从缓存中重新渲染标签,因为缩放行为会导致这些点移动。这就是偏移量也被存储起来的原因,因此它可以被重新应用到新位置的标签上。

无论如何,这里有一个完整的例子:

https://jsfiddle.net/qrpr0wre/

我会寻找让这个“第一类” d3fc标签布局的即将特点。