介绍
本文介绍了一个JavaScript组件,它使用Internet Explorer 6+中的(矢量标记语言)或Firefox 1.5+中的元素在屏幕上呈现树。 VML
有很多的JavaScript树,其中大多数具有更好的跨浏览器兼容性,更快,更好的优化。此代码的目标是展示Walker布局算法的客户端实现(请参阅参考资料),不再需要代码优化。简而言之,这个组件是在算法之后诞生的,因为我认为一个活的样本比一个抽象的源代码级的实现更好。
我使用的一个经典的treeview JavaScript组件有时是GeirLandrö的DTree:杰出和简单。前段时间,一篇文章出现在这里在CodeProject呈现水平的JavaScript树,基于DTREE,它使用HTML表格来呈现树以水平方式。我想在这里提及他们,因为他们激励我发表这篇文章。而且,这个版本的许多功能模仿了这些脚本。
我希望这个组件能够在需要树形布局时填补项目的空白,但是没有服务器端的代码。当然,任何意见,更正,建议等都是非常受欢迎的。
特征
了解使用这个组件可以完成什么的最好方法是下载源代码并使用包含的示例进行播放。下面的API参考可以给你一个更确切的想法,可以做些什么。但是,作为一个简报,功能包括:
- 节点可以是任何大小,颜色。(通过调整代码,可以很容易地根据需要进行调整)。
- 节点可以有一个标题和一个隐藏的相关元数据。
- 选择模式有:多选,单选和不选。
- 节点链接可以是直线(曼哈顿)或贝塞尔曲线。
- 树形布局可以从上到下,从右到左或颠倒。(感谢沃克的算法,而不是我...!)
- 节点可以有一个相关的超链接。
- 子树可以按需要折叠和展开。
- 节点搜索可以基于标题和元数据来完成。
我想说这是一个正在进行的工作。特别是,代码的结构允许不同的渲染技术,我必须在这个主题上更加努力地工作。
背景
Walker算法扩展了Reingold,Tilford,Shannon等人以前的作品。提供一个解决方案,在满足以下审美规则的同时,树形图占用尽可能小的空间:
- 同一级别的节点是对齐的,并且所有级别的轴是平行的。
- 父母应该集中在孩子身上。
- 以相反的顺序定义的树和相同的树应该产生彼此反射的布局。无论树在哪里出现,都必须以相同的方式呈现相同的子树。
Walker算法的目标是提供一个完全满足第三个规则的解决方案,即在相邻较大的子树内部均匀划分较小的子树。
图4. 示例显示Walker算法中分配例程的差异。。
算法的主要概念是:
- 把每个子树看作是一个坚硬的单位,移动一个节点意味着移动它的所有后代。
- 这样做是通过对每个节点使用初始坐标和修饰符。移动节点意味着增加/减少其初始坐标及其修饰符,但只有修饰符会影响节点后代的最终位置。所以移动子树意味着改变子树的根修饰符。计算节点的最终位置,计算节点初始坐标加上其所有祖先的修改量。
该算法工作在两遍。第一遍(firstWalk
)是一个后序遍历。不同的子树从底部到顶部递归处理,并从左到右定位形成每个子树的刚性单元,直到没有人相互接触。随着遍历的进行,较小的子树被组合形成较大的子树,直到我们到达根。在这个过程中,例行程序将可能在两个相邻较大子树之间漂浮的内部较小子树(均匀地满足第三个规则的对称性)均匀地分隔开来。第二遍()是一个前序遍历,它通过将所有的祖先修饰符添加到每个节点的初始坐标来计算最终的节点位置。 apportion
secondWalk
高超威(参见参考文献)提出了对例行程序的优化,其中包括Walker算法的增量版本。此版本避免在对树结构所做的更改不意味着修改其值时,重新计算节点的初始坐标和修饰符。这个优化还没有在这个组件中实现。 firstWalk
该算法还调整计算,如果布局是在不同的方向(即从底部到顶部)。不同的用途可能需要不同的意见 在欧美国家,传统意义上的顶级意味着权力,就像组织层次结构一样; 底部布局意味着进化或生长,就像生物学一样; 而左右布局可能意味着时间的演变。(但这是一个特别的考虑)。
只要提一句,像这样一个统一的布局算法就足够用于相对较小的树木。具有大量节点的树可能需要其他布局和可视化技术,例如缩放,平移和聚焦的能力,折叠节点的一些而不是所有子节点,增加交互式搜索。有许多其他解决方案可以实现相同的目标,包括但不限于双曲树,树图,兴趣度计算,...好奇的读者可以在网上找到很多信息。
使用代码
快速和肮脏的指导,让事情和工作
让我们来构建一个例子(所有样本都包含在下载中),以了解如何绘制一棵简单的树。之后,通过API参考并查看高级示例代码,您可以充分了解如何使用此组件。
首先,您必须包含组件脚本并将样式表链接到
你的HTML页面的一部分(记得在安装时设置路径):
<< / span> head >
<< / span> 脚本 类型=“ text / javascript” src =“ ECOTree.js” > </ </ span> 脚本>
<< / span> link type =“ text / css” rel =“ style-sheet” href =“ ECOTree.css” / >
<< / span> / head >
此外,如果您打算使用Internet Explorer,则必须将下一行添加到
您的HTML页面的VML部分正确呈现:
<< / span> head >
<< / span> xml:namespace ns =“ urn:schemas-microsoft-com:vml” prefix =“ v” / >
<< / span> 风格> v :* {behavior:url(#default#VML); } </ </ span> style >
<< / span> / head >
在你的HTML页面中,你必须为树放置一个块容器,比如a
<< / span> div id =“ myTreeContainer” > << / span> / div >
var myTree = new ECOTree(“ myTree”,“ myTreeContainer”);
myTree.add(0,-1,“ 顶点节点”);
myTree.add(1,0,“ 左子”);
myTree.add(2,0,“ 右子”);
myTree.UpdateTree();
结果将是:
图5. 快速实施例1。
您必须确保在加载页面后至少在加载容器时执行脚本块。因此,您可以选择在容器后面插入脚本,或者在事件发生时为文档或主体调用的函数内部创建树。 OnLoad
请注意,组件具有几乎所有的默认值,导致这五行代码可以创建一个可以随意合拢或展开的树,只需单击它们即可选择/取消选择多个节点。另外,每个节点默认都有超链接。几乎每一次,你都会想要改变树的外观和感觉以及行为,以更好地满足你的需求。这可以通过树的实例成员完成。让我们通过添加一些行来修改前面的例子: Javascript:void(0);
config
var myTree = new ECOTree(“ myTree”,“ myTreeContainer”);
myTree.config.linkType = ' B' ;
myTree.config.iRootOrientation = ECOTree.RO_BOTTOM;
myTree.config.topYAdjustment = -160;
myTree.config.linkColor = “ black” ;
myTree.config.nodeColor = “ #FFAAAA” ;
myTree.config.nodeBorderColor = “ black” ;
myTree.config.useTarget = false ;
myTree.config.selectMode = ECOTree.SL_SINGLE;
myTree.add(0,-1,“ 顶点节点”);
myTree.add(1,0,“ 左子”);
myTree.add(2,0,“ 右子”);
myTree.UpdateTree();
有了这些细微的变化,现在树会看起来像这样:
图6. 快速例2。
这次,节点没有超链接(),并且一次只能选择一个节点()。useTarget = false
selectMode = ECOTree.SL_SINGLE
好,现在基本已经被覆盖了,让我们继续发现所有的可能性。
API参考
ECOTree配置
这里是配置参数及其默认值:
这个 .config = {
iMaxDepth:100,
iLevelSeparation:40,
iSiblingSeparation:40,
iSubtreeSeparation:80,
iRootOrientation:ECOTree.RO_TOP,
iNodeJustification:ECOTree.NJ_TOP,
topX调整:0,
topY调整:0,
渲染:“ 自动”,
linkType:“ M”,
linkColor:“ 蓝色”,
nodeColor:“ #CCCCFF”,
nodeFill:ECOTree.NF_GRADIENT,
nodeBorderColor:“ blue”,
nodeSelColor:“ #FFFFCC”,
levelColors:[ “ #5555FF” ,“#8888FF” ,“#AAAAFF” ,“#CCCCFF” ],
levelBorderColors:[ “ #5555FF” ,“#8888FF” ,“#AAAAFF” ,“#CCCCFF” ],
colorStyle:ECOTree.CS_NODE,
useTarget:true,
searchMode:ECOTree.SM_DSC,
selectMode:ECOTree.SL_MULTIPLE,
defaultNodeWidth:80,
defaultNodeHeight:40,
defaultTarget:' Javascript:void(0);' ,
expandedImage:' ./img/less.gif',
collapsedImage:' ./img/plus.gif',
transImage:' ./ img/ trans.gif'
}
iMaxDepth
:允许树的最大级别数。将其设置为比预期的最大级别更大的值。iLevelSeparation
:以像素为单位的级别之间的空间距离。请注意,级别大小将由该级别的最大节点大小给出。iSiblingSeparation
:兄弟节点之间的最小空间距离(以像素为单位)。iSubtreeSeparation
:邻居节点之间的最小空间距离(不具有相同的父节点),以像素为单位。iRootOrientation
:布局的方向。可能的值是:ECOTree.RO_TOP
:从上到下布局。ECOTree.RO_BOTTOM
:从底部到顶部的布局。ECOTree.RO_RIGHT
:从右向左布局。ECOTree.RO_LEFT
:从左到右布局。
iNodeJustification
:属于同一级别的节点的对齐。可能的值是:topXAdjustment
:给出根节点的水平偏移量(以像素为单位)。用它来中心/平移屏幕上的树。ECOTree.NJ_TOP
:节点顶部对齐。ECOTree.NJ_CENTER
:节点居中对齐。ECOTree.NJ_BOTTOM
:节点底部对齐。
topYAdjustment
:给出根节点的垂直偏移像素。用它来中心/平移屏幕上的树。render
:渲染类型。可能的值是:"AUTO"
:自动。这是默认值。代码将自动检测,如果客户端是Internet Explorer 6或Firefox,并且渲染类型将分别设置为或。"VML"
"CANVAS"
"VML"
:矢量标记语言。仅适用于Internet Explorer。如果您使用它,请记得在文章中指出的部分添加和。XML namespace
head
"CANVAS"
:渲染将基于HTML元素。仅适用于Firefox 1.5+。(尽管Firefox 2.0速度更快)。
linkType
:节点链接的样式。可能的值是:linkColor
:用于连接线的颜色。任何用HTML表示的颜色都是有效的。"M"
: 曼哈顿。链接是交叉的直线。经典。"B"
:贝济耶 链接是贝塞尔曲线。在某些情况下更合适。
nodeColor
:用于节点的颜色。请参阅关于如何破解节点呈现模式的文章中的注释。任何用HTML表示的颜色都是有效的。nodeFill
:节点的填充风格。可能的值是:nodeBorderColor
:用于节点边界的颜色。任何用HTML表示的颜色都是有效的。ECOTree.NF_GRADIENT
:节点将用节点颜色和“whitesmoke”之间的渐变填充。ECOTree.NF_FLAT
:节点将有一个坚实的填充。
nodeSelColor
:用于所选节点的颜色。任何用HTML表示的颜色都是有效的。levelColors
:具有连续级别颜色的Javascript数组。当选项设置为使用级别颜色时应用。树的第一级的节点将具有此数组中的第一个颜色,第二级节点数组的第二个颜色,依此类推。如果有比这个数组中的元素更多的级别,那么后续的级别会重新重复这些颜色。任何用HTML表示的颜色都是有效的。colorStyle
levelBorderColors
:和上面一样,但是边框颜色。colorStyle
:指示如何计算节点颜色。可能的值是:useTarget
:节点是否显示超链接。可能的值是或true
false
ECOTree.CS_NODE
:每个节点将使用它自己的颜色来渲染。ECOTree.CS_LEVEL
:节点将根据树中节点的等级使用不同的颜色,忽略它自己的颜色。
searchMode
:表达搜索(见API )将如何完成。可能的值是:searchNodes
ECOTree.SM_DSC
:搜索将在节点标题内完成。ECOTree.SM_META
:搜索将在节点元数据内完成。ECOTree.SM_BOTH
:搜索将在两个值内完成。
selectMode
:表示树的选择行为。可能的值是:defaultNodeWidth
:节点宽度(以像素为单位),如果在向树添加节点时未给出明确的宽度。ECOTree.SL_MULTIPLE
:用户可以通过点击交互式地选择和取消选择多个节点。ECOTree.SL_SINGLE
:用户可以通过点击交互式地选择和取消选择单个节点。新的节点选择将取消选择先前的选择。ECOTree.SL_NONE
:用户不能通过单击来选择节点。无论如何,导致节点选择的API方法将始终有效,就像树上的搜索一样。
defaultNodeHeight
:节点高度(以像素为单位),如果在将节点添加到树时没有给出明确的高度。defaultTarget
:节点超链接(当点击标题时),如果在向树添加节点时没有给出明确的目标。通常在所有或大多数节点具有相同链接时设置。expandedImage
:允许折叠子树的减号图标。改变它,如果你不喜欢它,或指向你自己的图像文件夹。collapsedImage
:允许展开折叠子树的加号图标。改变它,如果你不喜欢它,或指向你自己的图像文件夹。transImage
:用于分隔折叠/展开图标和标题的透明图标。改变它,如果你不喜欢它,或指向你自己的图像文件夹。
ECOTree公共方法
UpdateTree()
:导致树刷新。add(id, pid, dsc, w, h, c, bc, target, meta)
:向树添加一个新节点。三个第一个参数是强制性的。参数是:
id
:节点ID。任何数字或字符串将是有效的。pid
:此节点的父ID。如果这是一个根节点,则父ID必须为-1。dsc
:节点标题。这将是可见的描述。它也将是到节点目标的链接。w
:(可选)节点宽度(以像素为单位)。c
:(可选)节点颜色。bc
:(可选)节点边框颜色。h
:(可选)节点高度(以像素为单位)。target
:(可选)节点超链接目标。如果您不提供此值,则节点将具有默认值。但是,如果您提供一个空字符串作为目标,您将以没有目标的节点结束。meta
:(可选)节点的元数据。元数据将不可见。您可以根据其内容搜索节点,也可以将其用作您自己的节点数据的容器。如果您使用Javascript对象作为元数据,请在该对象的原型中提供方法以使搜索正常工作。toString()
将节点添加到树中后,可以使用其他API对其进行修改,例如,在第一次调用之前,将其标记为选中或折叠(如果有子节点)。按照任何特定顺序添加节点并不是强制性的。 UpdateTree()
searchNodes(str)
:在树中搜索包含字符串的节点。找到的节点将被选中,如果是这样的话,他们的祖先扩展到查找找到的节点。搜索可以在节点的标题,元数据或两者中完成。搜索是不区分大小写的。如果是或将找到所有找到的节点。如果是只有第一个节点(在数据库顺序)将被选中,但随后的搜索将从下一个节点按顺序启动,这样你就可以调用这个API来模拟未来的搜索功能。所有的节点将被访问后,搜索将从头开始重新开始。在内部调用,所以你不需要刷新树。str
selectMode
SL_MULTIPLE
SL_NONE
selectMode
SL_SINGLE
UpdateTree()
selectAll()
:使树中的所有节点显示为选中状态。如果设置为这个API将返回没有选择。在内部调用,所以你不需要刷新树。selectMode
SL_NONE
UpdateTree()
unselectAll()
:清除所有选择。无论使用什么都可以使用。应该用来清除搜索之间的选择。在内部调用,所以你不需要刷新树。selectMode
UpdateTree()
collapseAll()
:导致所有父节点成为折叠状态。在内部调用,所以你不需要刷新树。UpdateTree()
expandAll()
:导致所有父节点变为扩展状态。在内部调用,所以你不需要刷新树。UpdateTree()
collapseNode(nodeid, upd)
:折叠ID =的节点。仅在您提供第二个参数时才在内部调用。所以如果你打算折叠几个节点,所有工作完成后你只应刷新一次。nodeid
UpdateTree()
true
selectNode(nodeid, upd)
:标记为ID =的节点。仅在您提供第二个参数时才在内部调用。nodeid
UpdateTree()
true
setNodeTitle(nodeid, title, upd)
:设置ID =的节点的标题。仅在您提供第三个参数时才在内部调用。title
nodeid
UpdateTree()
true
setNodeMetadata(nodeid, meta, upd)
:设置ID =的节点的元数据。仅在您提供第三个参数时才在内部调用。meta
nodeid
UpdateTree()
true
setNodeTarget(nodeid, target, upd)
:设置ID =的节点的超链接。仅在您提供第三个参数时才在内部调用。target
nodeid
UpdateTree()
true
setNodeColors(nodeid, color, border, upd)
:设置ID =的节点的背景和颜色。仅在您提供第四个参数时才在内部调用。color
border
nodeid
UpdateTree()
true
getSelectedNodes()
:返回一个JavaScript对象数组,每个对象的实例成员分别具有节点ID,标题和每个选定节点的元数据的值。查看示例以获取有关如何使用它的示例。如果你使用树客户端进行一些编辑,并使用该对象将用户选择或搜索结果发送到服务器,这可能很有用。(和AJAX不在本文讨论的范围内,但很高兴听到IE7最终实现为本地内部对象...)。"id","dsc", "meta"
XMLHttp
XMLHttp
XMLHttp
样品包括
在下载中,你可以找到几个简单的例子,你可以玩。本文中的所有图像都是使用示例中的代码制作的。有一个高级的例子,可以让你玩几乎所有的组件选项。样本中的数据已经在维基百科中获得。
参考
- 1990年Walker II,JQ,“一般树的节点定位算法”。软件 - 实践和经验,1980年,第553-561页。(从C ++用户期刊获得,1991年2月)。
- 2003高超威,“基于组件的可视化树搜索”。计算机科学系。计算学院。新加坡国立大学。
- VML - 矢量标记语言参考
- HTML 元素资源
- GeirLandrödTree:JavaScript树
- JavaScript水平树。Mahmoud Tahoon。代码项目中的条款。
未来的增强
- 为组件添加就地(客户端)编辑功能,如添加,删除,洗牌节点和更改其属性(即上下文菜单)
- 实现高超威提出的优化布局算法(见参考文献)。