motivation:
I first thought of making a binary tree because I needed to make a company structure chart. The previous approach was to draw a picture directly using graphics software. It looks great, but you need to paint a new one every time there are changes. On the other hand, the display and layout of lines on web pages are quite limited. Typesetting and positioning based on dynamically generated data are very difficult, and the aesthetics are not satisfactory. After making various attempts, I decided to use XML+XSL for data operations; use VML to beautify lines, and use JAVASCRIPT to position objects.
Material:
The structure tree diagram of the XML volume has 2 files: flow2.xml and flow2.xsl
Effect:
Browse here
explain:
Binary tree idea (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>
These are the basic formats of VML, so I won’t explain them in detail.
XML is a tree structure. When we read each data, we need to
XML data tree is traversed. Recursive operations are one of the advantages of XSL.
I also decided to use XSL after using various other methods to perform traversal operations and failed.
<FlowRoot>
<vcTitle>Binary tree--structure diagram</vcTitle>
<Author>Sailflying</Author>
<Email>[email protected]</Email>
<FlowNode>
<iProcess>1</iProcess>
<vcCourse>First node</vcCourse>
<iNextYes>
<FlowNode>
<iProcess>2</iProcess>
<vcCourse>Second node</vcCourse>
<iNextYes>…</iNextYes>
<iNextNo>…</iNextNo>
</FlowNode>
</iNextYes>
<iNextNo>
<FlowNode>
<iProcess>3</iProcess>
<vcCourse>The third node</vcCourse>
<iNextYes>…</iNextYes>
<iNextNo>…</iNextNo>
</FlowNode>
</iNextNo>
</FlowNode>
</FlowRoot>
The logic is very simple. There are two child nodes (2, 3) under the current node (1).
Just position node 2 and node 3 at the lower left and lower right of node 1.
Here I use green and red for the connecting lines of the left and right nodes respectively for easy display.
We talked about the recursive function of XSL earlier. In order to see each detailed display step more clearly, you only need to imitate the following code and add an alert statement.
<xsl:template match="FlowNode">
…
<SCRIPT language="JavaScript1.2">
…
alert('display step by step');
…
</SCRIPT>
…
</xsl:template>
After watching the slow motion above, can you understand my thoughts?
Binary tree idea (2)
My idea is very simple:
(1) Read the data of the current node and generate a new object using VML.
Assign an initial value to the object (such as name, id, style, etc.)
(2) Use script control to position the current object. (3) Add arrows and lines between the current node and its parent node.
(4) Continue to find the child nodes of the current node and loop until the end.
That is, all nodes have been traversed and the tree has been generated.
<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>
The entire recursive process is completed by the above three modules (templates).
The first template calls the following two templates when matching the template of each child node in the current node; and the latter two templates call the first template during specific execution, which is equivalent to a recursive function.
grammar:
To match the templates of each child node in the current node in turn, use the element's base form <xsl:apply-templates />.
Otherwise, the matching node is determined by the value of the XPath expression in the select parameter, such as <xsl:apply-templates select="./FlowNode" />
The functions of (1) and (2) are to return the string value of the expression given by the select parameter.
Their search conditions are the same, so the returned values are also the same.
It's just that their writing forms are different depending on the occasions they are used.
(1) <xsl:value-of select="./iProcess/text()" />
(2) {./iProcess/text()}
Some variables are defined here, and the positioning of the node is based on these variables to call the calculation formula.
root_left //The left margin of the root = the allocated width of all leaves (y*10) + the width of all leaves (y*50) + the basic value of the left margin (10)
root_top //The top margin of the root = the basic value of the top margin (10)
objOval //The current object is an object
objOval_iProcess //Step value of the current object
objParentOval //The parent node of the current object is an object
objParentOval_iProcess //The step value of the current object's parent node
objParent_name //The name of the current object's parent node
Leaf_left //The number of left leaves among all child nodes of the current object
Leaf_right //The number of right leaves among all child nodes of the current object
Leaf_sum //The number of leaves among all child nodes of the current object.
Leaf: refers to the current node having no child nodes.
Node positioning formula:
(1) The current node is the root node
//The position of the root
SobjOval.style.left=parseInt(root_left);
SobjOval.style.top=parseInt(root_top);
//The function of parseInt() function is to take the integer value, if not, it will be NAN
//The function of isNaN() function is to determine whether the value obtained by parseInt is an integer.
(2) The current node is the left child node of the parent node
1) The conditions for judgment are: The name of the current object’s parent node=’iNextYes’
…
2) If there is a right child leaf, the formula is:
The left of the current node = the left of the parent node - the total width of the right child leaf of the current node - the width of the current node
3) If there is no right child leaf, but there is a left child leaf, the formula is:
The left of the current node = the left of the parent node - the total width of the left child leaf of the current node
4) If the current node itself is a leaf, the formula is:
The left of the current node = the left of the parent node - the width of the current node...
(3) The current node is the right child node of the parent node
1) The conditions for judgment are: The name of the current object’s parent node=’iNextNo’
…
2) If there is a left child leaf, the formula is:
The left of the current node = the left of the parent node + the total width of the left child leaf of the current node + the width of the current node
3) If there is no left child leaf, but there is a right child leaf, the formula is:
The left of the current node = the left of the parent node + the total width of the right child leaf of the current node
4) If the current node itself is a leaf, the formula is:
The left of the current node = the left of the parent node + the width of the current node...
The formulas (2) and (3) both get the left of the current node, and we also need to get the top of the current node.
Very simple formula: top of current node = top of parent node + offset (80)
Binary tree idea (3)
Positioning ideas for connecting lines:
(1) Find the positions of the current node and the parent node (2) Determine whether the current node is the left child node or the right child node of the parent node (3) Draw a line
Some variables are defined here.
objOval //The current node is an object
objParentOval //The parent node of the current object is an object
objLine //The current line is an object
Line positioning formula:
from="x1,y1" to="x2,y2" is the way to position lines in VML.
The current node is the left child node of the parent node, then the formula is:
from = parent node's left + offset (15), parent node's top + offset (32)
to = left + offset (30) of the parent node, top - offset (2) of the parent node.
The current node is the right child node of the parent node, then the formula is:
from = left of parent node + offset (35), top of parent node + offset (32)
to = left of parent node + offset (20), top of parent node - offset (2)
That's all I can think of.
It would be much simpler if we just made a company structure chart.
The following is Cy Young's idea, and I am just going a little deeper on his basis.
First calculate the number of nodes at the bottom level to get the width,
The node's upper node position should then be calculated based on its affiliation, recursively.
The nodes at each level should be sorted according to their affiliation. First, set the "basic value" = the node should be offset to the right. The left value of each node containing child nodes is equal to half the width of the node it owns plus the basic value.
Postscript:
For some reason, the internet has been bad recently. Spend more time offline than online.
Therefore, the code has not been simplified. In fact, there are still many functions that need to be improved, such as:
You need to add a right-click menu. The right-click menu contains the ability to create new nodes, modify node names, change associations, etc. You can right-click on each node to open the right-click menu of this node.
explain:
1) flow2.xml is a data file, I believe everyone will have no problem.
2) flow2.xsl is a format file, there are several things to pay attention to.
(1) In the script:
(1) <xsl:value-of select="./iProcess/text()" />;
(2) {./iProcess/text()}
The functions of (1) and (2) are to return the string value of the expression given by the select parameter.
Their search conditions are the same, so the returned values are also the same.
It's just that their writing forms are different depending on the occasions they are used.
<xsl:apply-templates select="team" order-by="blue_ID"/>
For example, we want to generate the following code
<div name="parameter value">Content</div>
We assume that the name is "name" and the parameter value is the value of the child node book under the current node in the XML data.
The first way to write it is to add the attribute name first and then the parameter value.
<div>
<xsl:attribute name="name">
<xsl:value-of select="./book/text()"/> </xsl:attribute>
content
</div>
The second way to write is to directly add the attribute name and parameter value
<div name="{./book/text()}">Content</div>
For specific usage, you can see the examples in the code I wrote.
XSL is in the official standard xmlns:xsl=" http://www.w3.org/1999/XSL/Transform "
<xsl:value-of select="./book/text()"/>
The function is: just write out his text value, and
<xsl:value-of select="./book"/>
It displays its text value and the contents of all its child nodes.
You can try it out and output one with child nodes and one without child nodes to see if the displayed results are the same.
(2) Note:
IE5 does not support <tag att="{xpath}">
Want to use
<tag><xsl:attribute name="att"><xsl:value-of select="xpath"></xsl:attribute>
namespace needs to be used
xmlns:xsl=" http://www.w3.org/TR/WD-xsl "
<?xml version="1.0" encoding="gb2312" ?>
One more thing:
Encoding="gb2312" is rarely added to the code shown in most XML textbooks.
Therefore, when we use Chinese in XML, an error will be reported. The reason is that this declaration is not written.
postscript:
What I’m talking about here is a way of thinking. If you draw an analogy, it will naturally come in handy.