2016-12-10 15 views
0

散布図のような重なり合ったラベルについて何かしようとしています。D3:散布図のラベルレイアウト

私はd3fcを使用していますが、ラベルを配置するのは本当にうまく機能しますが、小さなポイント(> 100)でも遅くなりますが、実際の要件は通常> 1000ポイントです。チャートを最初に作成するには時間がかかり、ズーム/パディングはほとんど不可能です。

私はd3fcに間違っていますか?そうでない場合は、自動ラベルレイアウトのための他の安定したアプローチがありますか?

私は貪欲な戦略を使用しています:

貪欲な戦略は、ラベルの重複を削減する非常に高速な方法です。 は、ラベル がすでに追加されている矩形と最も重複している位置を選択し、 コンテナの内側にある各ラベルを順番に追加します。ここで

fc.layoutGreedy()

jsFiddleは簡略化され、再現コード(それはlibにd3fsロードされませんが)である - あなたのコードの問題は、そのレイアウトであるhttps://jsfiddle.net/f5oxcyg7/

enter image description here

+0

あなたの問題を示すより完全で実行可能な例を提供できますか? – ColinE

+0

こんにちは@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ラベルレイアウトのこの「最初のクラスの機能を作るために見ていきます。