XML-Data driven Component example: File-Tree The following component takes an XML-string, and draws itself based on the directory structure given in the XML. If you look at the SVG-code (e.g. view source option of SVG Viewer popup), you would find the XML-data (please see the XML below ) is included in it. You could substitute that XML-string with any XML-string that conforms the XML-schema and reload the web-page, this component presents the new file-tree. The JavaScript in the file processes the XML-string and presents the component. This kind of presentation-blocks are very useful to work with Web Services, since they could be refreshed frequently by getting new XML-string, whenever there is a change at the Web server.Features:
Note: Please see below for both the XML-data and the SVG/JavaScript code
|
var
XML_data
=
'<item caption="Node: Top" id="0">'
+'
<item caption="Node Top.1" id="1">'
+'
<item caption="Node Top.1.1" id="2">'
+'
<item caption="Node Top.1.1.1"
id="3">'
+'
<item caption="Node Top.1.1.1.1"
id="1">'
+'
<item caption="Node Top.1.1.1.1.1"
id="2">'
+'
<item caption="Node Top.1.1.1.1.1.1"
id="3"/>'
+'
</item>'
+'
<item caption="Node Top.1.1.1.1.2"
id="4" />'
+'
</item>'
+'
<item caption="Node Top.1.1.1.2" id="5"
/>'
+'
<item caption="Node Top.1.1.1.3"
id="6">'
+'
<item caption="Node Top.1.1.1.3.1"
id="7"/>'
+'
</item>'
+'
</item>'
+'
</item>'
+'
<item caption="Node Top.1.2" id="4"
/>'
+'
</item>'
+'
<item caption="Node Top.2" id="5" />'
+'
<item caption="Node Top.3" id="6">'
+'
<item caption="Node Top.3.1"
id="7"/>'
+'
</item>'
+'
<item caption="Node Top.4" id="1">'
+'
<item caption="Node Top.4.1" id="2">'
+'
<item caption="Node Top.4.1.1"
id="3">'
+'
<item caption="Node Top.4.1.1.1"
id="1">'
+'
<item caption="Node Top.4.1.1.1.1"
id="2">'
+'
<item caption="Node Top.4.1.1.1.1.1"
id="3">'
+'
<item caption="Node Top.4.1.1.1.1.1.1"
id="1">'
+'
<item caption="Node Top.4.1.1.1.1.1.1.1"
id="2">'
+'
<item caption="Node Top.4.1.1.1.1.1.1.1.1"
id="3"/>'
+'
</item>'
+'
<item caption="I\'m small ;)" id="4"
/>'
+'
</item>'
+'
<item caption="Node Top.4.1.1.1.1.1.2"
id="5" />'
+'
<item caption="Node Top.4.1.1.1.1.1.3"
id="6">'
+'
<item caption="Node Top.4.1.1.1.1.1.3.1"
id="7"/>'
+'
</item>'
+'
</item>'
+'
</item>'
+'
<item caption="Node Top.4.1.1.1.2"
id="4" />'
+'
</item>'
+'
<item caption="Node Top.4.1.1.2" id="5"
/>'
+'
<item caption="Node Top.4.1.1.3"
id="6">'
+'
<item caption="Node Top.4.1.1.3.1"
id="7"/>'
+'
</item>'
+'
</item>'
+'
</item>'
+'
<item caption="Node Top.4.2" id="4"
/>'
+'
</item>'
+'
<item caption="Node Top.5" id="5">'
+'
<item caption="Node Top.5.1" id="1">'
+'
<item caption="Node Top.5.1.1"
id="2">'
+'
<item caption="Node Top.5.1.1.1"
id="3"/>'
+'
</item>'
+'
<item caption="Node Top.5.1.2" id="4"
/>'
+'
</item>'
+'
<item caption="Node Top.5.2" id="5"
/>'
+'
<item caption="Node Top.5.3" id="6">'
+'
<item caption="Node Top.5.3.1"
id="7"/>'
+'
</item>'
+'
</item>'
+'
<item caption="Node Top.6" id="6">'
+'
<item caption="Node Top.6.1"
id="7"/>'
+'
</item>'
+'</item>'
The Presentation Block (or JavaScript code for the Directory-tree application-component):
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN"
"http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg id="root" onload="init(evt)" width="320" height="320"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g>
<script type="text/ecmascript"><![CDATA[
/*****
*
* Tree.js
*
* Copyright 2002, Philippe Elsass
*
* Thanks to Kevin Lindsey for his great Svg scripts.
*
*****/
Tree = new Object;
Tree.VERSION = 0.1;
Tree.ID_PLUS = "tree_plus";
Tree.ID_MINUS = "tree_minus";
Tree.ID_END = "tree_end";
Tree.ID_BUTTON = "tree_button";
Tree.TEXT_STYLE = "font-family:Arial,Helvetica;font-size:8pt;text-rendering:optimizeLegibility;";
Tree.TEXT_SELECT = "fill:white;pointer-events:none;";
Tree.TEXT_NORMAL = "fill:black;pointer-events:none;";
Tree.LINES_STYLE = "fill:none;stroke-width:0.5;stroke:black;stroke-dasharray:1 1;";
Tree.SELBOX_STYLE = "fill:#003399;stroke-width:0.5;stroke:black;stroke-dasharray:1 1;";
Tree.BG_STYLE = "fill:white;stroke:#eeeeee;stroke-width:1;shape-rendering:optimizeSpeed;";
Tree.HIGH_STYLE = "fill:none;stroke:white;stroke-width:1;shape-rendering:optimizeSpeed;";
Tree.LOW_STYLE = "fill:none;stroke:gray;stroke-width:1;shape-rendering:optimizeSpeed;";
Tree.SCROLL_STYLE = "fill:#eeeeee;stroke:none;";
Tree.SCREND_STYLE = "fill:silver;stroke:none;";
Tree.HIDE_STYLE = "stroke-opacity:0;fill-opacity:0;";
Tree.ITEM_HEIGHT = 20;
Tree.CHILD_TAB = 24;
Tree.TEXT_XOFFSET = 14;
Tree.TEXT_YOFFSET = 4;
Tree.BUTTON_SIZE = 12;
Tree.root = null;
Tree.depth = 0;
Tree.callBack = null;
Tree.current = null;
/*****
*
* updateTree (x,y,width,height: optionnal);
*
*****/
function updateTree(reorganize,x,y,width,height) {
if (!Tree.parent) exit;
if (!isNaN(x) && !isNaN(y)) {
Tree.x = x;
Tree.y = y;
}
if (!isNaN(width) && !isNaN(height)) {
Tree.width = width;
Tree.height = height;
Tree.clip.setAttribute("x",x+1);
Tree.clip.setAttribute("y",y+1);
Tree.background.setAttribute("x",x+1);
Tree.background.setAttribute("y",y+1);
Tree.background.setAttribute("width",width-2);
Tree.background.setAttribute("height",height-2);
Tree.background.setAttribute("style",Tree.BG_STYLE);
Tree.lowBorder.setAttribute("d","M"+Tree.x+","+(Tree.y+Tree.height)+"v-"+Tree.height+"h"+Tree.width);
Tree.lowBorder.setAttribute("style",Tree.LOW_STYLE);
Tree.highBorder.setAttribute("d","M"+Tree.x+","+(Tree.y+Tree.height)+"h"+Tree.width+"v-"+Tree.height);
Tree.highBorder.setAttribute("style",Tree.HIGH_STYLE);
}
if (reorganize) {
Tree.linesData = "";
Tree.maxX = 0;
Tree.maxY = 0;
Tree.root.organize(true,Tree.x+12,Tree.y+10);
}
if ((reorganize) || (!isNaN(width) && !isNaN(height))) {
var vBar = true;
var hBar = true;
if ((Tree.maxX+8<Tree.x+Tree.width) && (Tree.maxY+8<Tree.y+Tree.height))
{ vBar = false; hBar = false; } else
if ((Tree.maxX+8>Tree.x+Tree.width) && (Tree.maxY+8<Tree.y+Tree.height-16))
{ vBar = false; hBar = true; } else
if ((Tree.maxX+8<Tree.x+Tree.width-16) && (Tree.maxY+8>Tree.y+Tree.height))
{ vBar = true; hBar = false; }
if (reorganize || (vBar != Tree.vBar) || (hBar != Tree.hBar) || (!isNaN(width) && !isNaN(height))) {
Tree.vBar = vBar;
Tree.hBar = hBar;
if (Tree.vBar) Tree.xAvail = Tree.width-2-Tree.BUTTON_SIZE; else Tree.xAvail = Tree.width-2;
if (Tree.hBar) Tree.yAvail = Tree.height-2-Tree.BUTTON_SIZE; else Tree.yAvail = Tree.height-2;
Tree.maxScrollX = Tree.maxX-Tree.x-Tree.xAvail+8;
Tree.pageSizeX = Tree.xAvail-24;
Tree.maxScrollY = Tree.maxY-Tree.y-Tree.yAvail+8;
Tree.pageSizeY = Tree.yAvail-Tree.ITEM_HEIGHT-8;
if (Tree.vBar || Tree.hBar)
Tree.scrollBars.setAttribute("style","display:visible;"+Tree.SCROLL_STYLE);
var d="";
if (Tree.hBar) {
Tree.clip.setAttribute("height",Tree.height-2-Tree.BUTTON_SIZE);
d = "M"+(Tree.x+1)+","+(Tree.y+Tree.height-1-Tree.BUTTON_SIZE)
+ "v"+Tree.BUTTON_SIZE+"h"+Tree.xAvail+"v-"+Tree.BUTTON_SIZE+"z";
}
else Tree.clip.setAttribute("height",Tree.height-2);
if (Tree.vBar) {
Tree.clip.setAttribute("width",Tree.width-2-Tree.BUTTON_SIZE);
d += "M"+(Tree.x+Tree.width-1-Tree.BUTTON_SIZE)+","+(Tree.y+1)
+ "h"+Tree.BUTTON_SIZE+"v"+Tree.yAvail+"h-"+Tree.BUTTON_SIZE+"z";
}
else Tree.clip.setAttribute("width",Tree.width-2);
Tree.scrollBars.setAttribute("d",d);
if (hBar && vBar) {
Tree.scrollEnd.setAttribute("x",Tree.x+Tree.width-1-Tree.BUTTON_SIZE);
Tree.scrollEnd.setAttribute("y",Tree.y+Tree.height-1-Tree.BUTTON_SIZE);
Tree.scrollEnd.setAttribute("style","display:visible;"+Tree.SCREND_STYLE);
}
else Tree.scrollEnd.setAttribute("style","display:none;");
if (hBar) {
Tree.hSb.setAttribute("transform",
"translate("+(Tree.x+hPos()+1)+","+(Tree.y+Tree.height-1-Tree.BUTTON_SIZE)+")");
Tree.hSb.setAttribute("style", "display:visible;pointer-events:none;");
}
else {
Tree.hSb.setAttribute("style", "display:none;");
Tree.hScroll = 0;
}
if (vBar) {
Tree.vSb.setAttribute("transform",
"translate("+(Tree.x+Tree.width-1-Tree.BUTTON_SIZE)+","+(Tree.y+vPos()+1)+")");
Tree.vSb.setAttribute("style", "display:visible;pointer-events:none;");
}
else {
Tree.vSb.setAttribute("style", "display:none;");
Tree.vScroll = 0;
}
Tree.treeBox.setAttribute("transform",
"translate(-"+Math.floor(Tree.hScroll)+",-"+Math.floor(Tree.vScroll)+")");
}
}
}
/*****
*
* _root_init: reference to first node and callback function - create tree-lines path
*
*****/
function _root_init(_this) {
var SVGDoc = Tree.parent.getOwnerDocument();
Tree.root = _this;
var obj = SVGDoc.createElement("clipPath");
obj.setAttribute("id","treeClip");
Tree.clip = SVGDoc.createElement("rect");
obj.appendChild(Tree.clip);
Tree.parent.appendChild( obj );
Tree.backBox = SVGDoc.createElement("g");
Tree.background = SVGDoc.createElement("rect");
Tree.background.setAttribute("style", "display:none;");
Tree.backBox.appendChild( Tree.background );
Tree.scrollBars = SVGDoc.createElement("path");
Tree.scrollBars.setAttribute("style", "display:none;");
Tree.scrollBars.addEventListener("mousedown", sb_down, false);
Tree.backBox.appendChild( Tree.scrollBars );
Tree.scrollEnd = SVGDoc.createElement("rect");
Tree.scrollEnd.setAttribute("width",Tree.BUTTON_SIZE+1);
Tree.scrollEnd.setAttribute("height",Tree.BUTTON_SIZE+1);
Tree.scrollEnd.setAttribute("style", "display:none;");
Tree.backBox.appendChild( Tree.scrollEnd );
Tree.hSb = SVGDoc.getElementById(Tree.ID_BUTTON).cloneNode(true);
Tree.hSb.setAttribute("style", "display:none;");
Tree.backBox.appendChild( Tree.hSb );
Tree.hScroll = 0;
Tree.vSb = SVGDoc.getElementById(Tree.ID_BUTTON).cloneNode(true);
Tree.vSb.setAttribute("style", "display:none;");
Tree.backBox.appendChild( Tree.vSb );
Tree.vScroll = 0;
Tree.highBorder = SVGDoc.createElement("path");
Tree.highBorder.setAttribute("style", "display:none;");
Tree.backBox.appendChild( Tree.highBorder );
Tree.lowBorder = SVGDoc.createElement("path");
Tree.lowBorder.setAttribute("style", "display:none;");
Tree.backBox.appendChild( Tree.lowBorder );
Tree.treeClip = SVGDoc.createElement("g");
Tree.treeClip.setAttribute("style", "clip-path:url(#treeClip);");
Tree.treeBox = SVGDoc.createElement("g");
Tree.treeBox.setAttribute("style", Tree.TEXT_STYLE);
Tree.treeClip.appendChild( Tree.treeBox );
Tree.lines = SVGDoc.createElement("path");
Tree.lines.setAttribute("style", Tree.LINES_STYLE);
Tree.linesData = "";
Tree.treeBox.appendChild( Tree.lines );
Tree.parent.appendChild( Tree.backBox );
Tree.parent.appendChild( Tree.treeClip );
}
/*****
*
* constructor: create node - create corresponding svg data
*
*****/
function Node(parentIndex, index, caption, collapsed) {
if ((!parentIndex) && (index == 0)) _root_init(this);
this.members = new Object();
this.members.caption = caption;
this.pIndex = parentIndex;
this.index = index;
this.collapsed = collapsed;
this.link = null;
this.more = null;
this.less = null;
this.end = null;
this.text = null;
this.box = null;
this.child = null;
this.next = null;
this.initNode();
}
/*****
*
* initNode: duplicate svg objects and append it to group
*
*****/
Node.prototype.initNode = function() {
var SVGDoc = Tree.parent.getOwnerDocument();
this.link = SVGDoc.createElement("a");
this.link.setAttribute("id", "_node_"+this.pIndex+this.index);
this.link.setAttribute("href", "JavaScript://");
this.link.setAttribute("style", "display:none;");
this.link.addEventListener("mousedown", selectNode, false);
this.more = SVGDoc.getElementById(Tree.ID_PLUS).cloneNode(true);
this.more.setAttribute("style", "display:none;");
this.link.appendChild( this.more );
this.less = SVGDoc.getElementById(Tree.ID_MINUS).cloneNode(true);
this.less.setAttribute("style", "display:none;");
this.link.appendChild( this.less );
this.end = SVGDoc.getElementById(Tree.ID_END).cloneNode(true);
this.end.setAttribute("style", "display:none;");
this.link.appendChild( this.end );
this.box = SVGDoc.createElement("rect");
this.box.setAttribute("style", "display:none;");
this.link.appendChild( this.box );
this.text = SVGDoc.createElement("text");
this.text.setAttribute("x", Tree.TEXT_XOFFSET);
this.text.setAttribute("y", Tree.TEXT_YOFFSET);
this.text.setAttribute("style", "display:none;"+Tree.TEXT_NORMAL);
this.text.appendChild(SVGDoc.createTextNode(this.members.caption));
this.link.appendChild( this.text );
Tree.treeBox.appendChild( this.link );
}
/*****
*
* addNext: recursive find the last brother item and add a new node
*
*****/
Node.prototype.addNext = function(caption, collapsed) {
if (this.next) return this.next.addNext(caption, collapsed);
else {
this.next = new Node(this.pIndex,this.index+1, caption, collapsed);
return this.next;
}
}
/*****
*
* addChild: ask the child to add a brother node
*
*****/
Node.prototype.addChild = function(caption, collapsed) {
if (this.pIndex.length+1 > Tree.depth) Tree.depth = this.pIndex.length+1;
if (this.child) return this.child.addNext(caption, collapsed);
else {
this.child = new Node(this.pIndex+this.index,0, caption, collapsed);
return this.child;
}
}
/*****
*
* organize: recursive show/hide and set position of nodes
*
*****/
Node.prototype.organize = function(visible, x,y) {
this.x = x;
this.y = y;
if (!visible) {
this.link.setAttribute("style", "display:none");
if (this.child) this.child.organize(false,0,0, true);
if (this.next) this.next.organize(false,0,0, false);
return 0;
}
if (this.pIndex)
Tree.linesData +=
"M" + (x-Tree.CHILD_TAB+.5) + "," + (y-Tree.ITEM_HEIGHT+.5) + "v" + (Tree.ITEM_HEIGHT)
+ "M" + (x+.5) + "," + (y+.5) + "h-" + (Tree.CHILD_TAB);
if (!this.child) {
this.more.setAttribute("style", "display:none;");
this.less.setAttribute("style", "display:none;");
this.end.setAttribute("style", "");
}
else if (this.collapsed) {
this.more.setAttribute("style", "");
this.less.setAttribute("style", "display:none;");
this.end.setAttribute("style", "display:none;");
}
else {
this.more.setAttribute("style", "display:none;");
this.less.setAttribute("style", "display:visible;");
this.end.setAttribute("style", "display:none;");
}
if (this.selected)
this.text.setAttribute("style", "display:visible;"+Tree.TEXT_SELECT); else
this.text.setAttribute("style", "display:visible;"+Tree.TEXT_NORMAL);
var b = this.text.getBBox();
this.box.setAttribute("x",b.x-3);
this.box.setAttribute("y",b.y-3);
this.box.setAttribute("width",b.width+6);
this.box.setAttribute("height",b.height+4);
if (this.selected)
this.box.setAttribute("style", "display:visible;"+Tree.SELBOX_STYLE); else
this.box.setAttribute("style", "display:visible;"+Tree.HIDE_STYLE+Tree.SELBOX_STYLE);
var t = x+b.x+b.width;
if (t > Tree.maxX) Tree.maxX = t;
var t = y+b.y+b.height;
if (t > Tree.maxY) Tree.maxY = t;
this.link.setAttribute("transform", "translate("+x+","+y+")");
this.link.setAttribute("style", "display:visible;");
if (this.child) {
var h = this.child.organize( (visible && !this.collapsed), x+Tree.CHILD_TAB,y+Tree.ITEM_HEIGHT);
if (!this.collapsed && this.next)
Tree.linesData += "M" + (x-Tree.CHILD_TAB+.5) + "," + (y+.5) + "v" + h;
}
else var h = 0;
if (this.next)
return this.next.organize( visible, x,y+Tree.ITEM_HEIGHT+h) + Tree.ITEM_HEIGHT+h;
else {
if (!this.pIndex) Tree.lines.setAttribute("d",Tree.linesData);
return Tree.ITEM_HEIGHT+h;
}
}
/*****
*
* setSelected: select node, unselect previous node
*
*****/
Node.prototype.setSelected = function(state,update) {
// unselect previous node
if ((Tree.current) && (Tree.current != this)) Tree.current.selected = false;
// select node
this.selected = state;
if (state)
Tree.current = this;
else {
Tree.current = null;
//this.box.setAttribute("style", Tree.HIDE_STYLE);
}
// is asked, update
if (update) updateTree(true);
}
/*****
*
* getChild: return child #n of node
*
*****/
Node.prototype.getChild = function(index) {
if (!this.child) return null;
var n = this.child;
for (var i=0; i<index; i++)
if (!n.next) return null;
else n = n.next;
return n;
}
/*****
*
* selectNode: event click on node - collapse if has child - select if click on text
*
*****/
function selectNode(event) {
var obj = event.getTarget().getParentNode().getParentNode();
var id = obj.getAttribute("id").split("_");
var sel = false;
if (id[1]!="node") {
obj = event.getTarget().getParentNode();
id = obj.getAttribute("id").split("_");
sel = true;
}
var path = id[2];
var n = Tree.root;
if (path!="0")
for (var i=1; i<path.length; i++) {
n = n.getChild( parseInt(path.charAt(i)) );
if (!n) break;
}
if (n) {
if (!sel) n.collapsed = !n.collapsed;
var p = Tree.current;
if (sel) n.setSelected(true,false);
updateTree(true);
if ((sel) && (Tree.callBack))
if (p) Tree.callBack(event,n.members,p.members); else Tree.callBack(event,n.members,null);
}
}
/*****
*
* scrollbars events
*
*****/
var hmoving = false;
var hoffs = 0;
var vmoving = false;
var voffs = 0;
var root;
function set_hScroll(h) {
Tree.hScroll = h;
if (Tree.hScroll < 0) Tree.hScroll = 0;
if (Tree.hScroll > Tree.maxScrollX) Tree.hScroll = Tree.maxScrollX;
Tree.hSb.setAttribute("transform",
"translate("+(Tree.x+hPos())+","+(Tree.y+Tree.height-1-Tree.BUTTON_SIZE)+")");
Tree.treeBox.setAttribute("transform",
"translate(-"+Math.floor(Tree.hScroll)+",-"+Math.floor(Tree.vScroll)+")");
}
function set_vScroll(v) {
Tree.vScroll = v;
if (Tree.vScroll < 0) Tree.vScroll = 0;
if (Tree.vScroll > Tree.maxScrollY) Tree.vScroll = Tree.maxScrollY;
Tree.vSb.setAttribute("transform",
"translate("+(Tree.x+Tree.width-1-Tree.BUTTON_SIZE)+","+(Tree.y+vPos()+1)+")");
Tree.treeBox.setAttribute("transform",
"translate(-"+Math.floor(Tree.hScroll)+",-"+Math.floor(Tree.vScroll)+")");
}
function hPos() {
// horiz sb button x
if (Tree.maxScrollX <= 0) return 0;
if (Tree.hScroll > Tree.maxScrollX) Tree.hScroll = Tree.maxScrollX;
return (Tree.xAvail-Tree.BUTTON_SIZE)*Tree.hScroll/Tree.maxScrollX;
}
function vPos() {
// vert sb button y
if (Tree.maxScrollY <= 0) return 0;
if (Tree.vScroll > Tree.maxScrollY) Tree.vScroll = Tree.maxScrollY;
return (Tree.yAvail-Tree.BUTTON_SIZE)*Tree.vScroll/Tree.maxScrollY;
}
function sb_down(evt) {
root = evt.getTarget().getOwnerDocument().getDocumentElement();
var x = (evt.clientX-root.currentTranslate.x)/root.currentScale - Tree.x-1;
var y = (evt.clientY-root.currentTranslate.y)/root.currentScale - Tree.y-1;
// horiz sb
if (Tree.hBar && (y >= Tree.yAvail)) {
var p = hPos();
hmoving = (Tree.hBar && (x >= p) && (x <= p+Tree.BUTTON_SIZE));
hoffs = x-p;
if (!hmoving) // page jump
if (hoffs > 0)
set_hScroll(Tree.hScroll+Tree.pageSizeX); else
set_hScroll(Tree.hScroll-Tree.pageSizeX);
}
// vert sb
else {
var p = vPos();
vmoving = (Tree.vBar && (y >= p) && (y <= p+Tree.BUTTON_SIZE));
voffs = y-p;
if (!vmoving) // page jump
if (voffs > 0)
set_vScroll(Tree.vScroll+Tree.pageSizeY); else
set_vScroll(Tree.vScroll-Tree.pageSizeY);
}
// prepare to move
if (hmoving || vmoving) {
root.addEventListener("mousemove",sb_move,false);
root.addEventListener("mouseup", sb_up,false);
}
}
function sb_move(evt) {
if (hmoving) {
var x = (evt.clientX-root.currentTranslate.x)/root.currentScale - Tree.x-1;
set_hScroll(Tree.maxScrollX*(x-hoffs)/(Tree.xAvail-Tree.BUTTON_SIZE));
}
else
if (vmoving) {
var y = (evt.clientY-root.currentTranslate.y)/root.currentScale - Tree.y-1;
set_vScroll(Tree.maxScrollY*(y-voffs)/(Tree.yAvail-Tree.BUTTON_SIZE));
}
}
function sb_up(evt) {
root.removeEventListener("mousemove",sb_move,false);
root.removeEventListener("mouseup", sb_up,false);
hmoving = false;
vmoving = false;
}
/*****
*
* super-tiny XML parser
*
*****/
var tokens;
var curr_index;
var collapsedDefault;
// *** parse XML text ***
function parse(parent,text,collapsed) {
Tree.parent = parent;
tokens = tokenize(text);
collapsedDefault = collapsed;
curr_index = 1; // first token always empty
parse_tags(null);
}
// *** find caption attribut in token[curr_index] ***
function get_caption() {
for (var i=1; i<tokens[curr_index].length; i++)
if (tokens[curr_index][i][0] == "caption")
return tokens[curr_index][i][1].substr(1, tokens[curr_index][i][1].length-2 );
}
// *** add all other attributs in token[curr_index] ***
function add_attributs(node) {
for (var i=1; i<tokens[curr_index].length; i++)
if ((tokens[curr_index][i][0] != "/") && (tokens[curr_index][i][0] != "caption"))
eval("node.members."+tokens[curr_index][i][0]+"="+tokens[curr_index][i][1]+";");
}
// *** recursive parsing ***
function parse_tags(parentNode) {
if ((curr_index < tokens.length) && (tokens[curr_index].length >= 0)) {
// if closing tag, stop
if (tokens[curr_index][0][0].charAt(0) == "/") return;
else {
// if node element
if (tokens[curr_index][0][0] == "item") {
// if no root node
if (!Tree.root) {
Tree.root = new Node("",0, get_caption(), collapsedDefault);
parentNode = Tree.root;
var n = Tree.root;
}
// create new node
else var n = parentNode.addChild(get_caption(),collapsedDefault);
add_attributs(n);
}
// if element has children
if (tokens[curr_index][tokens[curr_index].length-1] != "/") {
curr_index++;
parse_tags(n);
}
// parse next element
curr_index++;
parse_tags(parentNode);
}
}
}
// *** split XML string ***
function tokenize(text) {
// cleaning xml
res = clean(text).split("<");
// split /tag and /attributs
for (var i=0; i<res.length; i++) {
if (res[i].length > 0) res[i] = res[i].split(" ");
for (var j=0; j<res[i].length; j++) {
if (res[i][j].length > 0) {
res[i][j] = res[i][j].split("=");
if (res[i][j][1]) res[i][j][1] = restaureSpaces(res[i][j][1]);
}
}
}
return res;
}
// *** restaure spaces converted to _
function restaureSpaces(s) {
var res = "";
var c;
for (var i=0; i < s.length; i++) {
c = s.charAt(i);
if (c != "_") res += c; else res += " ";
}
return res;
}
// *** clean XML string ***
function clean(s) {
var i = 0;
var c;
var res = "";
var save = 0;
var nosp;
while (i < s.length) {
// skip blank
nosp = 0;
c = s.charAt(i);
while ((i < s.length) &&
(c==" ") || (c=="\n") || (c=="\t") || (c=="=") || (c==">") || (c=="/")) {
if (c=="=") { res += "="; nosp=1; }
if (c=="/") {
if (res.charAt(res.length-1)=="<") res += "/"; else res += " /";
nosp=1;
}
if (c==">") { nosp=1; }
if (save) res += "_";
i++; c = s.charAt(i);
}
if (!nosp && !save) res += " ";
// get word
while ((i < s.length) &&
(c!=" ") && (c!="\n") && (c!="\t") && (c!="=") && (c!=">") && (c!="/")) {
res += c;
if (c == '\"') save = 1-save;
i++; c = s.charAt(i);
}
}
return res;
}
var SVGDoc;
var SVGRoot;
var root = null;
var sizeBox = null;
var moving = false;
var x = 0;
var y = 0;
var sizeX = 0;
var sizeY = 0;
var xml = '<item caption="Node: Top" id="0">'
+' <item caption="Node Top.1" id="1">'
+' <item caption="Node Top.1.1" id="2">'
+' <item caption="Node Top.1.1.1" id="3">'
+' <item caption="Node Top.1.1.1.1" id="1">'
+' <item caption="Node Top.1.1.1.1.1" id="2">'
+' <item caption="Node Top.1.1.1.1.1.1" id="3"/>'
+' </item>'
+' <item caption="Node Top.1.1.1.1.2" id="4" />'
+' </item>'
+' <item caption="Node Top.1.1.1.2" id="5" />'
+' <item caption="Node Top.1.1.1.3" id="6">'
+' <item caption="Node Top.1.1.1.3.1" id="7"/>'
+' </item>'
+' </item>'
+' </item>'
+' <item caption="Node Top.1.2" id="4" />'
+' </item>'
+' <item caption="Node Top.2" id="5" />'
+' <item caption="Node Top.3" id="6">'
+' <item caption="Node Top.3.1" id="7"/>'
+' </item>'
+' <item caption="Node Top.4" id="1">'
+' <item caption="Node Top.4.1" id="2">'
+' <item caption="Node Top.4.1.1" id="3">'
+' <item caption="Node Top.4.1.1.1" id="1">'
+' <item caption="Node Top.4.1.1.1.1" id="2">'
+' <item caption="Node Top.4.1.1.1.1.1" id="3">'
+' <item caption="Node Top.4.1.1.1.1.1.1" id="1">'
+' <item caption="Node Top.4.1.1.1.1.1.1.1" id="2">'
+' <item caption="Node Top.4.1.1.1.1.1.1.1.1" id="3"/>'
+' </item>'
+' <item caption="I\'m small ;)" id="4" />'
+' </item>'
+' <item caption="Node Top.4.1.1.1.1.1.2" id="5" />'
+' <item caption="Node Top.4.1.1.1.1.1.3" id="6">'
+' <item caption="Node Top.4.1.1.1.1.1.3.1" id="7"/>'
+' </item>'
+' </item>'
+' </item>'
+' <item caption="Node Top.4.1.1.1.2" id="4" />'
+' </item>'
+' <item caption="Node Top.4.1.1.2" id="5" />'
+' <item caption="Node Top.4.1.1.3" id="6">'
+' <item caption="Node Top.4.1.1.3.1" id="7"/>'
+' </item>'
+' </item>'
+' </item>'
+' <item caption="Node Top.4.2" id="4" />'
+' </item>'
+' <item caption="Node Top.5" id="5">'
+' <item caption="Node Top.5.1" id="1">'
+' <item caption="Node Top.5.1.1" id="2">'
+' <item caption="Node Top.5.1.1.1" id="3"/>'
+' </item>'
+' <item caption="Node Top.5.1.2" id="4" />'
+' </item>'
+' <item caption="Node Top.5.2" id="5" />'
+' <item caption="Node Top.5.3" id="6">'
+' <item caption="Node Top.5.3.1" id="7"/>'
+' </item>'
+' </item>'
+' <item caption="Node Top.6" id="6">'
+' <item caption="Node Top.6.1" id="7"/>'
+' </item>'
+'</item>';
function nodeClick(evt,node,prev) {
SVGDoc.getElementById("info").getFirstChild.setData
("CallBack with selected node {caption:"+node.caption+", id:"+node.id+"}");
}
function init(evt,truc) {
SVGDoc = evt.getTarget().getOwnerDocument();
SVGRoot = SVGDoc.getDocumentElement();
parse(SVGDoc.getElementById("tree"),xml,false);
Tree.root.collapsed = false;
Tree.callBack = nodeClick;
updateTree(true,10,10,300,300);
root=SVGDoc.getElementById("root");
root.addEventListener("mousemove", onmove, false);
root.addEventListener("mousedown", ondown, false);
root.addEventListener("mouseup", onup, false);
sizeBox=SVGDoc.getElementById("sizeBox");
sizeX = Tree.x+Tree.width;
sizeY = Tree.y+Tree.height;
sizeBox.setAttribute("x",sizeX);
sizeBox.setAttribute("y",sizeY);
}
function ondown(evt) {
moving = ( (x >= sizeX) && (x < sizeX+4) && (y >= sizeY) && (y < sizeY+5) );
}
function onmove(evt) {
x = (evt.clientX-root.currentTranslate.x)/root.currentScale;
y = (evt.clientY-root.currentTranslate.y)/root.currentScale;
if (moving) {
if (x < Tree.x+50) x = Tree.x+50;
if (y < Tree.y+50) y = Tree.y+50;
sizeX = x-2;
sizeY = y-2;
sizeBox.setAttribute("x",sizeX);
sizeBox.setAttribute("y",sizeY);
updateTree(false,Tree.x,Tree.y,x-Tree.x-2,y-Tree.y-2);
}
}
function onup(evt) {
moving = false;
}
]]></script>
<defs>
<g id="tree_plus">
<image x="-8" y="-6" width="16" height="13" xlink:href="fclose.png" />
</g>
<g id="tree_minus">
<image x="-8" y="-6" width="16" height="13" xlink:href="fopen.png" />
</g>
<g id="tree_end">
<image x="-2" y="-5" width="9" height="10" xlink:href="file.png" />
</g>
<g id="tree_button">
<rect x="0" y="0" width="12" height="12" style="fill:silver;stroke:none;shape-rendering:optimizeSpeed;" />
<path d="M1,12v-11h11" style="fill:none;stroke:white;stroke-width:1;shape-rendering:optimizeSpeed;" />
<path d="M1,11h10v-10" style="fill:none;stroke:gray;stroke-width:1;shape-rendering:optimizeSpeed;" />
<path d="M0,12h12v-12" style="fill:none;stroke:black;stroke-width:1;shape-rendering:optimizeSpeed;" />
</g>
</defs>
<rect x="0" y="0" width="320" height="320" style="stroke:none;fill:darkblue;" mousemove="onmove(evt);" />
<rect id="sizeBox" x="-10" y="-10" width="4" height="5" style="stroke:none;fill:red;" />
<g style="font-family:Arial;font-size:10pt;fill:black;text-rendering:optimizeLegibility;pointer-events:none;">
<text id="info" x="30" y="75" style="fill:#ff3300;"> </text>
</g>
<g style="font-family:Arial;font-size:10pt;fill:blue;text-rendering:optimizeLegibility;">
</g>
<g id="tree"></g>
</g>
</svg>