var labelType, useGradients, nativeTextSupport, animate; (function() { var ua = navigator.userAgent, iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i), typeOfCanvas = typeof HTMLCanvasElement, nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'), textSupport = nativeCanvasSupport && (typeof document.createElement('canvas').getContext('2d').fillText == 'function'); //I'm setting this based on the fact that ExCanvas provides text support for IE //and that as of today iPhone/iPad current text support is lame labelType = (!nativeCanvasSupport || (textSupport && !iStuff))? 'Native' : 'HTML'; nativeTextSupport = labelType == 'Native'; useGradients = nativeCanvasSupport; animate = !(iStuff || !nativeCanvasSupport); })(); var Log = { elem: false, write: function(text){ if (!this.elem) this.elem = document.getElementById('log'); this.elem.innerHTML = text; this.elem.style.left = (500 - this.elem.offsetWidth / 2) + 'px'; } }; function init(){ //init data var json = { id: "node02", name: "0.2", children: [{ id: "node13", name: "1.3", children: [{ id: "node24", name: "2.4" }, { id: "node222", name: "2.22" }] }, { id: "node125", name: "1.25", children: [{ id: "node226", name: "2.26" }, { id: "node237", name: "2.37" }, { id: "node258", name: "2.58" }] }, { id: "node165", name: "1.65", children: [{ id: "node266", name: "2.66" }, { id: "node283", name: "2.83" }, { id: "node2104", name: "2.104" }, { id: "node2109", name: "2.109" }, { id: "node2125", name: "2.125" }] }, { id: "node1130", name: "1.130", children: [{ id: "node2131", name: "2.131" }, { id: "node2138", name: "2.138" }] }] }; //end //init Node Types //Create a node rendering function that plots a fill //rectangle and a stroke rectangle for borders $jit.ST.Plot.NodeTypes.implement({ 'stroke-rect': { 'render': function(node, canvas) { var width = node.getData('width'), height = node.getData('height'), pos = this.getAlignedPos(node.pos.getc(true), width, height), posX = pos.x + width/2, posY = pos.y + height/2; this.nodeHelper.rectangle.render('fill', {x: posX, y: posY}, width, height, canvas); this.nodeHelper.rectangle.render('stroke', {x: posX, y: posY}, width, height, canvas); } } }); //end //init Spacetree //Create a new ST instance var st = new $jit.ST({ //id of viz container element injectInto: 'infovis', //set distance between node and its children levelDistance: 50, //set an X offset offsetX: 130, //set node, edge and label styles //set overridable=true for styling individual //nodes or edges Node: { overridable: true, type: 'stroke-rect', height: 20, width: 60, //canvas specific styles CanvasStyles: { fillStyle: '#daa', strokeStyle: '#ffc', lineWidth: 2 } }, Edge: { overridable: true, type: 'line', color: '#ffc', lineWidth: 1 }, Label: { type: labelType, style: 'bold', size: 10, color: '#333' }, //This method is called on DOM label creation. //Use this method to add event handlers and styles to //your node. onCreateLabel: function(label, node){ label.innerHTML = node.name; //set label styles var style = label.style; style.width = 60 + 'px'; style.height = 17 + 'px'; style.color = '#333'; style.fontSize = '0.8em'; style.textAlign= 'center'; style.paddingTop = '3px'; }, onPlaceLabel: function(label, node) { var style = label.style; style.width = node.getData('width') + 'px'; style.height = node.getData('height') + 'px'; style.color = node.getLabelData('color'); style.fontSize = node.getLabelData('size') + 'px'; style.textAlign= 'center'; style.paddingTop = '3px'; } }); //load json data st.loadJSON(json); //compute node positions and layout st.compute(); //emulate a click on the root node. st.onClick(st.root); //end //Add Select All/None actions var nodeAll = $jit.id('select-all-nodes'), nodeNone = $jit.id('select-none-nodes'), edgeAll = $jit.id('select-all-edges'), edgeNone = $jit.id('select-none-edges'), labelAll = $jit.id('select-all-labels'), labelNone = $jit.id('select-none-labels'); $jit.util.each([nodeAll, edgeAll, labelAll], function(elem) { elem.onclick = function() { var pn = elem.parentNode.parentNode.parentNode; //table var inputs = pn.getElementsByTagName('input'); for(var i=0, l=inputs.length; i<l; i++) { if(inputs[i].type == 'checkbox') { inputs[i].checked = true; } } }; }); $jit.util.each([nodeNone, edgeNone, labelNone], function(elem) { elem.onclick = function() { var pn = elem.parentNode.parentNode.parentNode; //table var inputs = pn.getElementsByTagName('input'); for(var i=0, l=inputs.length; i<l; i++) { if(inputs[i].type == 'checkbox') { inputs[i].checked = false; } } }; }); //get checkboxes var nWidth = $jit.id('n-width'), nHeight = $jit.id('n-height'), nColor = $jit.id('n-color'), nBorderColor = $jit.id('n-border-color'), nBorderWidth = $jit.id('n-border-width'), eLineWidth = $jit.id('e-line-width'), eLineColor = $jit.id('e-line-color'), lFontSize = $jit.id('l-font-size'), lFontColor = $jit.id('l-font-color'); //init Morphing Animations var button = $jit.id('update'), restore = $jit.id('restore'), rand = Math.random, floor = Math.floor, colors = ['#33a', '#55b', '#77c', '#99d', '#aae', '#bf0', '#cf5', '#dfa', '#faccff', '#ffccff', '#CCC', '#C37'], colorLength = colors.length; //add click event for restore $jit.util.addEvent(restore, 'click', function() { if(init.busy) return; init.busy = true; st.graph.eachNode(function(n) { //restore width and height node styles n.setDataset('end', { width: 60, height: 20 }); //restore canvas specific styles n.setCanvasStyles('end', { fillStyle: '#daa', strokeStyle: '#ffc', lineWidth: 2 }); //restore font styles n.setLabelDataset('end', { size: 10, color: '#333' }); //set adjacencies styles n.eachAdjacency(function(adj) { adj.setDataset('end', { lineWidth: 1, color: '#ffc' }); }); }); st.compute('end'); st.geom.translate({x:-130, y:0}, 'end'); st.fx.animate({ modes: ['linear', 'node-property:width:height', 'edge-property:lineWidth:color', 'label-property:size:color', 'node-style:fillStyle:strokeStyle:lineWidth'], duration: 1500, onComplete: function() { init.busy = false; } }); }); //add click event for updating styles $jit.util.addEvent(button, 'click', function() { if(init.busy) return; init.busy = true; st.graph.eachNode(function(n) { //set random width and height node styles nWidth.checked && n.setData('width', floor(rand() * 40 + 20), 'end'); nHeight.checked && n.setData('height', floor(rand() * 40 + 20), 'end'); //set random canvas specific styles nColor.checked && n.setCanvasStyle('fillStyle', colors[floor(colorLength * rand())], 'end'); nBorderColor.checked && n.setCanvasStyle('strokeStyle', colors[floor(colorLength * rand())], 'end'); nBorderWidth.checked && n.setCanvasStyle('lineWidth', 10 * rand() + 1, 'end'); //set label styles lFontSize.checked && n.setLabelData('size', 20 * rand() + 1, 'end'); lFontColor.checked && n.setLabelData('color', colors[floor(colorLength * rand())], 'end'); //set adjacency styles n.eachAdjacency(function(adj) { eLineWidth.checked && adj.setData('lineWidth', 10 * rand() + 1, 'end'); eLineColor.checked && adj.setData('color', colors[floor(colorLength * rand())], 'end'); }); }); st.compute('end'); st.geom.translate({x:-130, y:0}, 'end'); st.fx.animate({ modes: ['linear', 'node-property:width:height', 'edge-property:lineWidth:color', 'label-property:size:color', 'node-style:fillStyle:strokeStyle:lineWidth'], duration: 1500, onComplete: function() { init.busy = false; } }); }); //end }