Ответ 1
Поэтому, когда вы устанавливаете "размер" макета дерева, все, что вы делаете, - это значение, которое макет дерева будет интерполировать значения x и y. Поэтому нет причин, по которым вы не можете вычислить требуемую ширину или высоту и изменить их в макете при каждом вызове обновления.
Я скопировал пример, который вы передали jsFiddle, и добавил следующую функцию обновления:
// compute the new height
var levelWidth = [1];
var childCount = function(level, n) {
if(n.children && n.children.length > 0) {
if(levelWidth.length <= level + 1) levelWidth.push(0);
levelWidth[level+1] += n.children.length;
n.children.forEach(function(d) {
childCount(level + 1, d);
});
}
};
childCount(0, root);
var newHeight = d3.max(levelWidth) * 20; // 20 pixels per line
tree = tree.size([newHeight, w]);
Обратите внимание, что это довольно грубый расчет и не учитывает, где дети являются w.r.t их родителями или чем-то еще, но вы получаете идею.
Что касается манипулирования значениями x узлов, проще всего просто изменить узлы после того, как макет сделал это. Фактически вы можете видеть, что это уже сделано в примере с координатой y:
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
Он делает это так, что даже если дети скрыты, определенный уровень узлов остается в одной и той же позиции, иначе, если вы свернете все дети, оставшиеся уровни растянутся, чтобы охватить всю ширину (попробуйте прокомментировать эту строку и посмотрите, что произойдет, когда вы переключите целые уровни невидимым).
Что касается сверху вниз, я думаю, что вы можете просто перевернуть всюду, где увидите x и y (и x0 и y0). Не забудьте сделать то же самое с диагональной проекцией, чтобы убедиться, что ваши линии тоже переворачиваются.