https://github.com/thu-vis/MutualDetector
Tip revision: c1059af41f4a6627cec3b5094096e6635f57673c authored by unknown on 11 January 2022, 04:44:40 UTC
remove video
remove video
Tip revision: c1059af
layout_text.js
import * as d3 from "d3"
import {TreeCut} from "./treecut"
const exit_type = function(d){
let p = d;
let child_p = null;
// 0: collapsing to parent
// 1: stay till
// 2: collapsing to beforelist
// 3: collapsing to afterlist
let type = -1;
let translate = "";
while(p.parent && p.parent.children.indexOf(p) < 0){
child_p = p;
p = p.parent;
}
if (p.children.length === 0){
type = 0;
translate = "translate(" + p.prev_x + ", " + p.prev_y + ")";
}
else if (child_p && p.children.length !== 0){
if (child_p.in_before_list){
type = 2;
translate = "translate(" + p.before_node.x + ", " + p.before_node.y + ")";
}
else if (child_p.in_after_list){
type = 3;
translate = "translate(" + p.after_node.x +
", " + p.after_node.y + ")";
}
}
else{
type = 1;
translate = "translate(" + p.prev_x + ", " + p.prev_y + ")";
}
return [type, translate]
}
const mini_tree_layout = function(Size){
let that = this;
that.Size = Size;
this.layout = function(data){
// backup state
data.all_descendants.forEach(d => {
d.backup_children = d.children;
d.children = d.all_children;
if (d.children && d.children.length === 0) d.children = undefined;
d.backup_x = d.x;
d.backup_y = d.y;
});
// tree layout
data = d3.tree()
.size(that.Size)(data);
let nodes = data.descendants();
let links = data.links();
// restore state
data.descendants().forEach(d => {
d.mini_x = d.x;
d.mini_y = d.y;
d.x = d.backup_x;
d.y = d.backup_y;
d.children = d.backup_children;
d.mini_selected = false;
});
// set selected state
data.descendants().forEach(d => d.mini_selected = true);
return {nodes, links};
};
};
const tree_layout = function(nodeSize, layout_height){
let that = this;
that.nodeSize = nodeSize;
that.x_delta = nodeSize[0];
that.y_delta = nodeSize[1];
that.layout_height = layout_height;
that.max_num = parseInt(that.layout_height / that.y_delta);
this.layout = function(data, expand_tree){
if (expand_tree === false){
return that._aligned_layout(data);
}
else{
return that._layout(data);
}
};
this.update_layout_by_num = function(num){
if (num < that.max_num){
that.y_delta = that.layout_height / num;
}
else{
that.y_delta = that.nodeSize[1];
}
};
this.reset_layout = function(){
that.y_delta = that.nodeSize[1];
};
this.layout_with_nodes = function(data, expand_tree){
if (expand_tree === false){
return that._aligned_layout(data);
}
else{
// const root = that._layout(data);
return that._layout(data).filter(d => !d.is_rest_node);
}
};
this.layout_with_rest_node = function(data, expand_tree){
if (expand_tree === false){
return that._aligned_layout(data);
}
else{
// const root = that._layout(data);
return that._layout(data);
}
}
this._aligned_layout = function(data){
data.descendants().forEach(d => {
if (!d.children) d.children = [];
});
let nodes = data.descendants().filter(d => d.children.length === 0);
// let y_delta = that.y_delta * (data.descendants().length - 1) / nodes.length;
let y_delta = that.layout_height / (nodes.length);
console.log("y_delta in aligned_layout", y_delta);
let layer = 0;
data.eachBefore(d => {
if (d.children.length === 0){
d.y = layer * y_delta;
layer += 1;
}
})
nodes.forEach((d) => {
d.x = 0;
d.link_x = 0;
d.link_top = that.y_delta / 2;
d.link_bottom = d.link_top;
});
return nodes;
}
this._layout = function(data){
data.all_descendants.forEach(d => {
d.is_rest_node = false;
d.in_before_list = false;
d.in_after_list = false;
});
let visible_nodes = data.descendants();
visible_nodes.forEach(d => {
d.tmp_children = d.children.slice();
if (d.beforeList.length > 0){
d.beforeList.forEach(n => n.in_before_list = true);
let rest_node = {};
rest_node.id = "rest-before-" + d.id;
rest_node.is_rest_node = true;
rest_node.rest_children = d.beforeList;
rest_node.parent = d;
rest_node.depth = d.depth + 1;
rest_node.data = {};
rest_node.data.precision = 1;
rest_node.data.recall = 1;
rest_node.siblings_id = -1;
rest_node.prev_vis = false;
d.beforeList.forEach(n => {
if (n.prev_vis) rest_node.prev_vis=true;
})
d.children.push(rest_node);
d.before_node = rest_node;
}
if (d.afterList.length > 0){
d.afterList.forEach(n => n.in_after_list = true);
let rest_node = {};
rest_node.id = "rest-after-" + d.id;
rest_node.is_rest_node = true;
rest_node.rest_children = d.afterList;
rest_node.parent = d;
rest_node.depth = d.depth + 1;
rest_node.data = {};
rest_node.data.precision = 1;
rest_node.data.recall = 1;
rest_node.siblings_id = 1000;
rest_node.prev_vis = false;
d.afterList.forEach(n => {
if (n.prev_vis) rest_node.prev_vis=true;
})
d.children.push(rest_node);
d.after_node = rest_node;
}
d.children.sort(function(a,b){return a.siblings_id - b.siblings_id;})
});
data.eachBefore((d,i) => {
d.x = (d.depth - 1) * that.x_delta;
d.y = (i - 1) * that.y_delta;
});
data.descendants().forEach(d => {
if (!d.children) d.children = [];
// if (d.parent){
// d.parent_x = d.parent.x;
// d.parent_y = d.parent.y;
// }
})
// calculate node link
data.descendants().forEach(d => {
d.link_x = 0;
d.link_top = that.y_delta / 2;
if (d.children && d.children.length > 0){
d.link_bottom = d.link_top + (d.descendants().length - 1) * that.y_delta;
}
else{
d.link_bottom = d.link_top;
}
})
// calculate node type
data.descendants().forEach(d => {
let type = -1;
if (!d.all_children || d.all_children.length===0){
type = 2;
}
else{
if (!d.children || d.children.length===0){
type = 0;
}
else{
type = 1;
}
}
d.type = type;
});
let nodes = data.descendants().filter(d => d.name !== "root");
nodes.filter(d => d.is_rest_node).forEach(d => {
d.rest_children.forEach(n => {n.x = d.x; n.y = d.y;})
d.rest_children = d.rest_children.slice(0, 3); // show max 3 rest children
let children_num = d.rest_children.length;
let single_height = that.y_delta * 0.6;
let max_delta = that.y_delta * 0.2;
let total_height = single_height + max_delta * (children_num - 1);
if (total_height > that.y_delta * 0.8){
let delta = (this.y_delta * 0.8 - single_height) / (children_num - 1);
d.rest_children.forEach((e,i) => {
e.x_delta = i * 4;
e.y_delta = - that.y_delta * 0.8 / 2 + i * delta;
e.is_rest_node = true;
})
}
else{
d.rest_children.forEach((e,i) =>{
e.x_delta = i * 4;
e.y_delta = i * max_delta - total_height / 2;
})
}
d.rest_children.forEach((e,i) => {
e.last_rest_children = i === (d.rest_children.length - 1);
})
})
visible_nodes.forEach(d => {d.children = d.tmp_children});
return nodes;
}
}
export {TreeCut, tree_layout, mini_tree_layout, exit_type}