|
动机: 最初想起做二叉树是因为需要做一个公司结构图。 以前的做法都是直接用图象软件画出来一个图片。很好看,但每次有变动后都需要重新画一个新的。 另一方面,网页上对线条的显示、布局相当局限。根据动态生成的数据进行排版、定位都相当困难, 而且在美观上也差强人意。 做了各种尝试以后,决定用XML+XSL作数据运算; 用VML来美化线条,用JAVASCRIPT来给对象定位。
材料: XML卷之结构树图 有2个文件:flow2.xml 和 flow2.xsl 效果: 浏览这里 讲解: 二叉树思路(1)
<html xmlns:v="urn:schemas-microsoft-com:vml"> <STYLE> v\:* { BEHAVIOR: url(#default#VML) } </STYLE> <v:group id="group1" name="group1" coordsize = "100,100"> … </v:group> 以上这些都是VML的基本格式,我就不详细讲解了。
XML是树型结构,我们读取每个数据就需要对这个 XML数据树进行遍历。而递归运算是XSL优势之一。 我也是在用其它多种方法进行遍历运算失败后才 决定使用XSL的。
<FlowRoot> <vcTitle>二叉树--结构图</vcTitle> <Author>Sailflying</Author> <Email>sailflying@163.net</Email> <FlowNode> <iProcess>1</iProcess> <vcCourse>第一个节点</vcCourse> <iNextYes> <FlowNode> <iProcess>2</iProcess> <vcCourse>第二个节点</vcCourse> <iNextYes>…</iNextYes> <iNextNo>…</iNextNo> </FlowNode> </iNextYes> <iNextNo> <FlowNode> <iProcess>3</iProcess> <vcCourse>第三个节点</vcCourse> <iNextYes>…</iNextYes> <iNextNo>…</iNextNo> </FlowNode> </iNextNo> </FlowNode> </FlowRoot>
逻辑上很简单,当前节点(1)下面有两个子节点(2,3)。 只需要将节点2和节点3定位在节点1的左下方和右下方就可以了。 这里我将左右节点的连接线分别用了绿色和红色,方便显示。
前面我们说到了XSL的递归功能,为了更清楚的看到每一个详细的 显示步骤,只需要仿照下面的代码,加一个alert语句就可以了。
<xsl:template match="FlowNode"> … <SCRIPT language="JavaScript1.2"> … alert('逐步显示'); … </SCRIPT> … </xsl:template>
看了上面的慢动作,是否能让大家了解到我的思路。
二叉树思路(2) 我的思路很简单: (1)读取当前节点的资料,用VML生成一个新的对象。 给对象赋初始数值(如 name,id,style样式等) (2)用脚本控制来给当前对象定位 (3)当前节点和它的父亲节点之间加箭头,线条。 (4)继续找当前节点的子节点,一直循环定位到结束。 也就是所有节点都遍历完毕,已经生成好了树。
<xsl:template match="FlowNode"> … <xsl:apply-templates /> … </xsl:template> <xsl:template match="iNextYes"> <xsl:apply-templates select="./FlowNode" /> </xsl:template>
<xsl:template match="iNextNo"> <xsl:apply-templates select="./FlowNode" /> </xsl:template>
整个递归过程就是靠上面这三个模块(template)来完成的。 第一个template在匹配当前节点中每一个子节点的模板的时候 调用了后面两个template; 而后面两个template又在具体执行 的时候调用了第一个template ,这就相当于一个递归函数。
语法:
要依次匹配当前节点中的每个子节点的模板,应使用该元 素的基本形式 <xsl:apply-templates />。 否则,匹配的节点由 select 参数中 XPath 表达式的值决 定,如 <xsl:apply-templates select="./FlowNode" />
(1)和(2)的作用都是返回由 select 参数给出的表达式的字符串值。 他们的搜索条件相同,所以返回的值也一样。 只不过是使用的场合不同,他们的书写形式也就不一样。
(1) <xsl:value-of select="./iProcess/text()" /> (2) {./iProcess/text()}
这里定义了一些变量,节点的定位就是根据这些变量来调用运算公式的。
root_left //根的左边距=所有叶子的分配宽度(y*10) + 所有叶子的宽度(y*50) + 左边距基本值(10) root_top //根的上边距=上边距基本值(10) objOval //当前对象,是一个object objOval_iProcess //当前对象的步骤值 objParentOval //当前对象的父节点,是一个object objParentOval_iProcess //当前对象父节点的步骤值 objParent_name //当前对象父节点的名称 Leaf_left //当前对象的所有子节点中的左边叶子数 Leaf_right //当前对象的所有子节点中的右边叶子数 Leaf_sum //当前对象的所有子节点中叶子数
叶子:是指当前节点没有子节点
节点的定位公式:
(1) 当前节点是根节点
//根的位置 SobjOval.style.left=parseInt(root_left); SobjOval.style.top=parseInt(root_top); //parseInt() 函数的作用是取整数值,如果不是则为NAN //isNaN()函数的作用是判断parseInt取得的是否为整数
(2)当前节点是父节点的左边子节点
1)判断的条件是: 当前对象父节点的名称='iNextYes' … 2)如果存在右边子叶子,则公式为: 当前节点的left=父节点的left - 当前节点的右边子叶子的总宽度- 当前节点的宽度
3)如果不存在右边子叶子,但存在左边子叶子,则公式为: 当前节点的left=父节点的left - 当前节点的左边子叶子的总宽度
4)如果当前节点本身就是叶子,则公式为: 当前节点的 此新闻共有2页 上一页 1 2 下一页 |