D3:散点图上的标签布局

时间:2016-12-10 02:43:17

标签: javascript d3.js scatter-plot d3fc

我试图对散点图上的重叠标签做一些事情,就像图片中那样。

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

d3fc有什么问题吗?如果没有,是否有其他稳定的自动标签布局方法可用?

我正在使用贪婪策略:

  

贪婪策略是一种减少标签重叠的快速方法。它   按顺序添加每个标签,选择标签的位置   与已经添加的矩形重叠最低,并且在内部   容器

     

fc.layoutGreedy()

这是带有简化可重现代码的jsFiddle(虽然它没有加载d3fs lib) - https://jsfiddle.net/f5oxcyg7/

enter image description here

1 个答案:

答案 0 :(得分:1)

代码的问题在于每次呈现图表时都会重新评估布局策略。通常,首次渲染图表时的渲染时间约为100毫秒,但如果需要平滑的平移/缩放,则会出现问题。

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

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

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-label-layout的“头等舱”功能。