BaseTree
这类节点拥有树的结构,除了根以外每个节点拥有一个父节点。我们把每个节点的父节点称为其前驱,把每个节点的子节点称为其后继。
树上的每个节点被抽象为一个个 node,树上的每条连边被抽象为一条条 link。
这是一个抽象类,不应该被实例化。
API 列表
class BaseTree extends SD2DNode {
// 与 node 有关的查询
nodes(): Array<SDNode>;
nodesId(): Array<string>;
element(node: number | string | SDNode): SDNode | undefined;
root(): SDNode;
rootId(): string;
nodeId(node: number | string | SDNode): string | undefined;
// 与 link 有关的查询
links(): Array<SDNode>;
element(source: number | string | SDNode, target: number | string | SDNode): SDNode | undefined;
source(link: SDNode): SDNode | undefined;
target(link: SDNode): SDNode | undefined;
sourceId(link: SDNode): string | undefined;
targetId(link: SDNode): string | undefined;
// 筛查
findNode(condition: (node: SDNode, id: string) => boolean): SDNode | undefined;
findNodes(condition: (node: SDNode, id: string) => boolean): Array<SDNode>;
findLink(condition: (link: SDNode, sourceId: string, targetId: string) => boolean): SDNode | undefined;
findLinks(condition: (link: SDNode, sourceId: string, targetId: string) => boolean): Array<SDNode>;
findNodeById(id: number | string): SDNode | undefined;
findLinkById(sourceId: number | string, targetId: number | string): SDNode | undefined;
// 基础信息查询
inLink(node: number | string | SDNode): SDNode | undefined;
outLinks(node: number | string | SDNode): Array<SDNode>;
children(node: number | string | SDNode): Array<SDNode>;
father(node: number | string | SDNode): SDNode | undefined;
fatherId(node: number | string | SDNode): string | undefined;
depth(): number;
depth(node: number | string | SDNode): number;
ancestor(node: number | string | SDNode, kth: number): SDNode | undefined;
ancestorId(node: number | string | SDNode, kth: number): string;
// 高级信息查询
lca(x: number | string | SDNode, y: number | string | SDNode): SDNode;
lcaId(x: number | string | SDNode, y: number | string | SDNode): string;
nodesInSubtree(node: number | string | SDNode): Array<SDNode>;
linksInSubtree(node: number | string | SDNode): Array<SDNode>;
forEachNodeInSubtree(node: number | string | SDNode, callback: (node: SDNode, id: string) => void): this;
forEachLinkInSubtree(node: number | string | SDNode, callback: (link: SDNode, sourceId: string, targetId: string) => void): this;
nodesOnPath(source: number | string | SDNode, target: number | string | SDNode): Array<SDNode>;
linksOnPath(source: number | string | SDNode, target: number | string | SDNode): Array<SDNode>;
forEachNodeOnPath(source: number | string | SDNode, target: number | string | SDNode, callback: (node: SDNode, id: string) => void): this;
forEachLinkOnPath(source: number | string | SDNode, target: number | string | SDNode, callback: (link: SDNode, sourceId: string, targetId: string) => void): this;
forEachNode(callback: (node: SDNode, id: string) => void): this;
forEachLink(callback: (link: SDNode, sourceId: string, targetId: string) => void): this;
// 树的结构管理
root(id: number | string, value?: any): this;
link(sourceId: number | string, targetId: number | string, value?: any): this;
newNode(id: number | string, value?: any): this;
newNodeFromExistValue(id: number | string, value: SDNode): this;
newNodeFromExistElement(id: number | string, element: SDNode): this;
newLink(sourceId: number | string, targetId: number | string, value?: any): this;
newLinkFromExistValue(sourceId: number | string, targetId: number | string, value: SDNode): this;
newLinkFromExistElement(sourceId: number | string, targetId: number | string, element: SDNode): this;
cut(sourceId: number | string, targetId: number | string): this;
// 元素属性管理
opacity(node: number | string | SDNode): number;
opacity(node: number | string | SDNode, opacity: number): this;
nodeOpacity(node: number | string | SDNode): number;
nodeOpacity(node: number | string | SDNode, opacity: number): this;
opacity(source: number | string | SDNode, target: number | string | SDNode): number;
opacity(source: number | string | SDNode, target: number | string | SDNode, opacity: number): this;
linkOpacity(source: number | string | SDNode, target: number | string | SDNode): number;
linkOpacity(source: number | string | SDNode, target: number | string | SDNode): number;
color(color: SDColor): this;
color(node: number | string | SDNode): PacketColor;
color(node: number | string | SDNode, color: SDColor): this;
color(source: number | string | SDNode, target: number | string | SDNode): PacketColor;
color(source: number | string | SDNode, target: number | string | SDNode, color: SDColor): this;
text(node: number | string | SDNode): string;
text(node: number | string | SDNode, text: string): this;
nodeText(node: number | string | SDNode): string;
nodeText(node: number | string | SDNode, text: string): this;
text(source: number | string | SDNode, target: number | string | SDNode): string;
text(source: number | string | SDNode, target: number | string | SDNode, text: string): this;
linkText(source: number | string | SDNode, target: number | string | SDNode): string;
linkText(source: number | string | SDNode, target: number | string | SDNode, text: string): this;
intValue(node: number | string | SDNode): number;
intValue(source: number | string | SDNode, target: number | string | SDNode): number;
value(node: number | string | SDNode): SDNode | undefined;
value(node: number | string | SDNode, value: any): this;
nodeValue(node: number | string | SDNode): SDNode | undefined;
nodeValue(node: number | string | SDNode, value: any): this;
value(source: number | string | SDNode, target: number | string | SDNode): SDNode | undefined;
value(source: number | string | SDNode, target: number | string | SDNode, value: any): this;
linkValue(source: number | string | SDNode, target: number | string | SDNode): SDNode | undefined;
linkValue(source: number | string | SDNode, target: number | string | SDNode, value: any): this;
}
与 node 相关的查询
class BaseTree {
nodes(): Array<SDNode>; // 获取所有的节点
nodesId(): Array<string>; // 获取所有的节点索引
element(node: number | string | SDNode): SDNode | undefined; // 获取目标节点
root(): SDNode; // 获取树根节点
rootId(): string; // 获取树根索引
nodeId(node: number | string | SDNode): string | undefined; // 获取目标节点对应的索引
}
这类方法可以用来查询一些 node 信息。
与 link 相关的查询
class BaseTree {
links(): Array<SDNode>; // 获取所有的连边
element(source: number | string | SDNode, target: number | string | SDNode): SDNode | undefined; // 获取目标连边
source(link: SDNode): SDNode | undefined; // 获取目标连边的起点(即边上的父节点)
target(link: SDNode): SDNode | undefined; // 获取目标连边的终点(即边上的子节点)
sourceId(link: SDNode): string | undefined; // 获取目标连边的起点索引
targetId(link: SDNode): string | undefined; // 获取目标连边的终点索引
}
这类方法可以用来查询一些 link 信息。
筛查
class BaseTree {
findNode(condition: (node: SDNode, id: string) => boolean): SDNode | undefined; // 查找第一个符合条件的节点
findNodes(condition: (node: SDNode, id: string) => boolean): Array<SDNode>; // 查找所有符合条件的节点
findLink(condition: (link: SDNode, sourceId: string, targetId: string) => boolean): SDNode | undefined; // 查找第一条符合条件的连边
findLinks(condition: (link: SDNode, sourceId: string, targetId: string) => boolean): Array<SDNode>; // 查找所有符合条件的连边
findNodeById(id: number | string): SDNode | undefined; // 根据节点索引查找节点
findLinkById(sourceId: number | string, targetId: number | string): SDNode | undefined; // 根据连边索引查找连边
}
各种各样的筛选 node 和 link 的方法。
基础信息查询
class BaseTree {
inLink(node: number | string | SDNode): SDNode | undefined; // 获取目标节点的入边(即父节点指向其的连边)
outLinks(node: number | string | SDNode): Array<SDNode>; // 获取目标节点的出边(即其指向所有子节点的连边)
children(node: number | string | SDNode): Array<SDNode>; // 获取目标节点的所有子节点
father(node: number | string | SDNode): SDNode | undefined; // 获取目标节点的父节点
fatherId(node: number | string | SDNode): string | undefined; // 获取目标节点的父节点索引
depth(): number; // 获取树的深度(只有一个节点的树的深度为 1)
depth(node: number | string | SDNode): number; // 获取目标节点的深度
ancestor(node: number | string | SDNode, kth: number): SDNode | undefined; // 获取目标节点的 k 级祖先
ancestorId(node: number | string | SDNode, kth: number): string; // 获取目标节点的 k 级祖先的索引
}
包括深度信息,父节点信息,子节点信息,祖先信息。
高级信息查询
class BaseTree {
lca(x: number | string | SDNode, y: number | string | SDNode): SDNode; // 查询最近公共祖先
lcaId(x: number | string | SDNode, y: number | string | SDNode): string; // 查询最近公共祖先索引
nodesInSubtree(node: number | string | SDNode): Array<SDNode>; // 获取子树内所有节点
linksInSubtree(node: number | string | SDNode): Array<SDNode>; // 获取子树内所有连边
forEachNodeInSubtree(node: number | string | SDNode, callback: (node: SDNode, id: string) => void): this; // 遍历子树内所有节点
forEachLinkInSubtree(node: number | string | SDNode, callback: (link: SDNode, sourceId: string, targetId: string) => void): this; // 遍历子树内所有连边
nodesOnPath(source: number | string | SDNode, target: number | string | SDNode): Array<SDNode>; // 获取路径上所有节点(并按照路径顺序依次存放)
linksOnPath(source: number | string | SDNode, target: number | string | SDNode): Array<SDNode>; // 获取路径上所有连边(并按照路径顺序依次存放)
forEachNodeOnPath(source: number | string | SDNode, target: number | string | SDNode, callback: (node: SDNode, id: string) => void): this; // 遍历路径上所有节点(按照路径顺序依次遍历)
forEachLinkOnPath(source: number | string | SDNode, target: number | string | SDNode, callback: (link: SDNode, sourceId: string, targetId: string) => void): this; // 遍历路径上所有连边(按照路径顺序依次遍历)
forEachNode(callback: (node: SDNode, id: string) => void): this; // 遍历树上所有节点
forEachLink(callback: (link: SDNode, sourceId: string, targetId: string) => void): this; // 遍历树上所有连边
}
一些本来可能需要写一个函数完成的任务,在这里也进行了封装简化。
树的结构管理
class BaseTree {
root(id: number | string, value?: any): this; // 设置树根
link(sourceId: number | string, targetId: number | string, value?: any): this; // 连接两个节点
newNode(id: number | string, value?: any): this; // 新建一个节点
newNodeFromExistValue(id: number | string, value: SDNode): this; // 新建一个节点
newNodeFromExistElement(id: number | string, element: SDNode): this; // 新建一个节点
newLink(sourceId: number | string, targetId: number | string, value?: any): this; // 新建一条连边
newLinkFromExistValue(sourceId: number | string, targetId: number | string, value: SDNode): this; // 新建一条连边
newLinkFromExistElement(sourceId: number | string, targetId: number | string, element: SDNode): this; // 新建一条连边
cut(sourceId: number | string, targetId: number | string): this; // 删除一条连边
}
让我们试着构建一棵树:
const svg = sd.svg();
const tree1 = new sd.Tree(svg).root(1).link(1, 2).link(1, 3); // 可以先设置树根再连边
const tree2 = new sd.Tree(svg).link(1, 2).link(1, 3).dx(250); // 如果直接连边,则会自动推断树根
const tree3 = new sd.Tree(svg).newNode(1).newNode(2).newLink(1, 2).newNode(3).newLink(1, 3).dx(500); // 也可以先建立节点再连边
试一试,三棵树的构建都是正确的。link 和 newLink 的区别在于,对 link 而言,它会检查连边两端的节点是否存在,如果不存在则会自动创建,而 newLink 只完成连边的创建这一个任务。link 相比于 newLink 更加智能。
如果我们希望在创建节点的时候,每个节点上显示的不是其索引,而是别的什么东西,则可以这样做:
const svg = sd.svg();
const C = sd.color();
const tree = new sd.Tree(svg);
tree.newNode(1, new sd.Rect(svg).color(C.orange));
tree.newNode(2, new sd.Circle(svg).color(C.blue));
tree.newNode(3, new sd.Image(svg).href("/img/gift.png"));
tree.link(1, 2).link(1, 3);
同样,我们可以指定连边上显示一些额外信息:
const svg = sd.svg();
const tree = new sd.Tree(svg);
tree.link(1, 2, new sd.Image(svg).href("/img/gift.png").scale(0.5));
tree.newNode(3).newLink(1, 3, new sd.Image(svg).href("/img/snowflake.png").scale(0.5));
目前树的结构错误检测尚不智能,需要用户自行保证输入的树的结构是正确的。
元素属性管理
这里提供了一些方法,对节点和连边的各项属性进行快捷操作。
opacity
class BaseTree {
opacity(node: number | string | SDNode): number;
opacity(node: number | string | SDNode, opacity: number): this;
nodeOpacity(node: number | string | SDNode): number;
nodeOpacity(node: number | string | SDNode, opacity: number): this;
opacity(source: number | string | SDNode, target: number | string | SDNode): number;
opacity(source: number | string | SDNode, target: number | string | SDNode, opacity: number): this;
linkOpacity(source: number | string | SDNode, target: number | string | SDNode): number;
linkOpacity(source: number | string | SDNode, target: number | string | SDNode): number;
}
color
class BaseTree {
color(color: SDColor): this;
color(node: number | string | SDNode): PacketColor;
color(node: number | string | SDNode, color: SDColor): this;
color(source: number | string | SDNode, target: number | string | SDNode): PacketColor;
color(source: number | string | SDNode, target: number | string | SDNode, color: SDColor): this;
}
text
class BaseTree {
text(node: number | string | SDNode): string;
text(node: number | string | SDNode, text: string): this;
nodeText(node: number | string | SDNode): string;
nodeText(node: number | string | SDNode, text: string): this;
text(source: number | string | SDNode, target: number | string | SDNode): string;
text(source: number | string | SDNode, target: number | string | SDNode, text: string): this;
linkText(source: number | string | SDNode, target: number | string | SDNode): string;
linkText(source: number | string | SDNode, target: number | string | SDNode, text: string): this;
}
intValue
class BaseTree {
intValue(node: number | string | SDNode): number;
intValue(source: number | string | SDNode, target: number | string | SDNode): number;
}
value
class BaseTree {
value(node: number | string | SDNode): SDNode | undefined;
value(node: number | string | SDNode, value: any): this;
nodeValue(node: number | string | SDNode): SDNode | undefined;
nodeValue(node: number | string | SDNode, value: any): this;
value(source: number | string | SDNode, target: number | string | SDNode): SDNode | undefined;
value(source: number | string | SDNode, target: number | string | SDNode, value: any): this;
linkValue(source: number | string | SDNode, target: number | string | SDNode): SDNode | undefined;
linkValue(source: number | string | SDNode, target: number | string | SDNode, value: any): this;
}