Вертикальное разделение дерева D3

Я использую макет дерева D3, такой как этот: http://mbostock.github.com/d3/talk/20111018/tree.html

Я изменил его для своих нужд, и я столкнулся с проблемой. В примере также есть одна и та же проблема: если у вас слишком много узлов, то они становятся компактными и затрудняют чтение и взаимодействие. Я хочу определить минимальное вертикальное пространство между узлами, в то время как этап повторной калибровки позволяет такое расстояние.

Я попытался изменить алгоритм разделения, чтобы он работал:

.separation(function (a, b) {
    return (a.parent == b.parent ? 1 : 2) / a.depth;
})

Это не сработало. Я также попытался рассчитать, какая глубина имела большинство детей, а затем говорила, что высота сцены children * spaceBetweenNodes. Это приблизило меня, но все еще было неточно.

depthCounts = [];
nodes.forEach(function(d, i) { 
    d.y = d.depth * 180;

    if(!depthCounts[d.depth])
        depthCounts[d.depth] = 0;

    if(d.children)
    {
        depthCounts[d.depth] += d.children.length;
    }
});

tree_resize(largest_depth(depthCounts) * spaceBetweenNodes);

Я также попытался изменить значение node x в методе ниже, где он вычисляет разделение y, но не сигару. Я бы опубликовал это изменение, но я удалил его из своего кода.

nodes.forEach(function(d, i) { 
    d.y = d.depth * 180;
});

Если вы можете предложить способ или знать способ, которым я могу выполнить минимальное расстояние между узлами, отправьте сообщение. Я буду очень благодарен. Я, вероятно, пропустил что-то очень простое.

Ответ 1

С 2016 года я смог достичь этого, используя только

tree.nodeSize([height, width])

https://github.com/mbostock/d3/wiki/Tree-Layout#nodeSize

Ссылка на API немного бедна, но работает довольно прямо. Обязательно используйте его после tree.size([height, width]), иначе вы снова переопределите свои значения.

Подробнее: Разделение макета дерева D3 между узлами с помощью NodeSize

Ответ 2

Я смог понять это с помощью пользователя в Google Groups. Я не смог найти сообщение. Решение требует, чтобы вы изменяли D3.js в одном месте, что не рекомендуется, но это было единственное, что удалось обойти эту проблему, которую я мог найти.

Начиная с строки 5724 или этого метода: d3_layout_treeVisitAfter

изменения:

d3_layout_treeVisitAfter(root, function(node) {
    node.x = (node.x - x0) / (x1 - x0) * size[0];
    node.y = node.depth / y1 * size[1];
    delete node._tree;
});

в

d3_layout_treeVisitAfter(root, function(node) {
    // make sure size is null, we will make it null when we create the tree
    if(size === undefined || size == null) 
    { 
        node.x = (node.x - x0) * elementsize[0]; 
        node.y = node.depth * elementsize[1]; 
    } 
    else 
    { 
        node.x = (node.x - x0) / (x1 - x0) * size[0];
        node.y = node.depth / y1 * size[1]; 
    } 
    delete node._tree;
});

Ниже добавлена ​​новая переменная, называемая: elementsize, и по умолчанию она [ 1, 1 ] соответствует строке 5731

var hierarchy = d3.layout.hierarchy().sort(null).value(null)
    , separation = d3_layout_treeSeparation
    , elementsize = [ 1, 1 ] // Right here
    , size = [ 1, 1 ];

Ниже приведен метод tree.size = function(x). Добавьте нижеприведенное определение:

tree.elementsize = function(x) {
    if (!arguments.length) return elementsize;
    elementsize = x;
    return tree;
};

Наконец, когда вы создаете дерево, вы можете изменить elementsize так:

var tree = d3.layout.tree()
             .size(null)
             .elementsize(50, 240);

Ответ 3

Я знаю, что я не должен отвечать на другие ответы, но у меня недостаточно репутации, чтобы добавить комментарий.

В любом случае, я просто хотел обновить это для людей, использующих последний файл d3.v3.js. (Я предполагаю, что это из-за новой версии, потому что ссылки линии в принятом ответе были неправильными для меня.)

Функция d3.layout.tree, которую вы редактируете, находится между строками 6236 и 6345. d3_layout_treeVisitAfter запускается в строке 6318. Переменная иерархии объявляется в строке 6237. Бит о tree.elementsize все еще стоит - я надел его строка 6343.

Наконец (я предполагаю, что это была ошибка): когда вы создаете дерево, поместите размеры в квадратные скобки, как обычно, с "размером". Итак:

var tree = d3.layout.tree()
         .size(null)
         .elementsize([50, 240]);

Ответ 4

Исходное исправление, которое вы предложили, будет работать, вам просто нужно убедиться, что вы сделаете это после того, как вы добавите все на холст. d3 пересчитывает компоновку каждый раз, когда вы входите, выходите, добавляете и т.д. После того, как вы сделали все это, вы можете поиграть с d.y, чтобы исправить глубину.

nodes.forEach(function(d) { d.y = d.depth * fixdepth});