2016-12-10 113 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標籤佈局的即將特點。