diff --git a/.gitignore b/.gitignore index a8a8bac..4e9aeda 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ .project .pydevproject +Examples +Jit +Extras/sh/ NaturalDocs* Docs* *.pyc diff --git a/Extras/code.css b/Extras/code.css new file mode 100644 index 0000000..5b461db --- /dev/null +++ b/Extras/code.css @@ -0,0 +1,42 @@ +html, body { + margin:0; + padding:0; + font-family: "Lucida Grande", Verdana; + font-size: 0.9em; + text-align: center; + background-color:#F2F2F2; +} + +h4 { + font-size:1.1em; + text-decoration:none; + font-weight:normal; + color:#23A4FF; +} + +#container { + width: 900px; + margin:0 auto; + background-color:white; + border:1px solid #ccc; +} + +#center-container { + text-align:left; + width:800px; + color:#888; + margin:auto; +} + +.headtext { + text-align:justify; + width:500px; + margin:20px auto; +} + +.code-wrapper { + width:750px; + margin:5px auto; + overflow:auto; + margin-bottom:30px +} diff --git a/Extras/excanvas.js b/Extras/excanvas.js index 367764b..a34ca1d 100644 --- a/Extras/excanvas.js +++ b/Extras/excanvas.js @@ -11,914 +11,25 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. - - -// Known Issues: -// -// * Patterns are not implemented. -// * Radial gradient are not implemented. The VML version of these look very -// different from the canvas one. -// * Clipping paths are not implemented. -// * Coordsize. The width and height attribute have higher priority than the -// width and height style values which isn't correct. -// * Painting mode isn't implemented. -// * Canvas width/height should is using content-box by default. IE in -// Quirks mode will draw the canvas using border-box. Either change your -// doctype to HTML5 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) -// or use Box Sizing Behavior from WebFX -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) -// * Non uniform scaling does not correctly scale strokes. -// * Optimize. There is always room for speed improvements. - -// Only add this code if we do not already have a canvas implementation -if (!document.createElement('canvas').getContext) { - -(function() { - - // alias some functions to make (compiled) code shorter - var m = Math; - var mr = m.round; - var ms = m.sin; - var mc = m.cos; - var abs = m.abs; - var sqrt = m.sqrt; - - // this is used for sub pixel precision - var Z = 10; - var Z2 = Z / 2; - - /** - * This funtion is assigned to the elements as element.getContext(). - * @this {HTMLElement} - * @return {CanvasRenderingContext2D_} - */ - function getContext() { - return this.context_ || - (this.context_ = new CanvasRenderingContext2D_(this)); - } - - var slice = Array.prototype.slice; - - /** - * Binds a function to an object. The returned function will always use the - * passed in {@code obj} as {@code this}. - * - * Example: - * - * g = bind(f, obj, a, b) - * g(c, d) // will do f.call(obj, a, b, c, d) - * - * @param {Function} f The function to bind the object to - * @param {Object} obj The object that should act as this when the function - * is called - * @param {*} var_args Rest arguments that will be used as the initial - * arguments when the function is called - * @return {Function} A new function that has bound this - */ - function bind(f, obj, var_args) { - var a = slice.call(arguments, 2); - return function() { - return f.apply(obj, a.concat(slice.call(arguments))); - }; - } - - var G_vmlCanvasManager_ = { - init: function(opt_doc) { - if (/MSIE/.test(navigator.userAgent) && !window.opera) { - var doc = opt_doc || document; - // Create a dummy element so that IE will allow canvas elements to be - // recognized. - doc.createElement('canvas'); - doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); - } - }, - - init_: function(doc) { - // create xmlns - if (!doc.namespaces['g_vml_']) { - doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml', - '#default#VML'); - - } - if (!doc.namespaces['g_o_']) { - doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office', - '#default#VML'); - } - - // Setup default CSS. Only add one style sheet per document - if (!doc.styleSheets['ex_canvas_']) { - var ss = doc.createStyleSheet(); - ss.owningElement.id = 'ex_canvas_'; - ss.cssText = 'canvas{display:inline-block;overflow:hidden;' + - // default size is 300x150 in Gecko and Opera - 'text-align:left;width:300px;height:150px}' + - 'g_vml_\\:*{behavior:url(#default#VML)}' + - 'g_o_\\:*{behavior:url(#default#VML)}'; - - } - - // find all canvas elements - var els = doc.getElementsByTagName('canvas'); - for (var i = 0; i < els.length; i++) { - this.initElement(els[i]); - } - }, - - /** - * Public initializes a canvas element so that it can be used as canvas - * element from now on. This is called automatically before the page is - * loaded but if you are creating elements using createElement you need to - * make sure this is called on the element. - * @param {HTMLElement} el The canvas element to initialize. - * @return {HTMLElement} the element that was created. - */ - initElement: function(el) { - if (!el.getContext) { - - el.getContext = getContext; - - // Remove fallback content. There is no way to hide text nodes so we - // just remove all childNodes. We could hide all elements and remove - // text nodes but who really cares about the fallback content. - el.innerHTML = ''; - - // do not use inline function because that will leak memory - el.attachEvent('onpropertychange', onPropertyChange); - el.attachEvent('onresize', onResize); - - var attrs = el.attributes; - if (attrs.width && attrs.width.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setWidth_(attrs.width.nodeValue); - el.style.width = attrs.width.nodeValue + 'px'; - } else { - el.width = el.clientWidth; - } - if (attrs.height && attrs.height.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setHeight_(attrs.height.nodeValue); - el.style.height = attrs.height.nodeValue + 'px'; - } else { - el.height = el.clientHeight; - } - //el.getContext().setCoordsize_() - } - return el; - } - }; - - function onPropertyChange(e) { - var el = e.srcElement; - - switch (e.propertyName) { - case 'width': - el.style.width = el.attributes.width.nodeValue + 'px'; - el.getContext().clearRect(); - break; - case 'height': - el.style.height = el.attributes.height.nodeValue + 'px'; - el.getContext().clearRect(); - break; - } - } - - function onResize(e) { - var el = e.srcElement; - if (el.firstChild) { - el.firstChild.style.width = el.clientWidth + 'px'; - el.firstChild.style.height = el.clientHeight + 'px'; - } - } - - G_vmlCanvasManager_.init(); - - // precompute "00" to "FF" - var dec2hex = []; - for (var i = 0; i < 16; i++) { - for (var j = 0; j < 16; j++) { - dec2hex[i * 16 + j] = i.toString(16) + j.toString(16); - } - } - - function createMatrixIdentity() { - return [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]; - } - - function matrixMultiply(m1, m2) { - var result = createMatrixIdentity(); - - for (var x = 0; x < 3; x++) { - for (var y = 0; y < 3; y++) { - var sum = 0; - - for (var z = 0; z < 3; z++) { - sum += m1[x][z] * m2[z][y]; - } - - result[x][y] = sum; - } - } - return result; - } - - function copyState(o1, o2) { - o2.fillStyle = o1.fillStyle; - o2.lineCap = o1.lineCap; - o2.lineJoin = o1.lineJoin; - o2.lineWidth = o1.lineWidth; - o2.miterLimit = o1.miterLimit; - o2.shadowBlur = o1.shadowBlur; - o2.shadowColor = o1.shadowColor; - o2.shadowOffsetX = o1.shadowOffsetX; - o2.shadowOffsetY = o1.shadowOffsetY; - o2.strokeStyle = o1.strokeStyle; - o2.globalAlpha = o1.globalAlpha; - o2.arcScaleX_ = o1.arcScaleX_; - o2.arcScaleY_ = o1.arcScaleY_; - o2.lineScale_ = o1.lineScale_; - } - - function processStyle(styleString) { - var str, alpha = 1; - - styleString = String(styleString); - if (styleString.substring(0, 3) == 'rgb') { - var start = styleString.indexOf('(', 3); - var end = styleString.indexOf(')', start + 1); - var guts = styleString.substring(start + 1, end).split(','); - - str = '#'; - for (var i = 0; i < 3; i++) { - str += dec2hex[Number(guts[i])]; - } - - if (guts.length == 4 && styleString.substr(3, 1) == 'a') { - alpha = guts[3]; - } - } else { - str = styleString; - } - - return {color: str, alpha: alpha}; - } - - function processLineCap(lineCap) { - switch (lineCap) { - case 'butt': - return 'flat'; - case 'round': - return 'round'; - case 'square': - default: - return 'square'; - } - } - - /** - * This class implements CanvasRenderingContext2D interface as described by - * the WHATWG. - * @param {HTMLElement} surfaceElement The element that the 2D context should - * be associated with - */ - function CanvasRenderingContext2D_(surfaceElement) { - this.m_ = createMatrixIdentity(); - - this.mStack_ = []; - this.aStack_ = []; - this.currentPath_ = []; - - // Canvas context properties - this.strokeStyle = '#000'; - this.fillStyle = '#000'; - - this.lineWidth = 1; - this.lineJoin = 'miter'; - this.lineCap = 'butt'; - this.miterLimit = Z * 1; - this.globalAlpha = 1; - this.canvas = surfaceElement; - - var el = surfaceElement.ownerDocument.createElement('div'); - el.style.width = surfaceElement.clientWidth + 'px'; - el.style.height = surfaceElement.clientHeight + 'px'; - el.style.overflow = 'hidden'; - el.style.position = 'absolute'; - surfaceElement.appendChild(el); - - this.element_ = el; - this.arcScaleX_ = 1; - this.arcScaleY_ = 1; - this.lineScale_ = 1; - } - - var contextPrototype = CanvasRenderingContext2D_.prototype; - contextPrototype.clearRect = function() { - this.element_.innerHTML = ''; - }; - - contextPrototype.beginPath = function() { - // TODO: Branch current matrix so that save/restore has no effect - // as per safari docs. - this.currentPath_ = []; - }; - - contextPrototype.moveTo = function(aX, aY) { - var p = this.getCoords_(aX, aY); - this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.lineTo = function(aX, aY) { - var p = this.getCoords_(aX, aY); - this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); - - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY) { - var p = this.getCoords_(aX, aY); - var cp1 = this.getCoords_(aCP1x, aCP1y); - var cp2 = this.getCoords_(aCP2x, aCP2y); - bezierCurveTo(this, cp1, cp2, p); - }; - - // Helper function that takes the already fixed cordinates. - function bezierCurveTo(self, cp1, cp2, p) { - self.currentPath_.push({ - type: 'bezierCurveTo', - cp1x: cp1.x, - cp1y: cp1.y, - cp2x: cp2.x, - cp2y: cp2.y, - x: p.x, - y: p.y - }); - self.currentX_ = p.x; - self.currentY_ = p.y; - } - - contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { - // the following is lifted almost directly from - // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes - - var cp = this.getCoords_(aCPx, aCPy); - var p = this.getCoords_(aX, aY); - - var cp1 = { - x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), - y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) - }; - var cp2 = { - x: cp1.x + (p.x - this.currentX_) / 3.0, - y: cp1.y + (p.y - this.currentY_) / 3.0 - }; - - bezierCurveTo(this, cp1, cp2, p); - }; - - contextPrototype.arc = function(aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { - aRadius *= Z; - var arcType = aClockwise ? 'at' : 'wa'; - - var xStart = aX + mc(aStartAngle) * aRadius - Z2; - var yStart = aY + ms(aStartAngle) * aRadius - Z2; - - var xEnd = aX + mc(aEndAngle) * aRadius - Z2; - var yEnd = aY + ms(aEndAngle) * aRadius - Z2; - - // IE won't render arches drawn counter clockwise if xStart == xEnd. - if (xStart == xEnd && !aClockwise) { - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - - var p = this.getCoords_(aX, aY); - var pStart = this.getCoords_(xStart, yStart); - var pEnd = this.getCoords_(xEnd, yEnd); - - this.currentPath_.push({type: arcType, - x: p.x, - y: p.y, - radius: aRadius, - xStart: pStart.x, - yStart: pStart.y, - xEnd: pEnd.x, - yEnd: pEnd.y}); - - }; - - contextPrototype.rect = function(aX, aY, aWidth, aHeight) { - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - }; - - contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.stroke(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.fill(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { - var gradient = new CanvasGradient_('gradient'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - return gradient; - }; - - contextPrototype.createRadialGradient = function(aX0, aY0, aR0, - aX1, aY1, aR1) { - var gradient = new CanvasGradient_('gradientradial'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.r0_ = aR0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - gradient.r1_ = aR1; - return gradient; - }; - - contextPrototype.drawImage = function(image, var_args) { - var dx, dy, dw, dh, sx, sy, sw, sh; - - // to find the original width we overide the width and height - var oldRuntimeWidth = image.runtimeStyle.width; - var oldRuntimeHeight = image.runtimeStyle.height; - image.runtimeStyle.width = 'auto'; - image.runtimeStyle.height = 'auto'; - - // get the original size - var w = image.width; - var h = image.height; - - // and remove overides - image.runtimeStyle.width = oldRuntimeWidth; - image.runtimeStyle.height = oldRuntimeHeight; - - if (arguments.length == 3) { - dx = arguments[1]; - dy = arguments[2]; - sx = sy = 0; - sw = dw = w; - sh = dh = h; - } else if (arguments.length == 5) { - dx = arguments[1]; - dy = arguments[2]; - dw = arguments[3]; - dh = arguments[4]; - sx = sy = 0; - sw = w; - sh = h; - } else if (arguments.length == 9) { - sx = arguments[1]; - sy = arguments[2]; - sw = arguments[3]; - sh = arguments[4]; - dx = arguments[5]; - dy = arguments[6]; - dw = arguments[7]; - dh = arguments[8]; - } else { - throw Error('Invalid number of arguments'); - } - - var d = this.getCoords_(dx, dy); - - var w2 = sw / 2; - var h2 = sh / 2; - - var vmlStr = []; - - var W = 10; - var H = 10; - - // For some reason that I've now forgotten, using divs didn't work - vmlStr.push(' ' , - '', - ''); - - this.element_.insertAdjacentHTML('BeforeEnd', - vmlStr.join('')); - }; - - contextPrototype.stroke = function(aFill) { - var lineStr = []; - var lineOpen = false; - var a = processStyle(aFill ? this.fillStyle : this.strokeStyle); - var color = a.color; - var opacity = a.alpha * this.globalAlpha; - - var W = 10; - var H = 10; - - lineStr.push(''); - - if (!aFill) { - var lineWidth = this.lineScale_ * this.lineWidth; - - // VML cannot correctly render a line if the width is less than 1px. - // In that case, we dilute the color to make the line look thinner. - if (lineWidth < 1) { - opacity *= lineWidth; - } - - lineStr.push( - '' - ); - } else if (typeof this.fillStyle == 'object') { - var fillStyle = this.fillStyle; - var angle = 0; - var focus = {x: 0, y: 0}; - - // additional offset - var shift = 0; - // scale factor for offset - var expansion = 1; - - if (fillStyle.type_ == 'gradient') { - var x0 = fillStyle.x0_ / this.arcScaleX_; - var y0 = fillStyle.y0_ / this.arcScaleY_; - var x1 = fillStyle.x1_ / this.arcScaleX_; - var y1 = fillStyle.y1_ / this.arcScaleY_; - var p0 = this.getCoords_(x0, y0); - var p1 = this.getCoords_(x1, y1); - var dx = p1.x - p0.x; - var dy = p1.y - p0.y; - angle = Math.atan2(dx, dy) * 180 / Math.PI; - - // The angle should be a non-negative number. - if (angle < 0) { - angle += 360; - } - - // Very small angles produce an unexpected result because they are - // converted to a scientific notation string. - if (angle < 1e-6) { - angle = 0; - } - } else { - var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_); - var width = max.x - min.x; - var height = max.y - min.y; - focus = { - x: (p0.x - min.x) / width, - y: (p0.y - min.y) / height - }; - - width /= this.arcScaleX_ * Z; - height /= this.arcScaleY_ * Z; - var dimension = m.max(width, height); - shift = 2 * fillStyle.r0_ / dimension; - expansion = 2 * fillStyle.r1_ / dimension - shift; - } - - // We need to sort the color stops in ascending order by offset, - // otherwise IE won't interpret it correctly. - var stops = fillStyle.colors_; - stops.sort(function(cs1, cs2) { - return cs1.offset - cs2.offset; - }); - - var length = stops.length; - var color1 = stops[0].color; - var color2 = stops[length - 1].color; - var opacity1 = stops[0].alpha * this.globalAlpha; - var opacity2 = stops[length - 1].alpha * this.globalAlpha; - - var colors = []; - for (var i = 0; i < length; i++) { - var stop = stops[i]; - colors.push(stop.offset * expansion + shift + ' ' + stop.color); - } - - // When colors attribute is used, the meanings of opacity and o:opacity2 - // are reversed. - lineStr.push(''); - } else { - lineStr.push(''); - } - - lineStr.push(''); - - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); - }; - - contextPrototype.fill = function() { - this.stroke(true); - } - - contextPrototype.closePath = function() { - this.currentPath_.push({type: 'close'}); - }; - - /** - * @private - */ - contextPrototype.getCoords_ = function(aX, aY) { - var m = this.m_; - return { - x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, - y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 - } - }; - - contextPrototype.save = function() { - var o = {}; - copyState(this, o); - this.aStack_.push(o); - this.mStack_.push(this.m_); - this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); - }; - - contextPrototype.restore = function() { - copyState(this.aStack_.pop(), this); - this.m_ = this.mStack_.pop(); - }; - - function matrixIsFinite(m) { - for (var j = 0; j < 3; j++) { - for (var k = 0; k < 2; k++) { - if (!isFinite(m[j][k]) || isNaN(m[j][k])) { - return false; - } - } - } - return true; - } - - function setM(ctx, m, updateLineScale) { - if (!matrixIsFinite(m)) { - return; - } - ctx.m_ = m; - - if (updateLineScale) { - // Get the line scale. - // Determinant of this.m_ means how much the area is enlarged by the - // transformation. So its square root can be used as a scale factor - // for width. - var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; - ctx.lineScale_ = sqrt(abs(det)); - } - } - - contextPrototype.translate = function(aX, aY) { - var m1 = [ - [1, 0, 0], - [0, 1, 0], - [aX, aY, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.rotate = function(aRot) { - var c = mc(aRot); - var s = ms(aRot); - - var m1 = [ - [c, s, 0], - [-s, c, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.scale = function(aX, aY) { - this.arcScaleX_ *= aX; - this.arcScaleY_ *= aY; - var m1 = [ - [aX, 0, 0], - [0, aY, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { - var m1 = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { - var m = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, m, true); - }; - - /******** STUBS ********/ - contextPrototype.clip = function() { - // TODO: Implement - }; - - contextPrototype.arcTo = function() { - // TODO: Implement - }; - - contextPrototype.createPattern = function() { - return new CanvasPattern_; - }; - - // Gradient / Pattern Stubs - function CanvasGradient_(aType) { - this.type_ = aType; - this.x0_ = 0; - this.y0_ = 0; - this.r0_ = 0; - this.x1_ = 0; - this.y1_ = 0; - this.r1_ = 0; - this.colors_ = []; - } - - CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { - aColor = processStyle(aColor); - this.colors_.push({offset: aOffset, - color: aColor.color, - alpha: aColor.alpha}); - }; - - function CanvasPattern_() {} - - // set up externs - G_vmlCanvasManager = G_vmlCanvasManager_; - CanvasRenderingContext2D = CanvasRenderingContext2D_; - CanvasGradient = CanvasGradient_; - CanvasPattern = CanvasPattern_; - -})(); - -} // if +document.createElement("canvas").getContext||(function(){var s=Math,j=s.round,F=s.sin,G=s.cos,V=s.abs,W=s.sqrt,k=10,v=k/2;function X(){return this.context_||(this.context_=new H(this))}var L=Array.prototype.slice;function Y(b,a){var c=L.call(arguments,2);return function(){return b.apply(a,c.concat(L.call(arguments)))}}var M={init:function(b){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var a=b||document;a.createElement("canvas");a.attachEvent("onreadystatechange",Y(this.init_,this,a))}},init_:function(b){b.namespaces.g_vml_|| +b.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML");b.namespaces.g_o_||b.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML");if(!b.styleSheets.ex_canvas_){var a=b.createStyleSheet();a.owningElement.id="ex_canvas_";a.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var c=b.getElementsByTagName("canvas"),d=0;for(;d','","");this.element_.insertAdjacentHTML("BeforeEnd",t.join(""))};i.stroke=function(b){var a=[],c=P(b?this.fillStyle:this.strokeStyle),d=c.color,f=c.alpha*this.globalAlpha;a.push("g.x)g.x=e.x;if(h.y==null||e.yg.y)g.y=e.y}}a.push(' ">');if(b)if(typeof this.fillStyle=="object"){var m=this.fillStyle,r=0,n={x:0,y:0},o=0,q=1;if(m.type_=="gradient"){var t=m.x1_/this.arcScaleX_,E=m.y1_/this.arcScaleY_,p=this.getCoords_(m.x0_/this.arcScaleX_,m.y0_/this.arcScaleY_), +z=this.getCoords_(t,E);r=Math.atan2(z.x-p.x,z.y-p.y)*180/Math.PI;if(r<0)r+=360;if(r<1.0E-6)r=0}else{var p=this.getCoords_(m.x0_,m.y0_),w=g.x-h.x,x=g.y-h.y;n={x:(p.x-h.x)/w,y:(p.y-h.y)/x};w/=this.arcScaleX_*k;x/=this.arcScaleY_*k;var R=s.max(w,x);o=2*m.r0_/R;q=2*m.r1_/R-o}var u=m.colors_;u.sort(function(ba,ca){return ba.offset-ca.offset});var J=u.length,da=u[0].color,ea=u[J-1].color,fa=u[0].alpha*this.globalAlpha,ga=u[J-1].alpha*this.globalAlpha,S=[],l=0;for(;l')}else a.push('');else{var K=this.lineScale_*this.lineWidth;if(K<1)f*=K;a.push("')}a.push("");this.element_.insertAdjacentHTML("beforeEnd",a.join(""))};i.fill=function(){this.stroke(true)};i.closePath=function(){this.currentPath_.push({type:"close"})};i.getCoords_=function(b,a){var c=this.m_;return{x:k*(b*c[0][0]+a*c[1][0]+c[2][0])-v,y:k*(b*c[0][1]+a*c[1][1]+c[2][1])-v}};i.save=function(){var b={};O(this,b);this.aStack_.push(b);this.mStack_.push(this.m_);this.m_=y(I(),this.m_)};i.restore=function(){O(this.aStack_.pop(), +this);this.m_=this.mStack_.pop()};function ha(b){var a=0;for(;a<3;a++){var c=0;for(;c<2;c++)if(!isFinite(b[a][c])||isNaN(b[a][c]))return false}return true}function A(b,a,c){if(!!ha(a)){b.m_=a;if(c)b.lineScale_=W(V(a[0][0]*a[1][1]-a[0][1]*a[1][0]))}}i.translate=function(b,a){A(this,y([[1,0,0],[0,1,0],[b,a,1]],this.m_),false)};i.rotate=function(b){var a=G(b),c=F(b);A(this,y([[a,c,0],[-c,a,0],[0,0,1]],this.m_),false)};i.scale=function(b,a){this.arcScaleX_*=b;this.arcScaleY_*=a;A(this,y([[b,0,0],[0,a, +0],[0,0,1]],this.m_),true)};i.transform=function(b,a,c,d,f,h){A(this,y([[b,a,0],[c,d,0],[f,h,1]],this.m_),true)};i.setTransform=function(b,a,c,d,f,h){A(this,[[b,a,0],[c,d,0],[f,h,1]],true)};i.clip=function(){};i.arcTo=function(){};i.createPattern=function(){return new U};function D(b){this.type_=b;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}D.prototype.addColorStop=function(b,a){a=P(a);this.colors_.push({offset:b,color:a.color,alpha:a.alpha})};function U(){}G_vmlCanvasManager= +M;CanvasRenderingContext2D=H;CanvasGradient=D;CanvasPattern=U})(); diff --git a/Source/AngularWidth.js b/Source/AngularWidth.js index 6927461..eb40292 100644 --- a/Source/AngularWidth.js +++ b/Source/AngularWidth.js @@ -21,14 +21,14 @@ var AngularWidth = { Sets nodes angular widths. */ setAngularWidthForNodes: function() { - var config = this.config; + var config = this.config.Node; var overridable = config.overridable; - var dim = config.Node.dim; + var dim = config.dim; Graph.Util.eachBFS(this.graph, this.root, function(elem, i) { var diamValue = (overridable && elem.data - && elem.data.$dim) || dim; + && elem.data.$aw) || dim; elem._angularWidth = diamValue / i; }, "ignore"); }, diff --git a/Source/Canvas.js b/Source/Canvas.js index 13c4e68..8b1e0a7 100644 --- a/Source/Canvas.js +++ b/Source/Canvas.js @@ -116,7 +116,6 @@ The _plot_ method is called for plotting a Canvas image. */ this.Canvas = (function () { - var ctx, bkctx, mainContainer, labelContainer, canvas, bkcanvas; var config = { 'injectInto': 'id', @@ -164,6 +163,7 @@ this.Canvas = (function () { }; return function(id, opt) { + var ctx, bkctx, mainContainer, labelContainer, canvas, bkcanvas; if(arguments.length < 1) throw "Arguments missing"; var idLabel = id + "-label", idCanvas = id + "-canvas", idBCanvas = id + "-bkcanvas"; opt = $merge(config, opt || {}); diff --git a/Source/Core.js b/Source/Core.js index fee2c33..88f816d 100644 --- a/Source/Core.js +++ b/Source/Core.js @@ -52,9 +52,6 @@ > SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -function $get(id) { - return document.getElementById(id); -}; function $empty() {}; @@ -144,6 +141,29 @@ function $clean(elem) { } }; +function $addEvent(obj, type, fn) { + if (obj.addEventListener) + obj.addEventListener(type, fn, false); + else + obj.attachEvent('on' + type, fn); +}; + +function $hasClass(obj, klass) { + return (' ' + obj.className + ' ').indexOf(' ' + klass + ' ') > -1; +}; + +function $addClass(obj, klass) { + if(!$hasClass(obj, klass)) obj.className = (obj.className + " " + klass); +}; + +function $removeClass(obj, klass) { + obj.className = obj.className.replace(new RegExp('(^|\\s)' + klass + '(?:\\s|$)'), '$1'); +}; + +function $get(id) { + return document.getElementById(id); +}; + var Class = function(properties){ properties = properties || {}; var klass = function(){ diff --git a/Source/Graph.Plot.js b/Source/Graph.Plot.js index 09edd30..ae4333e 100644 --- a/Source/Graph.Plot.js +++ b/Source/Graph.Plot.js @@ -356,7 +356,8 @@ Graph.Plot = { ctx = canvas.getCtx(), GUtil = Graph.Util; opt = opt || this.viz.controller; - canvas.clear(); + opt.clearCanvas && canvas.clear(); + var T = !!aGraph.getNode(id).visited; GUtil.eachNode(aGraph, function(node) { GUtil.eachAdjacency(node, function(adj) { @@ -365,7 +366,7 @@ Graph.Plot = { !animating && opt.onBeforePlotLine(adj); ctx.save(); ctx.globalAlpha = Math.min(Math.min(node.alpha, nodeTo.alpha), adj.alpha); - that.plotLine(adj, canvas); + that.plotLine(adj, canvas, animating); ctx.restore(); !animating && opt.onAfterPlotLine(adj); } @@ -374,10 +375,10 @@ Graph.Plot = { if(node.drawn) { ctx.globalAlpha = node.alpha; !animating && opt.onBeforePlotNode(node); - that.plotNode(node, canvas); + that.plotNode(node, canvas, animating); !animating && opt.onAfterPlotNode(node); } - if(!that.labelsHidden) { + if(!that.labelsHidden && opt.withLabels) { if(node.drawn && ctx.globalAlpha >= .95) { that.plotLabel(canvas, node, opt); } else { @@ -439,7 +440,7 @@ Graph.Plot = { ctx.strokeStyle = color; var f = node.data && node.data.$type || nconfig.type; - this.nodeTypes[f].call(this, node, canvas); + this.nodeTypes[f].call(this, node, canvas, animating); }, /* @@ -465,7 +466,7 @@ Graph.Plot = { ctx.strokeStyle = color; var f = adj.data && adj.data.$type || econfig.type; - this.edgeTypes[f].call(this, adj, canvas); + this.edgeTypes[f].call(this, adj, canvas, animating); }, /* diff --git a/Source/Hypertree.js b/Source/Hypertree.js index 3e1b988..712224a 100644 --- a/Source/Hypertree.js +++ b/Source/Hypertree.js @@ -135,6 +135,9 @@ Graph.Util.moebiusTransformation = function(graph, pos, prop, startPos, flags) { The configuration object can have the following properties (all properties are optional and have a default value) + *General* + - _withLabels_ Whether the visualization should use/create labels or not. Default's *true*. + *Node* Customize the visualization nodes' shape, color, and other style properties. @@ -178,6 +181,7 @@ Graph.Util.moebiusTransformation = function(graph, pos, prop, startPos, flags) { - _duration_ Duration of the animation in milliseconds. Default's 1500. - _fps_ Frames per second. Default's 40. - _transition_ One of the transitions defined in the class. Default's Quart.easeInOut. + - _clearCanvas_ Whether to clear canvas on each animation frame or not. Default's true. *Controller options* @@ -204,6 +208,7 @@ This method is useful for adding some styles to a particular edge before being p (start code js) var ht = new Hypertree(canvas, { + Node: { overridable: false, type: 'circle', @@ -223,7 +228,9 @@ This method is useful for adding some styles to a particular edge before being p duration: 1500, fps: 40, transition: Trans.Quart.easeInOut, - + clearCanvas: true, + withLabels: true, + onBeforeCompute: function(node) { //do something onBeforeCompute }, @@ -267,6 +274,8 @@ this.Hypertree = new Class({ var config = { labelContainer: canvas.id + '-label', + withLabels: true, + Node: { overridable: false, type: 'circle', @@ -284,11 +293,9 @@ this.Hypertree = new Class({ color: '#ccb', lineWidth: 1 }, - + clearCanvas: true, fps:40, - duration: 1500, - transition: Trans.Quart.easeInOut }; diff --git a/Source/RGraph.js b/Source/RGraph.js index 2e37ea6..2313c18 100644 --- a/Source/RGraph.js +++ b/Source/RGraph.js @@ -44,6 +44,7 @@ - _interpolation_ Interpolation type used for animations. Possible options are 'polar' and 'linear'. Default's 'linear'. - _levelDistance_ Distance between a parent node and its children. Default's 100. + - _withLabels_ Whether the visualization should use/create labels or not. Default's *true*. *Node* @@ -87,7 +88,8 @@ - _duration_ Duration of the animation in milliseconds. Default's 2500. - _fps_ Frames per second. Default's 40. - _transition_ One of the transitions defined in the class. Default's Quart.easeInOut. - + - _clearCanvas_ Whether to clear canvas on each animation frame or not. Default's true. + *Controller options* You can also implement controller functions inside the configuration object. This functions are @@ -115,6 +117,7 @@ This method is useful for adding some styles to a particular edge before being p var rgraph = new RGraph(canvas, { interpolation: 'linear', levelDistance: 100, + withLabels: true, Node: { overridable: false, type: 'circle', @@ -133,7 +136,7 @@ This method is useful for adding some styles to a particular edge before being p duration: 2500, fps: 40, transition: Trans.Quart.easeInOut, - + clearCanvas: true, onBeforeCompute: function(node) { //do something onBeforeCompute }, @@ -177,9 +180,9 @@ this.RGraph = new Class({ labelContainer: canvas.id + '-label', interpolation: 'linear', - levelDistance: 100, - + withLabels: true, + Node: { overridable: false, type: 'circle', @@ -199,7 +202,8 @@ this.RGraph = new Class({ fps:40, duration: 2500, - transition: Trans.Quart.easeInOut + transition: Trans.Quart.easeInOut, + clearCanvas: true }; var innerController = { diff --git a/Source/Spacetree.js b/Source/Spacetree.js index 0e51a2a..8d427d5 100644 --- a/Source/Spacetree.js +++ b/Source/Spacetree.js @@ -44,6 +44,7 @@ - _subtreeOffset_ Separation offset between subtrees. Default's 8. - _siblingOffset_ Separation offset between siblings. Default's 5. - _levelDistance_ Distance between levels. Default's 30. + - _withLabels_ Whether the visualization should use/create labels or not. Default's *true*. *Node* @@ -92,7 +93,8 @@ - _duration_ Duration of the animation in milliseconds. Default's 700. - _fps_ Frames per second. Default's 25. - _transition_ One of the transitions defined in the class. Default's Quart.easeInOut. - + - _clearCanvas_ Whether to clear canvas on each animation frame or not. Default's true. + *Controller options* You can also implement controller functions inside the configuration object. This functions are @@ -126,6 +128,7 @@ object must be called with the given result. subtreeOffset: 8, siblingOffset: 5, levelDistance: 30, + withLabels: true, Node: { overridable: false, type: 'rectangle', @@ -146,7 +149,8 @@ object must be called with the given result. duration: 700, fps: 25, transition: Trans.Quart.easeInOut, - + clearCanvas: true, + onBeforeCompute: function(node) { //do something onBeforeCompute }, @@ -298,6 +302,8 @@ this.ST= (function() { subtreeOffset: 8, siblingOffset: 5, levelDistance: 30, + withLabels: true, + clearCanvas: true, Node: { overridable: false, type: 'rectangle', @@ -486,8 +492,12 @@ this.ST= (function() { Group.contract(nodes, $merge(this.controller, onComplete)); }, - move: function(node, offset, onComplete) { + move: function(node, onComplete) { this.compute('endPos', false); + var move = onComplete.Move, offset = { + 'x': move.offsetX, + 'y': move.offsetY + }; this.geom.translate(node.endPos.add(offset).$scale(-1), "endPos"); this.fx.animate($merge(this.controller, { modes: ['linear'] }, onComplete)); }, @@ -541,9 +551,9 @@ this.ST= (function() { */ addSubtree: function(subtree, method, onComplete) { if(method == 'replot') { - this.op.sum(subtree, { type: 'replot' }); + this.op.sum(subtree, $extend({ type: 'replot' }, onComplete || {})); } else if (method == 'animate') { - this.op.sum(subtree, { type: 'fade:seq' }); + this.op.sum(subtree, $extend({ type: 'fade:seq' }, onComplete || {})); } }, @@ -575,9 +585,9 @@ this.ST= (function() { subids.push(n.id); }); if(method == 'replot') { - this.op.removeNode(subids, { type: 'replot' }); + this.op.removeNode(subids, $extend({ type: 'replot' }, onComplete || {})); } else if (method == 'animate') { - this.op.removeNode(subids, { type: 'fade:seq'}); + this.op.removeNode(subids, $extend({ type: 'fade:seq'}, onComplete || {})); } }, @@ -657,6 +667,10 @@ this.ST= (function() { onClick: function (id, options) { var canvas = this.canvas, that = this, Fx = this.fx, Util = Graph.Util, Geom = this.geom; var innerController = { + Move: { + offsetX: 0, + offsetY: 0 + }, onBeforeRequest: $empty, onBeforeContract: $empty, onBeforeMove: $empty, @@ -677,9 +691,9 @@ this.ST= (function() { that.contract({ onComplete: function() { Geom.setRightLevelToShow(node, canvas); - var offset = {x: 0, y: 0}; - complete.onBeforeMove(node, offset); - that.move(node, offset, { + complete.onBeforeMove(node); + that.move(node, { + Move: complete.Move, onComplete: function() { complete.onBeforeExpand(node); that.expand(node, { @@ -788,7 +802,7 @@ ST.Group = new Class({ compute: function(delta) { if(delta == 1) delta = .99; that.plotStep(1 - delta, controller, this.$animating); - this.$animating = true; + this.$animating = 'contract'; }, complete: function() { @@ -800,7 +814,10 @@ ST.Group = new Class({ hide: function(nodes, controller) { var GUtil = Graph.Util, viz = this.viz; for(var i=0; i= .95) this.plotLabel(canvas, node, opt); diff --git a/Source/Treemap.js b/Source/Treemap.js index 577dbf4..05a51a1 100644 --- a/Source/Treemap.js +++ b/Source/Treemap.js @@ -66,6 +66,9 @@ - _rootId_ The id of the div container where the Treemap will be injected. Default's 'infovis'. - _orientation_ For and only. The layout algorithm orientation. Possible values are 'h' or 'v'. - _levelsToShow_ Max depth of the plotted tree. Useful when using the request method. + - _addLeftClickHandler_ Add a left click event handler to zoom in the Treemap view when clicking a node. Default's *false*. + - _addRightClickHandler_ Add a right click event handler to zoom out the Treemap view. Default's *false*. + - _selectPathOnHover_ If setted to *true* all nodes contained in the path between the hovered node and the root node will have an *in-path* CSS class. Default's *false*. *Nodes* @@ -112,6 +115,21 @@ - _minColorValue_ A three-element RGB array defining the color to be assigned to the _$color_ having _minValue_ as value. Default's [255, 0, 50]. - _maxColorValue_ A three-element RGB array defining the color to be assigned to the _$color_ having _maxValue_ as value. Default's [0, 255, 50]. + *Tips* + + _Tips_ is an object containing as properties + + - _allow_ If *true*, a tooltip will be shown when a node is hovered. The tooltip is a div DOM element having "tip" as CSS class. Default's *false*. + - _offsetX_ An offset added to the current tooltip x-position (which is the same as the current mouse position). Default's 20. + - _offsetY_ An offset added to the current tooltip y-position (which is the same as the current mouse position). Default's 20. + - _onShow(tooltip, node, isLeaf, domElement)_ Implement this method to change the HTML content of the tooltip when hovering a node. + + Parameters: + tooltip - The tooltip div element. + node - The corresponding JSON tree node (See also ). + isLeaf - Whether is a leaf or inner node. + domElement - The current hovered DOM element. + *Controller options* You can also implement controller functions inside the configuration object. These functions are @@ -165,13 +183,24 @@ this.TM = { rootId: 'infovis', offset:4, levelsToShow: 3, + addLeftClickHandler: false, + addRightClickHandler: false, + selectPathOnHover: false, + Color: { allow: false, minValue: -100, maxValue: 100, minColorValue: [255, 0, 50], maxColorValue: [0, 255, 50] - } + }, + + Tips: { + allow: false, + offsetX: 20, + offsetY: 20, + onShow: $empty + } }, @@ -184,6 +213,19 @@ this.TM = { this.rootId = this.config.rootId; this.layout.orientation = this.config.orientation; + //add tooltip + if(this.config.Tips.allow && document.body) { + var tip = document.createElement('div'); + tip.id = '_tooltip'; + tip.className = 'tip'; + var style = tip.style; + style.position = 'absolute'; + style.display = 'none'; + style.zIndex = 13000; + document.body.appendChild(tip); + this.tip = tip; + } + //purge var that = this; var fn = function() { @@ -208,12 +250,11 @@ this.TM = { f - A function that takes as parameters the same as the onCreateElement and onDestroyElement methods described in . */ each: function(f) { - var sl = Array.prototype.slice; (function rec(elem) { if(!elem) return; var ch = elem.childNodes, len = ch.length; if(len > 0) { - f.apply(this, [elem, len === 1].concat(sl.call(ch))); + f.apply(this, [elem, len === 1, ch[0], ch[1]]); } if (len > 1) { for(var chi = ch[1].childNodes, i=0; i. + + See also: + + + */ + onLeftClick: function(elem) { + this.enter(elem); + }, + /* Method: out @@ -557,6 +629,33 @@ this.TM = { } }, + /* + Method: onRightClick + + Sets the _parent_ node of the currently shown subtree as root and performs the layout. + This method is called when _addRightClickHandler_ is *true* and a + node is right-clicked. You can override this method to add some custom behavior + when the node is right-clicked though. + + An Example for overriding this method could be + (start code js) + //TM.Strip or TM.SliceAndDice also work + TM.Squarified.implement({ + 'onRightClick': function() { + //some custom code... + } + }); + (end code) + + See also: + + + + */ + onRightClick: function() { + this.out(); + }, + /* Method: view @@ -607,11 +706,11 @@ this.TM = { if(container) { var parent = getParent(container); while(parent) { - var elem = parent.childNodes[0], klasses = elem.className.split(" "); - if(klasses.pop() == "in-path") { - if(remove == undefined || !!remove) elem.className = klasses.join(" "); + var elem = parent.childNodes[0] + if($hasClass(elem, 'in-path')) { + if(remove == undefined || !!remove) $removeClass(elem, 'in-path'); } else { - if(!remove) elem.className += " in-path"; + if(!remove) $addClass(elem, 'in-path'); } parent = getParent(parent); } @@ -632,12 +731,97 @@ this.TM = { node created. *By default, the Treemap wont add any event to its elements.* */ initializeElements: function() { - if(this.controller.onCreateElement != $empty) { - var cont = this.controller, that = this; - this.each(function(content, isLeaf, elem1, elem2) { - cont.onCreateElement(content, TreeUtil.getSubtree(that.tree, content.id), isLeaf, elem1, elem2); - }); - } + var cont = this.controller, that = this; + var ff = $lambda(false), tipsAllow = cont.Tips.allow; + this.each(function(content, isLeaf, elem1, elem2) { + var tree = TreeUtil.getSubtree(that.tree, content.id); + cont.onCreateElement(content, tree, isLeaf, elem1, elem2); + + //eliminate context menu when right clicking + if(cont.addRightClickHandler) elem1.oncontextmenu = ff; + + //add click handlers + if(cont.addLeftClickHandler || cont.addRightClickHandler) { + $addEvent(elem1, 'mouseup', function(e) { + var rightClick = (e.which == 3 || e.button == 2); + if (rightClick) { + if(cont.addRightClickHandler) that.onRightClick(); + } + else { + if(cont.addLeftClickHandler) that.onLeftClick(elem1); + } + + //prevent default + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + }); + } + + //add path selection on hovering nodes + if(cont.selectPathOnHover || tipsAllow) { + $addEvent(elem1, 'mouseover', function(e){ + if(cont.selectPathOnHover) { + if (isLeaf) { + $addClass(elem1, 'over-leaf'); + } + else { + $addClass(elem1, 'over-head'); + $addClass(content, 'over-content'); + } + if (content.id) + that.resetPath(tree); + } + if(tipsAllow) + cont.Tips.onShow(that.tip, tree, isLeaf, elem1); + }); + + $addEvent(elem1, 'mouseout', function(e){ + if(cont.selectPathOnHover) { + if (isLeaf) { + $removeClass(elem1, 'over-leaf'); + } + else { + $removeClass(elem1, 'over-head'); + $removeClass(content, 'over-content'); + } + that.resetPath(); + } + if(tipsAllow) + that.tip.style.display = 'none'; + }); + + if(tipsAllow) { + //Add mousemove event handler + $addEvent(elem1, 'mousemove', function(e){ + var tip = that.tip; + //get mouse position + var page = { + x: e.pageX || e.clientX + document.scrollLeft, + y: e.pageY || e.clientY + document.scrollTop + }; + tip.style.display = ''; + //get window dimensions + var win = { + 'height': document.body.clientHeight, + 'width': document.body.clientWidth + }; + //get tooltip dimensions + var obj = { + 'width': tip.offsetWidth, + 'height': tip.offsetHeight + }; + //set tooltip position + var style = tip.style, x = cont.Tips.offsetX, y = cont.Tips.offsetY; + style.top = ((page.y + y + obj.height > win.height)? + (page.y - obj.height - y) : page.y + y) + 'px'; + style.left = ((page.x + obj.width + x > win.width)? + (page.x - obj.width - x) : page.x + x) + 'px'; + }); + } + } + }); }, /* @@ -717,14 +901,25 @@ this.TM = { rootId: 'infovis', offset:4, levelsToShow: 3, + addLeftClickHandler: false, + addRightClickHandler: false, + selectPathOnHover: false, + Color: { allow: false, minValue: -100, maxValue: 100, minColorValue: [255, 0, 50], maxColorValue: [0, 255, 50] - } - + }, + + Tips: { + allow: false, + offsetX; 20, + offsetY: 20, + onShow: function(tooltip, node, isLeaf, domElement) {} + }, + onBeforeCompute: function(node) { //Some stuff on before compute... }, @@ -1037,13 +1232,24 @@ TM.Area = new Class({ rootId: 'infovis', offset:4, levelsToShow: 3, + addLeftClickHandler: false, + addRightClickHandler: false, + selectPathOnHover: false, + Color: { allow: false, minValue: -100, maxValue: 100, minColorValue: [255, 0, 50], maxColorValue: [0, 255, 50] - } + }, + + Tips: { + allow: false, + offsetX: 20, + offsetY: 20, + onShow: function(tooltip, node, isLeaf, domElement) {} + }, onBeforeCompute: function(node) { //Some stuff on before compute... @@ -1249,13 +1455,24 @@ TM.Squarified = new Class({ rootId: 'infovis', offset:4, levelsToShow: 3, + addLeftClickHandler: false, + addRightClickHandler: false, + selectPathOnHover: false, + Color: { allow: false, minValue: -100, maxValue: 100, minColorValue: [255, 0, 50], maxColorValue: [0, 255, 50] - } + }, + + Tips: { + allow: false, + offsetX: 20, + offsetY: 20, + onShow: function(tooltip, node, isLeaf, domElement) {} + }, onBeforeCompute: function(node) { //Some stuff on before compute... diff --git a/Templates/Hypertree/left.html b/Templates/Hypertree/left.html new file mode 100644 index 0000000..baf4aee --- /dev/null +++ b/Templates/Hypertree/left.html @@ -0,0 +1,16 @@ +$def with (model, type, number, max) + +$if number > 1: + previous +$if number < max: + next + + +
+

+$model['Title'] +

+$:model['Description'] +
+ +
diff --git a/Templates/Hypertree/test1.html b/Templates/Hypertree/test1.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/Hypertree/test1.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/Hypertree/test10.html b/Templates/Hypertree/test10.html new file mode 100644 index 0000000..d11e1df --- /dev/null +++ b/Templates/Hypertree/test10.html @@ -0,0 +1,65 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + +
+ node types: + + +
+ edge types: + + +
+ transitions: + + +
+ easing: + + +
+ +
+
diff --git a/Templates/Hypertree/test11.html b/Templates/Hypertree/test11.html new file mode 100644 index 0000000..9e1e225 --- /dev/null +++ b/Templates/Hypertree/test11.html @@ -0,0 +1,143 @@ +$def with (model) + +

Global Options

+ + + + + + + + + + + + + + + + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ +
+ +

1.- Remove Nodes

+ + + + + + + + + + +
+ type: + + +
+ + + +
+ +

2.- Remove Edges

+ + + + + + + + + + +
+ type: + + +
+ + + +
+ +

3.- Add Graph (Sum)

+ + + + + + + + + + +
+ type: + + +
+ + + +
+ +

4.- Morph

+ + + + + + + + + + +
+ type: + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Hypertree/test2.html b/Templates/Hypertree/test2.html new file mode 100644 index 0000000..69ed84c --- /dev/null +++ b/Templates/Hypertree/test2.html @@ -0,0 +1,2 @@ +$def with (model) + diff --git a/Templates/Hypertree/test3.html b/Templates/Hypertree/test3.html new file mode 100644 index 0000000..e6b411d --- /dev/null +++ b/Templates/Hypertree/test3.html @@ -0,0 +1,58 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/Hypertree/test4.html b/Templates/Hypertree/test4.html new file mode 100644 index 0000000..e6b411d --- /dev/null +++ b/Templates/Hypertree/test4.html @@ -0,0 +1,58 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/Hypertree/test5.html b/Templates/Hypertree/test5.html new file mode 100644 index 0000000..f53e75c --- /dev/null +++ b/Templates/Hypertree/test5.html @@ -0,0 +1,57 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/Hypertree/test6.html b/Templates/Hypertree/test6.html new file mode 100644 index 0000000..29e0b8b --- /dev/null +++ b/Templates/Hypertree/test6.html @@ -0,0 +1,56 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/Hypertree/test7.html b/Templates/Hypertree/test7.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/Hypertree/test7.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/Hypertree/test8.html b/Templates/Hypertree/test8.html new file mode 100644 index 0000000..69ed84c --- /dev/null +++ b/Templates/Hypertree/test8.html @@ -0,0 +1,2 @@ +$def with (model) + diff --git a/Templates/Hypertree/test9.html b/Templates/Hypertree/test9.html new file mode 100644 index 0000000..69ed84c --- /dev/null +++ b/Templates/Hypertree/test9.html @@ -0,0 +1,2 @@ +$def with (model) + diff --git a/Templates/Other/left.html b/Templates/Other/left.html new file mode 100644 index 0000000..f7bc257 --- /dev/null +++ b/Templates/Other/left.html @@ -0,0 +1,16 @@ +$def with (model, type, number, max) + +$if number > 1: + previous +$if number < max: + next + + +
+

+$model['Title'] +

+$:model['Description'] +
+ +
diff --git a/Templates/Other/test1.html b/Templates/Other/test1.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/Other/test1.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/Other/test2.html b/Templates/Other/test2.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/Other/test2.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/Other/test3.html b/Templates/Other/test3.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/Other/test3.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/RGraph/left.html b/Templates/RGraph/left.html new file mode 100644 index 0000000..f7bc257 --- /dev/null +++ b/Templates/RGraph/left.html @@ -0,0 +1,16 @@ +$def with (model, type, number, max) + +$if number > 1: + previous +$if number < max: + next + + +
+

+$model['Title'] +

+$:model['Description'] +
+ +
diff --git a/Templates/RGraph/test1.html b/Templates/RGraph/test1.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/RGraph/test1.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/RGraph/test2.html b/Templates/RGraph/test2.html new file mode 100644 index 0000000..e6b411d --- /dev/null +++ b/Templates/RGraph/test2.html @@ -0,0 +1,58 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/RGraph/test3.html b/Templates/RGraph/test3.html new file mode 100644 index 0000000..e6b411d --- /dev/null +++ b/Templates/RGraph/test3.html @@ -0,0 +1,58 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/RGraph/test4.html b/Templates/RGraph/test4.html new file mode 100644 index 0000000..f53e75c --- /dev/null +++ b/Templates/RGraph/test4.html @@ -0,0 +1,57 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/RGraph/test5.html b/Templates/RGraph/test5.html new file mode 100644 index 0000000..29e0b8b --- /dev/null +++ b/Templates/RGraph/test5.html @@ -0,0 +1,56 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ type: + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ + + +
+
\ No newline at end of file diff --git a/Templates/RGraph/test6.html b/Templates/RGraph/test6.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/RGraph/test6.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/RGraph/test7.html b/Templates/RGraph/test7.html new file mode 100644 index 0000000..8e04679 --- /dev/null +++ b/Templates/RGraph/test7.html @@ -0,0 +1,65 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + +
+ node types: + + +
+ edge types: + + +
+ transitions: + + +
+ easing: + + +
+ +
+
diff --git a/Templates/RGraph/test8.html b/Templates/RGraph/test8.html new file mode 100644 index 0000000..9e1e225 --- /dev/null +++ b/Templates/RGraph/test8.html @@ -0,0 +1,143 @@ +$def with (model) + +

Global Options

+ + + + + + + + + + + + + + + + + +
+ duration: + + +
+ fps: + + +
+ hide labels: + + +
+ +
+ +

1.- Remove Nodes

+ + + + + + + + + + +
+ type: + + +
+ + + +
+ +

2.- Remove Edges

+ + + + + + + + + + +
+ type: + + +
+ + + +
+ +

3.- Add Graph (Sum)

+ + + + + + + + + + +
+ type: + + +
+ + + +
+ +

4.- Morph

+ + + + + + + + + + +
+ type: + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Spacetree/left.html b/Templates/Spacetree/left.html new file mode 100644 index 0000000..f7bc257 --- /dev/null +++ b/Templates/Spacetree/left.html @@ -0,0 +1,16 @@ +$def with (model, type, number, max) + +$if number > 1: + previous +$if number < max: + next + + +
+

+$model['Title'] +

+$:model['Description'] +
+ +
diff --git a/Templates/Spacetree/test1.html b/Templates/Spacetree/test1.html new file mode 100644 index 0000000..c5c23c9 --- /dev/null +++ b/Templates/Spacetree/test1.html @@ -0,0 +1,17 @@ +$def with (model) + + + + + + +
+ Orientation: + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test2.html b/Templates/Spacetree/test2.html new file mode 100644 index 0000000..051cf23 --- /dev/null +++ b/Templates/Spacetree/test2.html @@ -0,0 +1,20 @@ +$def with (model) + + + + + + + + + + +
+ Animate: + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test3.html b/Templates/Spacetree/test3.html new file mode 100644 index 0000000..de017f1 --- /dev/null +++ b/Templates/Spacetree/test3.html @@ -0,0 +1,28 @@ +$def with (model) + + + + + + + + + + + + + + +
+ Animate: + + +
+ Remove Root: + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test4.html b/Templates/Spacetree/test4.html new file mode 100644 index 0000000..c5c23c9 --- /dev/null +++ b/Templates/Spacetree/test4.html @@ -0,0 +1,17 @@ +$def with (model) + + + + + + +
+ Orientation: + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test5.html b/Templates/Spacetree/test5.html new file mode 100644 index 0000000..8f234ab --- /dev/null +++ b/Templates/Spacetree/test5.html @@ -0,0 +1,29 @@ +$def with (model) + + + + + + + + + + +
+ Orientation: + + +
+ Align: + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test6.html b/Templates/Spacetree/test6.html new file mode 100644 index 0000000..5b73c4b --- /dev/null +++ b/Templates/Spacetree/test6.html @@ -0,0 +1,80 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + + + + +
+ node types: + + +
+ edge types: + + +
+ transitions: + + +
+ easing: + + +
+ Orientation: + + +
+ +
+
diff --git a/Templates/Spacetree/test7.html b/Templates/Spacetree/test7.html new file mode 100644 index 0000000..51e7a7b --- /dev/null +++ b/Templates/Spacetree/test7.html @@ -0,0 +1,36 @@ +$def with (model) + +

Change Tree Orientation

+ + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test8.html b/Templates/Spacetree/test8.html new file mode 100644 index 0000000..51e7a7b --- /dev/null +++ b/Templates/Spacetree/test8.html @@ -0,0 +1,36 @@ +$def with (model) + +

Change Tree Orientation

+ + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Spacetree/test9.html b/Templates/Spacetree/test9.html new file mode 100644 index 0000000..8dca247 --- /dev/null +++ b/Templates/Spacetree/test9.html @@ -0,0 +1,21 @@ +$def with (model) + +

Add Subtrees

+ + + + + + + + + +
+ Animate: + + +
+ + + +
\ No newline at end of file diff --git a/Templates/Treemap/left.html b/Templates/Treemap/left.html new file mode 100644 index 0000000..f7bc257 --- /dev/null +++ b/Templates/Treemap/left.html @@ -0,0 +1,16 @@ +$def with (model, type, number, max) + +$if number > 1: + previous +$if number < max: + next + + +
+

+$model['Title'] +

+$:model['Description'] +
+ +
diff --git a/Templates/Treemap/test1.html b/Templates/Treemap/test1.html new file mode 100644 index 0000000..8019f6d --- /dev/null +++ b/Templates/Treemap/test1.html @@ -0,0 +1,51 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ Layout: + + +
+ Colored: + + +
Title: + +
Offset: + +
Horizontal: + +
+ + +
\ No newline at end of file diff --git a/Templates/Treemap/test2.html b/Templates/Treemap/test2.html new file mode 100644 index 0000000..8019f6d --- /dev/null +++ b/Templates/Treemap/test2.html @@ -0,0 +1,51 @@ +$def with (model) + + + + + + + + + + + + + + + + + + + + + + +
+ Layout: + + +
+ Colored: + + +
Title: + +
Offset: + +
Horizontal: + +
+ + +
\ No newline at end of file diff --git a/Templates/Treemap/test3.html b/Templates/Treemap/test3.html new file mode 100644 index 0000000..b471163 --- /dev/null +++ b/Templates/Treemap/test3.html @@ -0,0 +1,3 @@ +$def with (model) + +
\ No newline at end of file diff --git a/Templates/Treemap/test4.html b/Templates/Treemap/test4.html new file mode 100644 index 0000000..0e7e692 --- /dev/null +++ b/Templates/Treemap/test4.html @@ -0,0 +1,7 @@ +$def with (model) + +

Click to go to parent node

+
+ +
+
\ No newline at end of file diff --git a/Templates/Treemap/test5.html b/Templates/Treemap/test5.html new file mode 100644 index 0000000..0e7e692 --- /dev/null +++ b/Templates/Treemap/test5.html @@ -0,0 +1,7 @@ +$def with (model) + +

Click to go to parent node

+
+ +
+
\ No newline at end of file diff --git a/Templates/basecode.html b/Templates/basecode.html new file mode 100644 index 0000000..b37713b --- /dev/null +++ b/Templates/basecode.html @@ -0,0 +1,51 @@ +$def with (name, title, code, example) + + + + +$name - $title - Code + + + + + + + + + + + + + +
+ +
+

Code for $title

+
+ These are ordered fragments for the $title example code. + I trimmed parts that seemed uninteresting and that are not related to the library code. + You can still see the full code here. Or go back to the example. +
+ + +$for elem in code: +

$elem['name']

+ $if elem['name'] == 'data': +
+ $else: +
+
+    $elem['code']
+    
+
+ +
+
+ + diff --git a/Templates/baseexamples.html b/Templates/baseexamples.html new file mode 100644 index 0000000..43578ea --- /dev/null +++ b/Templates/baseexamples.html @@ -0,0 +1,46 @@ +$def with (name, title, extras, example, build, includes, fancy) + + + + +$name - $title + + + + + +$if extras: + $for lib in extras: + $if lib == "excanvas.js": + + + + + + + + + +
+ +
+$:includes['left'] + +$if fancy: + +$else: + +
+ +
+
+
+ +
+$:includes['right'] +
+ +
+
+ + diff --git a/Templates/basetests.html b/Templates/basetests.html new file mode 100644 index 0000000..8a5e4aa --- /dev/null +++ b/Templates/basetests.html @@ -0,0 +1,45 @@ +$def with (name, title, extras, test, build, includes) + + + + +$name - $title + + + + + + + + +$if extras: + $for lib in extras: + $if lib == "excanvas.js": + + $else: + + + + + + + + + + +
+
+$:includes['left'] +
+
+
+
+
+$:includes['right'] +
+
+
+ + diff --git a/Tests/Hypertree/test1.js b/Tests/Hypertree/test1.js index 49b50b3..d8a9b7a 100644 --- a/Tests/Hypertree/test1.js +++ b/Tests/Hypertree/test1.js @@ -1,13 +1,4 @@ function init(){ - 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'; - } - }; //init data var json = { "id": "347_0", @@ -363,9 +354,9 @@ function init(){ //creation onCreateLabel: function(domElement, node){ domElement.innerHTML = node.name; - domElement.onclick = function () { + addEvent(domElement, 'click', function () { ht.onClick(node.id); - }; + }); }, //Change node styles when labels are placed //or moved. diff --git a/Tests/Hypertree/test10.js b/Tests/Hypertree/test10.js index f866584..1b466e7 100644 --- a/Tests/Hypertree/test10.js +++ b/Tests/Hypertree/test10.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "347_0", "name": "Nine Inch Nails", @@ -364,9 +355,9 @@ function init(){ onCreateLabel: function(domElement, node){ domElement.innerHTML = node.name; - domElement.onclick = function(){ + addEvent(domElement, 'click', function(){ ht.onClick(node.id); - }; + }); }, //Take the left style property and substract half of the label actual width. @@ -448,21 +439,21 @@ function init(){ transitions = document.getElementById('transitions'), easing = document.getElementById('easing'); - nodeTypes.onchange = function(){ + addEvent(nodeTypes, 'change', function(){ var nodeOpt = nodeOptions[nodeTypes.selectedIndex]; for (var prop in nodeOpt) { ht.config.Node[prop] = nodeOpt[prop]; } ht.plot(); ht.controller.onAfterCompute(); - }; + }); - edgeTypes.onchange = function(){ + addEvent(edgeTypes, 'change', function(){ var edgeOpt = edgeOptions[edgeTypes.selectedIndex]; ht.config.Edge.type = edgeOpt; ht.plot(); ht.controller.onAfterCompute(); - }; + }); transitions.onchange = function(){ var transition = transitions.options[transitions.selectedIndex].text; diff --git a/Tests/Hypertree/test11.js b/Tests/Hypertree/test11.js index 04bd88e..11ec135 100644 --- a/Tests/Hypertree/test11.js +++ b/Tests/Hypertree/test11.js @@ -1,13 +1,4 @@ function init(){ - 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'; - } - }; //init data var json = { "id": "190_0", @@ -449,10 +440,13 @@ function init(){ onBeforeCompute: function(node){ Log.write("centering"); }, - + //Add the node's name to its corresponding label. + //This method is only called on label creation. onCreateLabel: function(domElement, node){ domElement.innerHTML = node.name; }, + + //Ths method is called when moving/placing a label. //Add label styles based on their position. onPlaceLabel: function(domElement, node){ var style = domElement.style; diff --git a/Tests/Hypertree/test2.js b/Tests/Hypertree/test2.js index ec54fd1..9abf4ce 100644 --- a/Tests/Hypertree/test2.js +++ b/Tests/Hypertree/test2.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = [{ "id": "a_0", "name": "someNode", diff --git a/Tests/Hypertree/test3.js b/Tests/Hypertree/test3.js index cbfdaef..7e69867 100644 --- a/Tests/Hypertree/test3.js +++ b/Tests/Hypertree/test3.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "190_0", "name": "Pearl Jam", diff --git a/Tests/Hypertree/test4.js b/Tests/Hypertree/test4.js index 8b3c1cf..048bcc7 100644 --- a/Tests/Hypertree/test4.js +++ b/Tests/Hypertree/test4.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "190_0", "name": "Pearl Jam", diff --git a/Tests/Hypertree/test5.js b/Tests/Hypertree/test5.js index 63c12e0..f02d431 100644 --- a/Tests/Hypertree/test5.js +++ b/Tests/Hypertree/test5.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "190_0", "name": "Pearl Jam", diff --git a/Tests/Hypertree/test6.js b/Tests/Hypertree/test6.js index c8a0e85..10915de 100644 --- a/Tests/Hypertree/test6.js +++ b/Tests/Hypertree/test6.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "190_0", "name": "Pearl Jam", diff --git a/Tests/Hypertree/test7.js b/Tests/Hypertree/test7.js index 0b66498..7ba5d2c 100644 --- a/Tests/Hypertree/test7.js +++ b/Tests/Hypertree/test7.js @@ -1,13 +1,4 @@ function init(){ - 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'; - } - }; //init data //By defining properties with the dollar sign ($) //in nodes and edges we can override the global configuration @@ -244,9 +235,13 @@ function init(){ color: "#088" }, + //Change the animation transition type transition: Trans.Back.easeOut, duration:1000, + //This method is called right before plotting an + //edge. This method is useful for adding individual + //styles to edges. onBeforePlotLine: function(adj){ //Set random lineWidth for edges. if (!adj.data.$lineWidth) @@ -265,6 +260,8 @@ function init(){ }; }, + //This method is called when moving/placing a label. + //You can add some positioning offsets to the labels here. onPlaceLabel: function(domElement, node){ var width = domElement.offsetWidth; var intX = parseInt(domElement.style.left); diff --git a/Tests/Hypertree/test8.js b/Tests/Hypertree/test8.js index d9434cf..032e9ec 100644 --- a/Tests/Hypertree/test8.js +++ b/Tests/Hypertree/test8.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var p = { idPrefix: "node", levelStart: 0, diff --git a/Tests/Hypertree/test9.js b/Tests/Hypertree/test9.js index c6d2b0b..a13fefb 100644 --- a/Tests/Hypertree/test9.js +++ b/Tests/Hypertree/test9.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var p = { idPrefix: "node", levelStart: 0, diff --git a/Tests/Other/test1.js b/Tests/Other/test1.js new file mode 100644 index 0000000..24543b0 --- /dev/null +++ b/Tests/Other/test1.js @@ -0,0 +1,550 @@ +function init() { + //init data + var jsonpie = { + 'id': 'root', + 'name': 'RGraph based Pie Chart', + 'data': { + '$type': 'none' + }, + 'children':[ + { + 'id':'pie1', + 'name': 'pie1', + 'data': { + '$aw': 20, + '$color': '#f55' + }, + 'children': [] + }, + { + 'id':'pie2', + 'name': 'pie2', + 'data': { + '$aw': 40, + '$color': '#f77' + }, + 'children': [] + }, + { + 'id':'pie3', + 'name': 'pie3', + 'data': { + '$aw': 10, + '$color': '#f99' + }, + 'children': [] + }, + { + 'id':'pie4', + 'name': 'pie4', + 'data': { + '$aw': 30, + '$color': '#fbb' + }, + 'children': [] + } + ] + }; + + var jsonpie2 = { + 'id': 'root', + 'name': 'Making an Extended Pie Chart', + 'data': { + '$type': 'none' + }, + 'children':[ + { + 'id':'pie10', + 'name': 'pie1', + 'data': { + '$aw': 20, + '$color': '#f55' + }, + 'children': [ + { + 'id':'pie100', + 'name': 'pc1', + 'data': { + '$aw': 20, + '$color': '#55f' + }, + 'children': [] + + }, + { + 'id':'pie101', + 'name': 'pc2', + 'data': { + '$aw': 70, + '$color': '#66f' + }, + 'children': [] + + }, + { + 'id':'pie102', + 'name': 'pc3', + 'data': { + '$aw': 10, + '$color': '#77f' + }, + 'children': [] + + } + ] + }, + { + 'id':'pie20', + 'name': 'pie2', + 'data': { + '$aw': 40, + '$color': '#f77' + }, + 'children': [ + { + 'id':'pie200', + 'name': 'pc1', + 'data': { + '$aw': 40, + '$color': '#88f' + }, + 'children': [] + + }, + { + 'id':'pie201', + 'name': 'pc2', + 'data': { + '$aw': 60, + '$color': '#99f' + }, + 'children': [] + + } + ] + }, + { + 'id':'pie30', + 'name': 'pie3', + 'data': { + '$aw': 10, + '$color': '#f99' + }, + 'children': [ + { + 'id':'pie300', + 'name': 'pc1', + 'data': { + '$aw': 100, + '$color': '#aaf' + }, + 'children': [] + + } + ] + } + ] + }; + + var jsonpie3 = { + 'id': 'root1', + 'name': 'ST Bar Chart', + 'data': { + '$type': 'none', + '$width': 80, + '$height':20 + }, + 'children':[ + { + 'id':'h1', + 'name': 'h1', + 'data': { + '$color': '#55f', + '$height':30 + }, + 'children': [] + }, + { + 'id':'h2', + 'name': 'h2', + 'data': { + '$color': '#66f', + '$height':50 + }, + 'children': [] + }, + { + 'id':'h3', + 'name': 'h3', + 'data': { + '$color': '#77f', + '$height':70 + }, + 'children': [] + }, + { + 'id':'h4', + 'name': 'h4', + 'data': { + '$height':90, + '$color': '#88f' + }, + 'children': [] + }, + { + 'id':'h5', + 'name': 'h5', + 'data': { + '$height':100, + '$color': '#99f' + }, + 'children': [] + }, + { + 'id':'h6', + 'name': 'h6', + 'data': { + '$height':110, + '$color': '#aaf' + }, + 'children': [] + }, + { + 'id':'h7', + 'name': 'h7', + 'data': { + '$height':150, + '$color': '#bbf' + }, + 'children': [] + }, + { + 'id':'h8', + 'name': 'h8', + 'data': { + '$height':110, + '$color': '#aaf' + }, + 'children': [] + }, + { + 'id':'h9', + 'name': 'h9', + 'data': { + '$height':100, + '$color': '#99f' + }, + 'children': [] + }, + { + 'id':'h10', + 'name': 'h10', + 'data': { + '$height':90, + '$color': '#88f' + }, + 'children': [] + }, + { + 'id':'h11', + 'name': 'h11', + 'data': { + '$height':110, + '$color': '#aaf' + }, + 'children': [] + }, + { + 'id':'h12', + 'name': 'h12', + 'data': { + '$height':150, + '$color': '#bbf' + }, + 'children': [] + }, + { + 'id':'h13', + 'name': 'h13', + 'data': { + '$height':110, + '$color': '#aaf' + }, + 'children': [] + }, + { + 'id':'h14', + 'name': 'h14', + 'data': { + '$height':100, + '$color': '#99f' + }, + 'children': [] + }, + { + 'id':'h15', + 'name': 'h15', + 'data': { + '$height':90, + '$color': '#88f' + }, + 'children': [] + } + ] + }; + //end + + var infovis = document.getElementById('infovis'); + var w = infovis.offsetWidth, h = infovis.offsetHeight; + + //create some containers for the visualizations + var container = document.createElement('div'); + container.id = "infovis1"; + var style = container.style; + style.left = "0px"; + style.top = "0px"; + style.width = Math.floor(w / 2) + "px"; + style.height = Math.floor(h / 2) + "px"; + style.position = 'absolute'; + infovis.appendChild(container); + + container = document.createElement('div'); + container.id = "infovis2"; + var style = container.style; + style.left = Math.floor(w / 2) + "px"; + style.top = "0px"; + style.width = style.left; + style.height = Math.floor(h / 2) + "px"; + style.position = 'absolute'; + infovis.appendChild(container); + + container = document.createElement('div'); + container.id = "infovis3"; + var style = container.style; + style.left = "0px"; + style.top = Math.floor(h / 2) + "px"; + style.width = w + "px"; + style.height = Math.floor(h / 2) + "px"; + style.position = 'absolute'; + infovis.appendChild(container); + + //init canvas + //Create new canvas instances. + var canvas1 = new Canvas('mycanvas1', { + 'injectInto': 'infovis1', + 'width': w/2, + 'height': h/2 + }); + + var canvas2 = new Canvas('mycanvas2', { + 'injectInto': 'infovis2', + 'width': w/2, + 'height': h/2 + }); + + var canvas3 = new Canvas('mycanvas3', { + 'injectInto': 'infovis3', + 'width': w, + 'height': h/2, + 'backgroundColor': '#1a1a1a' + }); + //end + + //init nodetypes + //Here we implement custom node rendering types for the RGraph + //Using this feature requires some javascript and canvas experience. + RGraph.Plot.NodeTypes.implement({ + //This node type is used for plotting the upper-left pie chart + 'nodepie': function(node, canvas) { + var span = node.angleSpan, begin = span.begin, end = span.end; + var polarNode = node.pos.getp(true); + var polar = new Polar(polarNode.rho, begin); + var p1coord = polar.getc(true); + polar.theta = end; + var p2coord = polar.getc(true); + + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(p1coord.x, p1coord.y); + ctx.moveTo(0, 0); + ctx.lineTo(p2coord.x, p2coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho, begin, end, false); + ctx.fill(); + }, + //This node type is used for plotting the upper-right pie chart + 'shortnodepie': function(node, canvas) { + var ldist = this.config.levelDistance; + var span = node.angleSpan, begin = span.begin, end = span.end; + var polarNode = node.pos.getp(true); + + var polar = new Polar(polarNode.rho, begin); + var p1coord = polar.getc(true); + + polar.theta = end; + var p2coord = polar.getc(true); + + polar.rho += ldist; + var p3coord = polar.getc(true); + + polar.theta = begin; + var p4coord = polar.getc(true); + + + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(p1coord.x, p1coord.y); + ctx.lineTo(p4coord.x, p4coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho, begin, end, false); + + ctx.moveTo(p2coord.x, p2coord.y); + ctx.lineTo(p3coord.x, p3coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true); + + ctx.fill(); + } + }); + //end + + //init rgraph + //This RGraph is used to plot the upper-left pie chart. + //It has custom *pie-chart-nodes*. + var rgraph = new RGraph(canvas1, { + //Add node/edge styles and set + //overridable=true if you want your + //styles to be individually overriden + Node: { + 'overridable': true, + 'type': 'nodepie' + }, + Edge: { + 'overridable': true + }, + //Parent-children distance + levelDistance: 135, + + //Add styles to node labels on label creation + onCreateLabel: function(domElement, node){ + domElement.innerHTML = node.name; + if(node.data.$aw) + domElement.innerHTML += " " + node.data.$aw + "%"; + var style = domElement.style; + style.fontSize = "0.8em"; + style.color = "#fff"; + }, + //Add some offset to the labels when placed. + onPlaceLabel: function(domElement, node){ + var style = domElement.style; + var left = parseInt(style.left); + var w = domElement.offsetWidth; + style.left = (left - w / 2) + 'px'; + } + }); + //load graph. + rgraph.loadJSON(jsonpie); + rgraph.refresh(); + //end + //init rgraph2 + //This RGraph instance is used for plotting the upper-right + //pie chart. + var rgraph2 = new RGraph(canvas2, { + //Add node/edge styles and set + //overridable=true if you want your + //styles to be individually overriden + Node: { + 'overridable': true, + 'type':'shortnodepie' + }, + Edge: { + 'overridable': true + }, + //Parent-children distance + levelDistance: 45, + + //Add styles to node labels on label creation + onCreateLabel: function(domElement, node){ + if(node.id == rgraph2.root) return; + domElement.innerHTML = node.name; + if(node.data.$aw) { + domElement.innerHTML += " " + node.data.$aw + "%"; + } + var style = domElement.style; + style.fontSize = "0.8em"; + style.color = "#fff"; + }, + + onPlaceLabel: function(domElement, node){ + var style = domElement.style; + var left = parseInt(style.left); + var w = domElement.offsetWidth; + style.left = (left - w / 2) + 'px'; + } + }); + //load graph. + rgraph2.loadJSON(jsonpie2); + rgraph2.refresh(); + //end + //init st + //This Spacetree nodes' heights are overriden individually + //so that it serves as a bar chart. + var st = new ST(canvas3, { + //set orientarion + orientation:'bottom', + //set duration for the animation + duration: 800, + //set parent-children distance + levelDistance: 30, + //set node and edge styles + //set overridable=true for styling individual + //nodes or edges + Node: { + overridable: true, + width: 30, + type: 'rectangle', + color: '#aaa', + align: 'right' + }, + + Edge: { + type: 'bezier', + color: '#444' + }, + + //This method is called on DOM label creation. + //Use this method to add styles to + //your node label. + onCreateLabel: function(label, node){ + label.id = node.id; + label.innerHTML = node.name; + //set label styles + var style = label.style; + style.fontSize = '0.7em'; + style.textAlign= 'center'; + style.paddingTop = '3px'; + style.height = node.data.$height + 'px'; + + if(node.id == st.root) { + style.color = '#eee'; + style.width = node.data.$width + 'px'; + } else { + style.color = '#fff'; + style.width = 30 + 'px'; + } + } + }); + //load json data + st.loadJSON(jsonpie3); + //compute node positions and layout + st.compute(); + //emulate a click on the root node and + //add an offset position to the tree + st.onClick(st.root, { + Move: { + offsetY: -110 + } + }); + //end +} diff --git a/Tests/Other/test2.js b/Tests/Other/test2.js new file mode 100644 index 0000000..2a38d68 --- /dev/null +++ b/Tests/Other/test2.js @@ -0,0 +1,288 @@ +function init() { + //init data + var json = { + 'id': 'root', + 'name': 'RGraph( RGraph )', + 'data': { + '$type': 'none' + }, + 'children':[ + { + 'id':'pie10', + 'name': 'pie1', + 'data': { + '$aw': 20, + '$color': '#f55' + }, + 'children': [ + { + 'id':'pie100', + 'name': 'pc1', + 'data': { + '$aw': 20, + '$color': '#55f' + }, + 'children': [] + + }, + { + 'id':'pie101', + 'name': 'pc2', + 'data': { + '$aw': 70, + '$color': '#66f' + }, + 'children': [] + + }, + { + 'id':'pie102', + 'name': 'pc3', + 'data': { + '$aw': 10, + '$color': '#77f' + }, + 'children': [] + + } + ] + }, + { + 'id':'pie20', + 'name': 'pie2', + 'data': { + '$aw': 40, + '$color': '#f77' + }, + 'children': [ + { + 'id':'pie200', + 'name': 'pc1', + 'data': { + '$aw': 40, + '$color': '#88f' + }, + 'children': [] + + }, + { + 'id':'pie201', + 'name': 'pc2', + 'data': { + '$aw': 60, + '$color': '#99f' + }, + 'children': [] + + } + ] + }, + { + 'id':'pie30', + 'name': 'pie3', + 'data': { + '$aw': 10, + '$color': '#f99' + }, + 'children': [ + { + 'id':'pie300', + 'name': 'pc1', + 'data': { + '$aw': 100, + '$color': '#aaf' + }, + 'children': [] + + } + ] + } + ] + }; + var jsonpie = { + 'id': 'root', + 'name': 'RGraph based Pie Chart', + 'data': { + '$type': 'none' + }, + 'children':[ + { + 'id':'pie1', + 'name': 'pie1', + 'data': { + '$aw': 20, + '$color': '#f55' + }, + 'children': [] + }, + { + 'id':'pie2', + 'name': 'pie2', + 'data': { + '$aw': 40, + '$color': '#f77' + }, + 'children': [] + }, + { + 'id':'pie3', + 'name': 'pie3', + 'data': { + '$aw': 10, + '$color': '#f99' + }, + 'children': [] + }, + { + 'id':'pie4', + 'name': 'pie4', + 'data': { + '$aw': 30, + '$color': '#fbb' + }, + 'children': [] + } + ] + }; + //end + + var infovis = document.getElementById('infovis'); + var w = infovis.offsetWidth, h = infovis.offsetHeight; + + //init canvas + //Create new canvas instances. + var canvas = new Canvas('mycanvas', { + 'injectInto': 'infovis', + 'width': w, + 'height': h, + + //Optional: create a background canvas and plot + //concentric circles in it. + 'backgroundCanvas': { + 'styles': { + 'strokeStyle': '#555' + }, + + 'impl': { + 'init': function(){}, + 'plot': function(canvas, ctx){ + var times = 4, d = 100; + var pi2 = Math.PI * 2; + for (var i = 1; i <= times; i++) { + ctx.beginPath(); + ctx.arc(0, 0, i * d, 0, pi2, true); + ctx.stroke(); + ctx.closePath(); + } + } + } + } + + }); + //end + + //init nodetypes + //Here we implement custom node rendering types for the RGraph + //Using this feature requires some javascript and canvas experience. + RGraph.Plot.NodeTypes.implement({ + //This node type is used for plotting pie-chart slices as nodes + 'nodepie': function(node, canvas) { + var span = node.angleSpan, begin = span.begin, end = span.end; + var polarNode = node.pos.getp(true); + var polar = new Polar(polarNode.rho, begin); + var p1coord = polar.getc(true); + polar.theta = end; + var p2coord = polar.getc(true); + + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(p1coord.x, p1coord.y); + ctx.moveTo(0, 0); + ctx.lineTo(p2coord.x, p2coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho, begin, end, false); + ctx.fill(); + }, + //Create a new node type that renders an entire RGraph visualization + //as node + 'piechart': function(node, canvas, animating) { + var ctx = canvas.getCtx(), pos = node.pos.getc(true); + ctx.save(); + ctx.translate(pos.x, pos.y); + pie.plot(); + ctx.restore(); + } + }); + //end + + //init pie + //This RGraph instance will be used as the node for + //another RGraph instance. + var pie = new RGraph(canvas, { + //Add node/edge styles and set + //overridable=true if you want your + //styles to be individually overriden + Node: { + 'overridable': true, + 'type':'nodepie' + }, + Edge: { + 'type':'none' + }, + //Parent-children distance + levelDistance: 30, + //Don't create labels in this visualization + withLabels: false, + //Don't clear the entire canvas when plotting + //this visualization + clearCanvas: false + }); + //load graph. + pie.loadJSON(jsonpie); + pie.compute(); + //end + + //init rgraph + var rgraph = new RGraph(canvas, { + //Add node/edge styles and set + //overridable=true if you want your + //styles to be individually overriden + Node: { + //set the RGraph rendering function + //as node type + 'type': 'piechart' + }, + Edge: { + color: '#772277' + }, + //Parent-children distance + levelDistance: 100, + + //Add styles to node labels on label creation + onCreateLabel: function(domElement, node){ + domElement.innerHTML = node.name; + var style = domElement.style; + style.fontSize = "0.8em"; + style.color = "#fff"; + style.cursor = "pointer"; + domElement.onclick = function() { + rgraph.onClick(node.id, { + hideLabels: false + }); + }; + }, + + onPlaceLabel: function(domElement, node){ + var style = domElement.style; + var left = parseInt(style.left); + var w = domElement.offsetWidth; + style.left = (left - w / 2) + 'px'; + style.display = ''; + }, + }); + //load graph. + rgraph.loadJSON(json); + rgraph.refresh(); + //end +} diff --git a/Tests/Other/test3.js b/Tests/Other/test3.js new file mode 100644 index 0000000..f478d1e --- /dev/null +++ b/Tests/Other/test3.js @@ -0,0 +1,288 @@ +function init() { + //init data + var json = { + 'id': 'root', + 'name': 'root', + 'data': { + //'$type': 'none' + }, + 'children':[ + { + 'id':'pie10', + 'name': 'pie1', + 'data': { + '$aw': 20, + '$color': '#f55' + }, + 'children': [ + { + 'id':'pie100', + 'name': 'pc1', + 'data': { + '$aw': 20, + '$color': '#55f' + }, + 'children': [] + + }, + { + 'id':'pie101', + 'name': 'pc2', + 'data': { + '$aw': 70, + '$color': '#66f' + }, + 'children': [] + + }, + { + 'id':'pie102', + 'name': 'pc3', + 'data': { + '$aw': 10, + '$color': '#77f' + }, + 'children': [] + + } + ] + }, + { + 'id':'pie20', + 'name': 'pie2', + 'data': { + '$aw': 40, + '$color': '#f77' + }, + 'children': [ + { + 'id':'pie200', + 'name': 'pc1', + 'data': { + '$aw': 40, + '$color': '#88f' + }, + 'children': [] + + }, + { + 'id':'pie201', + 'name': 'pc2', + 'data': { + '$aw': 60, + '$color': '#99f' + }, + 'children': [] + + } + ] + }, + { + 'id':'pie30', + 'name': 'pie3', + 'data': { + '$aw': 10, + '$color': '#f99' + }, + 'children': [ + { + 'id':'pie300', + 'name': 'pc1', + 'data': { + '$aw': 100, + '$color': '#aaf' + }, + 'children': [] + + } + ] + } + ] + }; + var jsonpie = { + 'id': 'root', + 'name': 'RGraph based Pie Chart', + 'data': { + '$type': 'none' + }, + 'children':[ + { + 'id':'pie1', + 'name': 'pie1', + 'data': { + '$aw': 20, + '$color': '#55f' + }, + 'children': [] + }, + { + 'id':'pie2', + 'name': 'pie2', + 'data': { + '$aw': 40, + '$color': '#77f' + }, + 'children': [] + }, + { + 'id':'pie3', + 'name': 'pie3', + 'data': { + '$aw': 10, + '$color': '#99f' + }, + 'children': [] + }, + { + 'id':'pie4', + 'name': 'pie4', + 'data': { + '$aw': 30, + '$color': '#bbf' + }, + 'children': [] + } + ] + }; + //end + + var infovis = document.getElementById('infovis'); + var w = infovis.offsetWidth, h = infovis.offsetHeight; + + //init canvas + //Create a new canvas instance. + var canvas = new Canvas('mycanvas', { + 'injectInto': 'infovis', + 'width': w, + 'height': h, + 'backgroundColor': '#1a1a1a' + }); + //end + + //init nodetypes + //Here we implement custom node rendering types for the RGraph + //Using this feature requires some javascript and canvas experience. + RGraph.Plot.NodeTypes.implement({ + //This node type is used for plotting pie-chart slices as nodes + 'shortnodepie': function(node, canvas) { + var ldist = this.config.levelDistance; + var span = node.angleSpan, begin = span.begin, end = span.end; + var polarNode = node.pos.getp(true); + + var polar = new Polar(polarNode.rho, begin); + var p1coord = polar.getc(true); + + polar.theta = end; + var p2coord = polar.getc(true); + + polar.rho += ldist; + var p3coord = polar.getc(true); + + polar.theta = begin; + var p4coord = polar.getc(true); + + + var ctx = canvas.getCtx(); + ctx.beginPath(); + ctx.moveTo(p1coord.x, p1coord.y); + ctx.lineTo(p4coord.x, p4coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho, begin, end, false); + + ctx.moveTo(p2coord.x, p2coord.y); + ctx.lineTo(p3coord.x, p3coord.y); + ctx.moveTo(0, 0); + ctx.arc(0, 0, polarNode.rho + ldist, end, begin, true); + + ctx.fill(); + } + }); + + ST.Plot.NodeTypes.implement({ + //Create a new node type that renders an entire RGraph visualization + 'piechart': function(node, canvas, animating) { + var ctx = canvas.getCtx(), pos = node.pos.getc(true); + ctx.save(); + ctx.translate(pos.x, pos.y); + pie.plot(); + ctx.restore(); + } + }); + //end + + //init pie + var pie = new RGraph(canvas, { + //Add node/edge styles and set + //overridable=true if you want your + //styles to be individually overriden + Node: { + 'overridable': true, + 'type':'shortnodepie' + }, + Edge: { + 'type':'none' + }, + //Parent-children distance + levelDistance: 15, + //Don't create labels for this visualization + withLabels: false, + //Don't clear the canvas when plotting + clearCanvas: false + }); + //load graph. + pie.loadJSON(jsonpie); + pie.compute(); + //end + + //init st + var st = new ST(canvas, { + orientation: 'bottom', + //Add node/edge styles + Node: { + 'type': 'piechart', + width: 60, + height: 60 + }, + Edge: { + color: '#999', + type: 'quadratic:begin' + }, + //Parent-children distance + levelDistance: 60, + + //Add styles to node labels on label creation + onCreateLabel: function(domElement, node){ + //add some styles to the node label + var style = domElement.style; + domElement.id = node.id; + style.color = '#fff'; + style.fontSize = '0.8em'; + style.textAlign = 'center'; + style.width = "60px"; + style.height = "24px"; + style.paddingTop = "22px"; + style.cursor = 'pointer'; + domElement.innerHTML = node.name; + domElement.onclick = function() { + st.onClick(node.id, { + Move: { + offsetY: -90 + } + }); + }; + } + }); + //load json data + st.loadJSON(json); + //compute node positions and layout + st.compute(); + //optional: make a translation of the tree + st.geom.translate(new Complex(0, 200), "startPos"); + //Emulate a click on the root node. + st.onClick(st.root, { + Move: { + offsetY: -90 + } + }); + //end +} diff --git a/Tests/RGraph/test1.js b/Tests/RGraph/test1.js index 2b3f6ef..5da6cee 100644 --- a/Tests/RGraph/test1.js +++ b/Tests/RGraph/test1.js @@ -1,13 +1,4 @@ function init(){ - 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'; - } - }; //init data var json = { id: "190_0", diff --git a/Tests/RGraph/test2.js b/Tests/RGraph/test2.js index 2e7644c..960ed7d 100644 --- a/Tests/RGraph/test2.js +++ b/Tests/RGraph/test2.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "190_0", "name": "Pearl Jam", diff --git a/Tests/RGraph/test3.js b/Tests/RGraph/test3.js index b46af23..1f7ff75 100644 --- a/Tests/RGraph/test3.js +++ b/Tests/RGraph/test3.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var json = { "id": "190_0", "name": "Pearl Jam", diff --git a/Tests/RGraph/test4.js b/Tests/RGraph/test4.js index dc22b89..05478d1 100644 --- a/Tests/RGraph/test4.js +++ b/Tests/RGraph/test4.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = { diff --git a/Tests/RGraph/test5.js b/Tests/RGraph/test5.js index 3b921c1..68fbde7 100644 --- a/Tests/RGraph/test5.js +++ b/Tests/RGraph/test5.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = { diff --git a/Tests/RGraph/test6.js b/Tests/RGraph/test6.js index dc61121..3967678 100644 --- a/Tests/RGraph/test6.js +++ b/Tests/RGraph/test6.js @@ -1,13 +1,4 @@ function init(){ - 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'; - } - }; var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; //init data @@ -287,6 +278,9 @@ function init(){ //Change father-child distance. levelDistance: 200, + //This method is called right before plotting + //an edge. This method is useful to change edge styles + //individually. onBeforePlotLine: function(adj){ //Add some random lineWidth to each edge. if (!adj.data.$lineWidth) @@ -308,6 +302,7 @@ function init(){ }, //Add node click handler and some styles. + //This method is called only once for each node/label crated. onCreateLabel: function(domElement, node){ domElement.innerHTML = node.name; domElement.onclick = function () { @@ -318,7 +313,9 @@ function init(){ style.fontSize = "0.8em"; style.color = "#fff"; }, - + //This method is called when rendering/moving a label. + //This is method is useful to make some last minute changes + //to node labels like adding some position offset. onPlaceLabel: function(domElement, node){ var style = domElement.style; var left = parseInt(style.left); diff --git a/Tests/RGraph/test7.js b/Tests/RGraph/test7.js index faf81a7..ba003d6 100644 --- a/Tests/RGraph/test7.js +++ b/Tests/RGraph/test7.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var hoveredNode = false; diff --git a/Tests/RGraph/test8.js b/Tests/RGraph/test8.js index 8efabbd..3fd065f 100644 --- a/Tests/RGraph/test8.js +++ b/Tests/RGraph/test8.js @@ -1,14 +1,4 @@ function init(){ - 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'; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; @@ -462,10 +452,14 @@ function init(){ color: '#772277' }, //Add the node's name into the label + //This method is called only once, on label creation. onCreateLabel: function(domElement, node){ domElement.innerHTML = node.name; }, + //Change the node's style based on its position. + //This method is called each time a label is rendered/positioned + //during an animation. onPlaceLabel: function(domElement, node){ var style = domElement.style; style.display = ''; diff --git a/Tests/Spacetree/test1.js b/Tests/Spacetree/test1.js index 2c12caa..08c112f 100644 --- a/Tests/Spacetree/test1.js +++ b/Tests/Spacetree/test1.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = Feeder.makeTree(); diff --git a/Tests/Spacetree/test2.js b/Tests/Spacetree/test2.js index a4ff2e0..40ef94c 100644 --- a/Tests/Spacetree/test2.js +++ b/Tests/Spacetree/test2.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = Feeder.makeTree(); diff --git a/Tests/Spacetree/test3.js b/Tests/Spacetree/test3.js index e18ae86..2bcf917 100644 --- a/Tests/Spacetree/test3.js +++ b/Tests/Spacetree/test3.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = Feeder.makeTree(); diff --git a/Tests/Spacetree/test4.js b/Tests/Spacetree/test4.js index dbbc5db..277d304 100644 --- a/Tests/Spacetree/test4.js +++ b/Tests/Spacetree/test4.js @@ -1,12 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = Feeder.makeTree({ diff --git a/Tests/Spacetree/test5.js b/Tests/Spacetree/test5.js index 21be087..2e8e946 100644 --- a/Tests/Spacetree/test5.js +++ b/Tests/Spacetree/test5.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = Feeder.makeTree({ diff --git a/Tests/Spacetree/test6.js b/Tests/Spacetree/test6.js index cc1a65c..fc79190 100644 --- a/Tests/Spacetree/test6.js +++ b/Tests/Spacetree/test6.js @@ -1,13 +1,4 @@ function init(){ - var Log = { - elem: false, - write: function(text){ - if (!this.elem) - this.elem = document.getElementById('log'); - this.elem.innerHTML = text; - } - }; - var infovis = document.getElementById('infovis'); var w = infovis.offsetWidth, h = infovis.offsetHeight; var json = Feeder.makeTree(); diff --git a/Tests/Spacetree/test7.js b/Tests/Spacetree/test7.js index f1f5072..c8553f0 100644 --- a/Tests/Spacetree/test7.js +++ b/Tests/Spacetree/test7.js @@ -1,13 +1,4 @@ function init(){ - 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 get(id) { return document.getElementById(id); }; @@ -752,7 +743,7 @@ function init(){ 'injectInto': 'infovis', 'width': w, 'height': h, - 'backgroundColor': '#222' + 'backgroundColor': '#1a1a1a' }); //end @@ -859,7 +850,7 @@ function init(){ st.geom.translate(new Complex(-200, 0), "startPos"); //emulate a click on the root node. st.onClick(st.root); - + //end //Add event handlers to switch spacetree orientation. var top = get('r-top'), left = get('r-left'), diff --git a/Tests/Spacetree/test8.js b/Tests/Spacetree/test8.js new file mode 100644 index 0000000..5d1d826 --- /dev/null +++ b/Tests/Spacetree/test8.js @@ -0,0 +1,197 @@ +function init(){ + //init data + var json = "{id:\"node02\", name:\"0.2\", data:{}, children:[{id:\"node13\", name:\"1.3\", data:{}, children:[{id:\"node24\", name:\"2.4\", data:{}, children:[{id:\"node35\", name:\"3.5\", data:{}, children:[{id:\"node46\", name:\"4.6\", data:{}, children:[]}]}, {id:\"node37\", name:\"3.7\", data:{}, children:[{id:\"node48\", name:\"4.8\", data:{}, children:[]}, {id:\"node49\", name:\"4.9\", data:{}, children:[]}, {id:\"node410\", name:\"4.10\", data:{}, children:[]}, {id:\"node411\", name:\"4.11\", data:{}, children:[]}]}, {id:\"node312\", name:\"3.12\", data:{}, children:[{id:\"node413\", name:\"4.13\", data:{}, children:[]}]}, {id:\"node314\", name:\"3.14\", data:{}, children:[{id:\"node415\", name:\"4.15\", data:{}, children:[]}, {id:\"node416\", name:\"4.16\", data:{}, children:[]}, {id:\"node417\", name:\"4.17\", data:{}, children:[]}, {id:\"node418\", name:\"4.18\", data:{}, children:[]}]}, {id:\"node319\", name:\"3.19\", data:{}, children:[{id:\"node420\", name:\"4.20\", data:{}, children:[]}, {id:\"node421\", name:\"4.21\", data:{}, children:[]}]}]}, {id:\"node222\", name:\"2.22\", data:{}, children:[{id:\"node323\", name:\"3.23\", data:{}, children:[{id:\"node424\", name:\"4.24\", data:{}, children:[]}]}]}]}, {id:\"node125\", name:\"1.25\", data:{}, children:[{id:\"node226\", name:\"2.26\", data:{}, children:[{id:\"node327\", name:\"3.27\", data:{}, children:[{id:\"node428\", name:\"4.28\", data:{}, children:[]}, {id:\"node429\", name:\"4.29\", data:{}, children:[]}]}, {id:\"node330\", name:\"3.30\", data:{}, children:[{id:\"node431\", name:\"4.31\", data:{}, children:[]}]}, {id:\"node332\", name:\"3.32\", data:{}, children:[{id:\"node433\", name:\"4.33\", data:{}, children:[]}, {id:\"node434\", name:\"4.34\", data:{}, children:[]}, {id:\"node435\", name:\"4.35\", data:{}, children:[]}, {id:\"node436\", name:\"4.36\", data:{}, children:[]}]}]}, {id:\"node237\", name:\"2.37\", data:{}, children:[{id:\"node338\", name:\"3.38\", data:{}, children:[{id:\"node439\", name:\"4.39\", data:{}, children:[]}, {id:\"node440\", name:\"4.40\", data:{}, children:[]}, {id:\"node441\", name:\"4.41\", data:{}, children:[]}]}, {id:\"node342\", name:\"3.42\", data:{}, children:[{id:\"node443\", name:\"4.43\", data:{}, children:[]}]}, {id:\"node344\", name:\"3.44\", data:{}, children:[{id:\"node445\", name:\"4.45\", data:{}, children:[]}, {id:\"node446\", name:\"4.46\", data:{}, children:[]}, {id:\"node447\", name:\"4.47\", data:{}, children:[]}]}, {id:\"node348\", name:\"3.48\", data:{}, children:[{id:\"node449\", name:\"4.49\", data:{}, children:[]}, {id:\"node450\", name:\"4.50\", data:{}, children:[]}, {id:\"node451\", name:\"4.51\", data:{}, children:[]}, {id:\"node452\", name:\"4.52\", data:{}, children:[]}, {id:\"node453\", name:\"4.53\", data:{}, children:[]}]}, {id:\"node354\", name:\"3.54\", data:{}, children:[{id:\"node455\", name:\"4.55\", data:{}, children:[]}, {id:\"node456\", name:\"4.56\", data:{}, children:[]}, {id:\"node457\", name:\"4.57\", data:{}, children:[]}]}]}, {id:\"node258\", name:\"2.58\", data:{}, children:[{id:\"node359\", name:\"3.59\", data:{}, children:[{id:\"node460\", name:\"4.60\", data:{}, children:[]}, {id:\"node461\", name:\"4.61\", data:{}, children:[]}, {id:\"node462\", name:\"4.62\", data:{}, children:[]}, {id:\"node463\", name:\"4.63\", data:{}, children:[]}, {id:\"node464\", name:\"4.64\", data:{}, children:[]}]}]}]}, {id:\"node165\", name:\"1.65\", data:{}, children:[{id:\"node266\", name:\"2.66\", data:{}, children:[{id:\"node367\", name:\"3.67\", data:{}, children:[{id:\"node468\", name:\"4.68\", data:{}, children:[]}, {id:\"node469\", name:\"4.69\", data:{}, children:[]}, {id:\"node470\", name:\"4.70\", data:{}, children:[]}, {id:\"node471\", name:\"4.71\", data:{}, children:[]}]}, {id:\"node372\", name:\"3.72\", data:{}, children:[{id:\"node473\", name:\"4.73\", data:{}, children:[]}, {id:\"node474\", name:\"4.74\", data:{}, children:[]}, {id:\"node475\", name:\"4.75\", data:{}, children:[]}, {id:\"node476\", name:\"4.76\", data:{}, children:[]}]}, {id:\"node377\", name:\"3.77\", data:{}, children:[{id:\"node478\", name:\"4.78\", data:{}, children:[]}, {id:\"node479\", name:\"4.79\", data:{}, children:[]}]}, {id:\"node380\", name:\"3.80\", data:{}, children:[{id:\"node481\", name:\"4.81\", data:{}, children:[]}, {id:\"node482\", name:\"4.82\", data:{}, children:[]}]}]}, {id:\"node283\", name:\"2.83\", data:{}, children:[{id:\"node384\", name:\"3.84\", data:{}, children:[{id:\"node485\", name:\"4.85\", data:{}, children:[]}]}, {id:\"node386\", name:\"3.86\", data:{}, children:[{id:\"node487\", name:\"4.87\", data:{}, children:[]}, {id:\"node488\", name:\"4.88\", data:{}, children:[]}, {id:\"node489\", name:\"4.89\", data:{}, children:[]}, {id:\"node490\", name:\"4.90\", data:{}, children:[]}, {id:\"node491\", name:\"4.91\", data:{}, children:[]}]}, {id:\"node392\", name:\"3.92\", data:{}, children:[{id:\"node493\", name:\"4.93\", data:{}, children:[]}, {id:\"node494\", name:\"4.94\", data:{}, children:[]}, {id:\"node495\", name:\"4.95\", data:{}, children:[]}, {id:\"node496\", name:\"4.96\", data:{}, children:[]}]}, {id:\"node397\", name:\"3.97\", data:{}, children:[{id:\"node498\", name:\"4.98\", data:{}, children:[]}]}, {id:\"node399\", name:\"3.99\", data:{}, children:[{id:\"node4100\", name:\"4.100\", data:{}, children:[]}, {id:\"node4101\", name:\"4.101\", data:{}, children:[]}, {id:\"node4102\", name:\"4.102\", data:{}, children:[]}, {id:\"node4103\", name:\"4.103\", data:{}, children:[]}]}]}, {id:\"node2104\", name:\"2.104\", data:{}, children:[{id:\"node3105\", name:\"3.105\", data:{}, children:[{id:\"node4106\", name:\"4.106\", data:{}, children:[]}, {id:\"node4107\", name:\"4.107\", data:{}, children:[]}, {id:\"node4108\", name:\"4.108\", data:{}, children:[]}]}]}, {id:\"node2109\", name:\"2.109\", data:{}, children:[{id:\"node3110\", name:\"3.110\", data:{}, children:[{id:\"node4111\", name:\"4.111\", data:{}, children:[]}, {id:\"node4112\", name:\"4.112\", data:{}, children:[]}]}, {id:\"node3113\", name:\"3.113\", data:{}, children:[{id:\"node4114\", name:\"4.114\", data:{}, children:[]}, {id:\"node4115\", name:\"4.115\", data:{}, children:[]}, {id:\"node4116\", name:\"4.116\", data:{}, children:[]}]}, {id:\"node3117\", name:\"3.117\", data:{}, children:[{id:\"node4118\", name:\"4.118\", data:{}, children:[]}, {id:\"node4119\", name:\"4.119\", data:{}, children:[]}, {id:\"node4120\", name:\"4.120\", data:{}, children:[]}, {id:\"node4121\", name:\"4.121\", data:{}, children:[]}]}, {id:\"node3122\", name:\"3.122\", data:{}, children:[{id:\"node4123\", name:\"4.123\", data:{}, children:[]}, {id:\"node4124\", name:\"4.124\", data:{}, children:[]}]}]}, {id:\"node2125\", name:\"2.125\", data:{}, children:[{id:\"node3126\", name:\"3.126\", data:{}, children:[{id:\"node4127\", name:\"4.127\", data:{}, children:[]}, {id:\"node4128\", name:\"4.128\", data:{}, children:[]}, {id:\"node4129\", name:\"4.129\", data:{}, children:[]}]}]}]}, {id:\"node1130\", name:\"1.130\", data:{}, children:[{id:\"node2131\", name:\"2.131\", data:{}, children:[{id:\"node3132\", name:\"3.132\", data:{}, children:[{id:\"node4133\", name:\"4.133\", data:{}, children:[]}, {id:\"node4134\", name:\"4.134\", data:{}, children:[]}, {id:\"node4135\", name:\"4.135\", data:{}, children:[]}, {id:\"node4136\", name:\"4.136\", data:{}, children:[]}, {id:\"node4137\", name:\"4.137\", data:{}, children:[]}]}]}, {id:\"node2138\", name:\"2.138\", data:{}, children:[{id:\"node3139\", name:\"3.139\", data:{}, children:[{id:\"node4140\", name:\"4.140\", data:{}, children:[]}, {id:\"node4141\", name:\"4.141\", data:{}, children:[]}]}, {id:\"node3142\", name:\"3.142\", data:{}, children:[{id:\"node4143\", name:\"4.143\", data:{}, children:[]}, {id:\"node4144\", name:\"4.144\", data:{}, children:[]}, {id:\"node4145\", name:\"4.145\", data:{}, children:[]}, {id:\"node4146\", name:\"4.146\", data:{}, children:[]}, {id:\"node4147\", name:\"4.147\", data:{}, children:[]}]}]}]}]}"; + //end + + //A client-side tree generator + var getTree = (function() { + var i = 0; + return function(nodeId, level) { + var subtree = eval('(' + json.replace(/id:\"([a-zA-Z0-9]+)\"/g, + function(all, match) { + return "id:\"" + match + "_" + i + "\"" + }) + ')'); + TreeUtil.prune(subtree, level); i++; + return { + 'id': nodeId, + 'children': subtree.children + }; + }; + })(); + + var infovis = document.getElementById('infovis'); + var w = infovis.offsetWidth, h = infovis.offsetHeight; + //init canvas + //Create a new canvas instance. + var canvas = new Canvas('mycanvas', { + 'injectInto': 'infovis', + 'width': w, + 'height': h, + 'backgroundColor': '#1a1a1a' + }); + //end + + + //Implement a node rendering function called 'nodeline' that plots a straight line + //when contracting or expanding a subtree. + ST.Plot.NodeTypes.implement({ + 'nodeline': function(node, canvas, animating) { + if(animating === 'expand' || animating === 'contract') { + var pos = node.pos.getc(true), nconfig = this.node, data = node.data; + var width = nconfig.width, height = nconfig.height; + var algnPos = this.getAlignedPos(pos, width, height); + var ctx = canvas.getCtx(), ort = this.config.orientation; + ctx.beginPath(); + if(ort == 'left' || ort == 'right') { + ctx.moveTo(algnPos.x, algnPos.y + height / 2); + ctx.lineTo(algnPos.x + width, algnPos.y + height / 2); + } else { + ctx.moveTo(algnPos.x + width / 2, algnPos.y); + ctx.lineTo(algnPos.x + width / 2, algnPos.y + height); + } + ctx.stroke(); + } + } + }); + + //init st + //Create a new ST instance + var st = new ST(canvas, { + //set duration for the animation + duration: 800, + //set animation transition type + transition: Trans.Quart.easeInOut, + //set distance between node and its children + levelDistance: 50, + //set max levels to show. Useful when used with + //the request method for requesting trees of specific depth + levelsToShow: 2, + //set node and edge styles + //set overridable=true for styling individual + //nodes or edges + Node: { + height: 20, + width: 40, + //use a custom + //node rendering function + type: 'nodeline', + color:'#23A4FF', + lineWidth: 2, + align:"center", + overridable: true + }, + + Edge: { + type: 'bezier', + lineWidth: 2, + color:'#23A4FF', + overridable: true + }, + + //Add a request method for requesting on-demand json trees. + //This method gets called when a node + //is clicked and its subtree has a smaller depth + //than the one specified by the levelsToShow parameter. + //In that case a subtree is requested and is added to the dataset. + //This method is asynchronous, so you can make an Ajax request for that + //subtree and then handle it to the onComplete callback. + //Here we just use a client-side tree generator (the getTree function). + request: function(nodeId, level, onComplete) { + var ans = getTree(nodeId, level); + onComplete.onComplete(nodeId, ans); + }, + + onBeforeCompute: function(node){ + Log.write("loading " + node.name); + }, + + onAfterCompute: function(){ + Log.write("done"); + }, + + //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.id = node.id; + label.innerHTML = node.name; + label.onclick = function(){ + st.onClick(node.id); + }; + //set label styles + var style = label.style; + style.width = 40 + 'px'; + style.height = 17 + 'px'; + style.cursor = 'pointer'; + style.color = '#fff'; + //style.backgroundColor = '#1a1a1a'; + style.fontSize = '0.8em'; + style.textAlign= 'center'; + style.textDecoration = 'underline'; + style.paddingTop = '3px'; + }, + + //This method is called right before plotting + //a node. It's useful for changing an individual node + //style properties before plotting it. + //The data properties prefixed with a dollar + //sign will override the global node style properties. + onBeforePlotNode: function(node){ + //add some color to the nodes in the path between the + //root node and the selected node. + if (node.selected) { + node.data.$color = "#ff7"; + } + else { + delete node.data.$color; + } + }, + + //This method is called right before plotting + //an edge. It's useful for changing an individual edge + //style properties before plotting it. + //Edge data proprties prefixed with a dollar sign will + //override the Edge global style properties. + onBeforePlotLine: function(adj){ + if (adj.nodeFrom.selected && adj.nodeTo.selected) { + adj.data.$color = "#eed"; + adj.data.$lineWidth = 3; + } + else { + delete adj.data.$color; + delete adj.data.$lineWidth; + } + } + }); + //load json data + st.loadJSON(eval( '(' + json + ')' )); + //compute node positions and layout + st.compute(); + //emulate a click on the root node. + st.onClick(st.root); + //end + //Add event handlers to switch spacetree orientation. + function get(id) { + return document.getElementById(id); + }; + + var top = get('r-top'), + left = get('r-left'), + bottom = get('r-bottom'), + right = get('r-right'); + + function changeHandler() { + if(this.checked) { + top.disabled = bottom.disabled = right.disabled = left.disabled = true; + st.switchPosition(this.value, { + onComplete: function(){ + top.disabled = bottom.disabled = right.disabled = left.disabled = false; + } + }); + } + }; + + top.onchange = left.onchange = bottom.onchange = right.onchange = changeHandler; + //end + +} diff --git a/Tests/Spacetree/test9.js b/Tests/Spacetree/test9.js new file mode 100644 index 0000000..c449b6c --- /dev/null +++ b/Tests/Spacetree/test9.js @@ -0,0 +1,848 @@ +function init(){ + var infovis = document.getElementById('infovis'); + var w = infovis.offsetWidth, h = infovis.offsetHeight; + //init data + var json = { + id: "node02", + name: "0.2", + data: {}, + children: [{ + id: "node13", + name: "1.3", + data: {}, + children: [{ + id: "node24", + name: "2.4", + data: {}, + children: [{ + id: "node35", + name: "3.5", + data: {}, + children: [{ + id: "node46", + name: "4.6", + data: {}, + children: [] + }] + }, { + id: "node37", + name: "3.7", + data: {}, + children: [{ + id: "node48", + name: "4.8", + data: {}, + children: [] + }, { + id: "node49", + name: "4.9", + data: {}, + children: [] + }, { + id: "node410", + name: "4.10", + data: {}, + children: [] + }, { + id: "node411", + name: "4.11", + data: {}, + children: [] + }] + }, { + id: "node312", + name: "3.12", + data: {}, + children: [{ + id: "node413", + name: "4.13", + data: {}, + children: [] + }] + }, { + id: "node314", + name: "3.14", + data: {}, + children: [{ + id: "node415", + name: "4.15", + data: {}, + children: [] + }, { + id: "node416", + name: "4.16", + data: {}, + children: [] + }, { + id: "node417", + name: "4.17", + data: {}, + children: [] + }, { + id: "node418", + name: "4.18", + data: {}, + children: [] + }] + }, { + id: "node319", + name: "3.19", + data: {}, + children: [{ + id: "node420", + name: "4.20", + data: {}, + children: [] + }, { + id: "node421", + name: "4.21", + data: {}, + children: [] + }] + }] + }, { + id: "node222", + name: "2.22", + data: {}, + children: [{ + id: "node323", + name: "3.23", + data: {}, + children: [{ + id: "node424", + name: "4.24", + data: {}, + children: [] + }] + }] + }] + }, { + id: "node125", + name: "1.25", + data: {}, + children: [{ + id: "node226", + name: "2.26", + data: {}, + children: [{ + id: "node327", + name: "3.27", + data: {}, + children: [{ + id: "node428", + name: "4.28", + data: {}, + children: [] + }, { + id: "node429", + name: "4.29", + data: {}, + children: [] + }] + }, { + id: "node330", + name: "3.30", + data: {}, + children: [{ + id: "node431", + name: "4.31", + data: {}, + children: [] + }] + }, { + id: "node332", + name: "3.32", + data: {}, + children: [{ + id: "node433", + name: "4.33", + data: {}, + children: [] + }, { + id: "node434", + name: "4.34", + data: {}, + children: [] + }, { + id: "node435", + name: "4.35", + data: {}, + children: [] + }, { + id: "node436", + name: "4.36", + data: {}, + children: [] + }] + }] + }, { + id: "node237", + name: "2.37", + data: {}, + children: [{ + id: "node338", + name: "3.38", + data: {}, + children: [{ + id: "node439", + name: "4.39", + data: {}, + children: [] + }, { + id: "node440", + name: "4.40", + data: {}, + children: [] + }, { + id: "node441", + name: "4.41", + data: {}, + children: [] + }] + }, { + id: "node342", + name: "3.42", + data: {}, + children: [{ + id: "node443", + name: "4.43", + data: {}, + children: [] + }] + }, { + id: "node344", + name: "3.44", + data: {}, + children: [{ + id: "node445", + name: "4.45", + data: {}, + children: [] + }, { + id: "node446", + name: "4.46", + data: {}, + children: [] + }, { + id: "node447", + name: "4.47", + data: {}, + children: [] + }] + }, { + id: "node348", + name: "3.48", + data: {}, + children: [{ + id: "node449", + name: "4.49", + data: {}, + children: [] + }, { + id: "node450", + name: "4.50", + data: {}, + children: [] + }, { + id: "node451", + name: "4.51", + data: {}, + children: [] + }, { + id: "node452", + name: "4.52", + data: {}, + children: [] + }, { + id: "node453", + name: "4.53", + data: {}, + children: [] + }] + }, { + id: "node354", + name: "3.54", + data: {}, + children: [{ + id: "node455", + name: "4.55", + data: {}, + children: [] + }, { + id: "node456", + name: "4.56", + data: {}, + children: [] + }, { + id: "node457", + name: "4.57", + data: {}, + children: [] + }] + }] + }, { + id: "node258", + name: "2.58", + data: {}, + children: [{ + id: "node359", + name: "3.59", + data: {}, + children: [{ + id: "node460", + name: "4.60", + data: {}, + children: [] + }, { + id: "node461", + name: "4.61", + data: {}, + children: [] + }, { + id: "node462", + name: "4.62", + data: {}, + children: [] + }, { + id: "node463", + name: "4.63", + data: {}, + children: [] + }, { + id: "node464", + name: "4.64", + data: {}, + children: [] + }] + }] + }] + }, { + id: "node165", + name: "1.65", + data: {}, + children: [{ + id: "node266", + name: "2.66", + data: {}, + children: [{ + id: "node367", + name: "3.67", + data: {}, + children: [{ + id: "node468", + name: "4.68", + data: {}, + children: [] + }, { + id: "node469", + name: "4.69", + data: {}, + children: [] + }, { + id: "node470", + name: "4.70", + data: {}, + children: [] + }, { + id: "node471", + name: "4.71", + data: {}, + children: [] + }] + }, { + id: "node372", + name: "3.72", + data: {}, + children: [{ + id: "node473", + name: "4.73", + data: {}, + children: [] + }, { + id: "node474", + name: "4.74", + data: {}, + children: [] + }, { + id: "node475", + name: "4.75", + data: {}, + children: [] + }, { + id: "node476", + name: "4.76", + data: {}, + children: [] + }] + }, { + id: "node377", + name: "3.77", + data: {}, + children: [{ + id: "node478", + name: "4.78", + data: {}, + children: [] + }, { + id: "node479", + name: "4.79", + data: {}, + children: [] + }] + }, { + id: "node380", + name: "3.80", + data: {}, + children: [{ + id: "node481", + name: "4.81", + data: {}, + children: [] + }, { + id: "node482", + name: "4.82", + data: {}, + children: [] + }] + }] + }, { + id: "node283", + name: "2.83", + data: {}, + children: [{ + id: "node384", + name: "3.84", + data: {}, + children: [{ + id: "node485", + name: "4.85", + data: {}, + children: [] + }] + }, { + id: "node386", + name: "3.86", + data: {}, + children: [{ + id: "node487", + name: "4.87", + data: {}, + children: [] + }, { + id: "node488", + name: "4.88", + data: {}, + children: [] + }, { + id: "node489", + name: "4.89", + data: {}, + children: [] + }, { + id: "node490", + name: "4.90", + data: {}, + children: [] + }, { + id: "node491", + name: "4.91", + data: {}, + children: [] + }] + }, { + id: "node392", + name: "3.92", + data: {}, + children: [{ + id: "node493", + name: "4.93", + data: {}, + children: [] + }, { + id: "node494", + name: "4.94", + data: {}, + children: [] + }, { + id: "node495", + name: "4.95", + data: {}, + children: [] + }, { + id: "node496", + name: "4.96", + data: {}, + children: [] + }] + }, { + id: "node397", + name: "3.97", + data: {}, + children: [{ + id: "node498", + name: "4.98", + data: {}, + children: [] + }] + }, { + id: "node399", + name: "3.99", + data: {}, + children: [{ + id: "node4100", + name: "4.100", + data: {}, + children: [] + }, { + id: "node4101", + name: "4.101", + data: {}, + children: [] + }, { + id: "node4102", + name: "4.102", + data: {}, + children: [] + }, { + id: "node4103", + name: "4.103", + data: {}, + children: [] + }] + }] + }, { + id: "node2104", + name: "2.104", + data: {}, + children: [{ + id: "node3105", + name: "3.105", + data: {}, + children: [{ + id: "node4106", + name: "4.106", + data: {}, + children: [] + }, { + id: "node4107", + name: "4.107", + data: {}, + children: [] + }, { + id: "node4108", + name: "4.108", + data: {}, + children: [] + }] + }] + }, { + id: "node2109", + name: "2.109", + data: {}, + children: [{ + id: "node3110", + name: "3.110", + data: {}, + children: [{ + id: "node4111", + name: "4.111", + data: {}, + children: [] + }, { + id: "node4112", + name: "4.112", + data: {}, + children: [] + }] + }, { + id: "node3113", + name: "3.113", + data: {}, + children: [{ + id: "node4114", + name: "4.114", + data: {}, + children: [] + }, { + id: "node4115", + name: "4.115", + data: {}, + children: [] + }, { + id: "node4116", + name: "4.116", + data: {}, + children: [] + }] + }, { + id: "node3117", + name: "3.117", + data: {}, + children: [{ + id: "node4118", + name: "4.118", + data: {}, + children: [] + }, { + id: "node4119", + name: "4.119", + data: {}, + children: [] + }, { + id: "node4120", + name: "4.120", + data: {}, + children: [] + }, { + id: "node4121", + name: "4.121", + data: {}, + children: [] + }] + }, { + id: "node3122", + name: "3.122", + data: {}, + children: [{ + id: "node4123", + name: "4.123", + data: {}, + children: [] + }, { + id: "node4124", + name: "4.124", + data: {}, + children: [] + }] + }] + }, { + id: "node2125", + name: "2.125", + data: {}, + children: [{ + id: "node3126", + name: "3.126", + data: {}, + children: [{ + id: "node4127", + name: "4.127", + data: {}, + children: [] + }, { + id: "node4128", + name: "4.128", + data: {}, + children: [] + }, { + id: "node4129", + name: "4.129", + data: {}, + children: [] + }] + }] + }] + }, { + id: "node1130", + name: "1.130", + data: {}, + children: [{ + id: "node2131", + name: "2.131", + data: {}, + children: [{ + id: "node3132", + name: "3.132", + data: {}, + children: [{ + id: "node4133", + name: "4.133", + data: {}, + children: [] + }, { + id: "node4134", + name: "4.134", + data: {}, + children: [] + }, { + id: "node4135", + name: "4.135", + data: {}, + children: [] + }, { + id: "node4136", + name: "4.136", + data: {}, + children: [] + }, { + id: "node4137", + name: "4.137", + data: {}, + children: [] + }] + }] + }, { + id: "node2138", + name: "2.138", + data: {}, + children: [{ + id: "node3139", + name: "3.139", + data: {}, + children: [{ + id: "node4140", + name: "4.140", + data: {}, + children: [] + }, { + id: "node4141", + name: "4.141", + data: {}, + children: [] + }] + }, { + id: "node3142", + name: "3.142", + data: {}, + children: [{ + id: "node4143", + name: "4.143", + data: {}, + children: [] + }, { + id: "node4144", + name: "4.144", + data: {}, + children: [] + }, { + id: "node4145", + name: "4.145", + data: {}, + children: [] + }, { + id: "node4146", + name: "4.146", + data: {}, + children: [] + }, { + id: "node4147", + name: "4.147", + data: {}, + children: [] + }] + }] + }] + }] + }; + var subtree = json.children.pop(); + //end + var removing = false; + //init canvas + //Create a new canvas instance. + var canvas = new Canvas('mycanvas', { + 'injectInto': 'infovis', + 'width': w, + 'height': h, + 'backgroundColor': '#1a1a1a' + }); + //end + + //init st + //Create a new ST instance + var st = new ST(canvas, { + //add styles/shapes/colors + //to nodes and edges + + //set overridable=true if you want + //to set styles for nodes individually + Node: { + overridable: true, + width: 60, + height: 20, + color: '#ccc' + }, + //change the animation/transition effect + transition: Trans.Quart.easeOut, + + onBeforeCompute: function(node){ + Log.write("loading " + node.name); + }, + + onAfterCompute: function(node){ + Log.write("done"); + }, + + //This method is triggered on label + //creation. This means that for each node + //this method is triggered only once. + //This method is useful for adding event + //handlers to each node label. + onCreateLabel: function(label, node){ + //add some styles to the node label + var style = label.style; + label.id = node.id; + style.color = '#333'; + style.fontSize = '0.8em'; + style.textAlign = 'center'; + style.width = "60px"; + style.height = "20px"; + label.innerHTML = node.name; + //Delete the specified subtree + //when clicking on a label. + //Only apply this method for nodes + //in the first level of the tree. + if(node._depth == 1) { + style.cursor = 'pointer'; + label.onclick = function() { + if(!removing) { + removing = true; + Log.write("removing subtree..."); + //remove the subtree + st.removeSubtree(label.id, true, 'animate', { + hideLabels: false, + onAfterCompute: function() { + removing = false; + Log.write("subtree removed"); + } + }); + } + } + }; + }, + //This method is triggered right before plotting a node. + //This method is useful for adding style + //to a node before it's being rendered. + onBeforePlotNode: function(node) { + if (node._depth == 1) { + node.data.$color = '#f77'; + } + } + }); + //load json data + st.loadJSON(json); + //compute node positions and layout + st.compute(); + //optional: make a translation of the tree + st.geom.translate(new Complex(-200, 0), "startPos"); + //Emulate a click on the root node. + st.onClick(st.root); + //end + + //init handler + //Add an event handler to the add button for + //adding a subtree. + var animate = document.getElementById('animate'); + var addButton = document.getElementById('addSubtree'); + addButton.onclick = function() { + var type = animate.checked? "animate" : "replot"; + subtree.id = "node02"; + Log.write("adding subtree..."); + //add the subtree + st.addSubtree(subtree, type, { + hideLabels: false, + onAfterCompute: function() { + Log.write("subtree added"); + } + }); + }; + //end +} diff --git a/Tests/Treemap/test3.js b/Tests/Treemap/test3.js index dde8207..36caae4 100644 --- a/Tests/Treemap/test3.js +++ b/Tests/Treemap/test3.js @@ -10,12 +10,50 @@ function init(){ var w = infovis.offsetWidth, h = infovis.offsetHeight; infovis.style.width = w + 'px'; infovis.style.height = h + 'px'; + //init tm var tm = new TM.Squarified({ //The id of the treemap container rootId: 'infovis', //Set the max. depth to be shown for a subtree levelsToShow: 1, + + //Add click handlers for + //zooming the Treemap in and out + addLeftClickHandler: true, + addRightClickHandler: true, + + //When hovering a node highlight the nodes + //between the root node and the hovered node. This + //is done by adding the 'in-path' CSS class to each node. + selectPathOnHover: true, + + //Allow tips + Tips: { + allow: true, + //add positioning offsets + offsetX: 20, + offsetY: 20, + //implement the onShow method to + //add content to the tooltip when a node + //is hovered + onShow: function(tip, node, isLeaf, domElement) { + tip.innerHTML = "
" + node.name + "
" + + "
" + this.makeHTMLFromData(node.data) + "
"; + }, + + //Aux method: Build the tooltip inner html by using the data property + makeHTMLFromData: function(data){ + var html = ''; + html += "playcount" + ': ' + data.$area + '
'; + if ("$color" in data) + html += "rank" + ': ' + data.$color + '
'; + if ("image" in data) + html += ""; + return html; + } + }, + //Implement this method for retrieving a requested //subtree that has as root a node with id = nodeId, //and level as depth. This method could also make a server-side @@ -28,127 +66,9 @@ function init(){ onComplete.onComplete(nodeId, subtree); }, - //Here we manually create the tooltip and add tooltip event - //handlers for each DOM node. - //This code might seem a little bit complicated because - //its made library agnostic (i.e with pure JS and not some JS lib). - //I encourage anyone that uses the treemap to also use - //some DOM manipulation framework that has tooltip and event support - //like JQuery with some tooltip plugin or MooTools. - //You'll see that by using some DOM manipulation library - //this code gets really simpler. - makeTip: function(elem, json){ - var title = json.name; - //create tooltip inner html - var html = this.makeHTMLFromData(json.data); - var tooltip = document.getElementById('tooltip'); - //Add mousemove event handlers. - elem.onmousemove = function(e){ - //get mouse position - var page = { - x: e.pageX || e.clientX + document.scrollLeft, - y: e.pageY || e.clientY + document.scrollTop - }; - tooltip.style.display = ''; - //get window dimensions - var win = { - 'height': document.body.clientHeight, - 'width': document.body.clientWidth - }; - //get tooltip dimensions - var obj = { - 'width': tooltip.offsetWidth, - 'height': tooltip.offsetHeight - }; - //set tooltip position - var style = tooltip.style; - style.top = ((page.y + 20 + obj.height > win.height)? - (page.y - obj.height - 20) : page.y + 20) + 'px'; - style.left = ((page.x + obj.width + 20 > win.width)? - (page.x - obj.width - 20) : page.x + 20) + 'px'; - }; - //show tooltip onmouseover - elem.onmouseover = function(e){ - tooltip.style.display = ''; - tooltip.innerHTML = '
' + title + '
'; - tooltip.innerHTML += '
' + html + '
'; - }; - //hide tooltip onmouseout - elem.onmouseout = function(e){ - tooltip.style.display = 'none'; - }; - }, - - //Build the tooltip inner html by taking each node data property - makeHTMLFromData: function(data){ - var html = ''; - html += "playcount" + ': ' + data.$area + '
'; - if ("$color" in data) - html += "rank" + ': ' + data.$color + '
'; - if ("image" in data) - html += ""; - return html; - }, - - //This method is invoked when a DOM element is created. - //Its useful to set all kind of DOM event handlers here. - //The code in this method could be a lot simpler if you - //used some event javascript framework like JQuery or MooTools, - //but unfortunately I have to make also these examples - //library agnostic. I'll probably post this example with - //JQuery and MooTools in my blog. - onCreateElement: function(content, tree, isLeaf, leaf){ - var that = tm; - //Add tip events - if (tree) - this.makeTip(leaf, tree); - //Change an element CSS class - //onmouseover - var prevmover = leaf.onmouseover; - leaf.onmouseover = function(e){ - if (isLeaf) { - leaf.className += ' over-leaf'; - } - else { - leaf.className += ' over-head'; - content.className += ' over-content'; - } - if (content.id) - that.resetPath(tree); - prevmover(); - }; - //Change an element CSS class - //onmouseout - var prevmovout = leaf.onmouseout; - leaf.onmouseout = function(e){ - leaf.className = leaf.className.split(" ")[0]; - content.className = content.className.split(" ")[0]; - that.resetPath(); - prevmovout(); - }; - //Add left and right click handlers - leaf.onmouseup = function(e){ - var rightClick = (e.which == 3 || e.button == 2); - if (rightClick) - tm.out(); - else - tm.enter(leaf); - - //Stop event propagation - if (e.stopPropagation) - e.stopPropagation(); - else - e.cancelBubble = true; - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - }; - }, //Remove all events for the element before destroying it. onDestroyElement: function(content, tree, isLeaf, leaf){ - leaf.onmouseout = leaf.onmousemove = leaf.onmouseover = null; + if(leaf.clearAttributes) leaf.clearAttributes(); } }); diff --git a/Tests/Treemap/test4.js b/Tests/Treemap/test4.js index 7d5c676..1e4074a 100644 --- a/Tests/Treemap/test4.js +++ b/Tests/Treemap/test4.js @@ -665,7 +665,17 @@ function init(){ var tm = new TM.Squarified({ //Where to inject the treemap. rootId: 'infovis', + + //Add click handlers for + //zooming the Treemap in and out + addLeftClickHandler: true, + addRightClickHandler: true, + //When hovering a node highlight the nodes + //between the root node and the hovered node. This + //is done by adding the 'in-path' CSS class to each node. + selectPathOnHover: true, + Color: { //Allow coloring allow: true, @@ -681,127 +691,35 @@ function init(){ maxColorValue: [255, 0, 50] }, - //Here we manually create the tooltip and add tooltip event - //handlers for each DOM node. - //This code might seem a little bit complicated because - //its made library agnostic (i.e with pure JS and not some JS lib). - //I encourage anyone that uses the treemap to also use - //some DOM manipulation framework that has tooltip and event support - //like JQuery with some tooltip plugin or MooTools. - //You'll see that by using some DOM manipulation library - //this code gets really simpler. - makeTip: function(elem, json){ - var title = json.name; - //create tooltip inner html - var html = this.makeHTMLFromData(json.data); - var tooltip = document.getElementById('tooltip'); - //Add mousemove event handlers. - elem.onmousemove = function(e){ - //get mouse position - var page = { - x: e.pageX || e.clientX + document.scrollLeft, - y: e.pageY || e.clientY + document.scrollTop - }; - tooltip.style.display = ''; - //get window dimensions - var win = { - 'height': document.body.clientHeight, - 'width': document.body.clientWidth - }; - //get tooltip dimensions - var obj = { - 'width': tooltip.offsetWidth, - 'height': tooltip.offsetHeight - }; - //set tooltip position - var style = tooltip.style; - style.top = ((page.y + 20 + obj.height > win.height)? - (page.y - obj.height - 20) : page.y + 20) + 'px'; - style.left = ((page.x + obj.width + 20 > win.width)? - (page.x - obj.width - 20) : page.x + 20) + 'px'; - }; - //show tooltip onmouseover - elem.onmouseover = function(e){ - tooltip.style.display = ''; - tooltip.innerHTML = '
' + title + '
'; - tooltip.innerHTML += '
' + html + '
'; - }; - //hide tooltip onmouseout - elem.onmouseout = function(e){ - tooltip.style.display = 'none'; - }; - }, + //Allow tips + Tips: { + allow: true, + //add positioning offsets + offsetX: 20, + offsetY: 20, + //implement the onShow method to + //add content to the tooltip when a node + //is hovered + onShow: function(tip, node, isLeaf, domElement) { + tip.innerHTML = "
" + node.name + "
" + + "
" + this.makeHTMLFromData(node.data) + "
"; + }, - //Build the tooltip inner html by taking each node data property - makeHTMLFromData: function(data){ - var html = ''; - html += "playcount" + ': ' + data.$area + '
'; - if ("$color" in data) - html += "rank" + ': ' + data.$color + '
'; - if ("image" in data) - html += ""; - return html; + //Build the tooltip inner html by taking each node data property + makeHTMLFromData: function(data){ + var html = ''; + html += "playcount" + ': ' + data.$area + '
'; + if ("$color" in data) + html += "rank" + ': ' + data.$color + '
'; + if ("image" in data) + html += ""; + return html; + } }, - //This method is invoked when a DOM element is created. - //Its useful to set all kind of DOM event handlers here. - //The code in this method could be a lot simpler if you - //used some event javascript framework like JQuery or MooTools, - //but unfortunately I have to make also these examples - //library agnostic. I'll probably post this example with - //JQuery and MooTools in my blog. - onCreateElement: function(content, tree, isLeaf, leaf){ - var that = tm; - //Add tip events - if (tree) - this.makeTip(leaf, tree); - //Change an element CSS class - //onmouseover - var prevmover = leaf.onmouseover; - leaf.onmouseover = function(e){ - if (isLeaf) { - leaf.className += ' over-leaf'; - } - else { - leaf.className += ' over-head'; - content.className += ' over-content'; - } - if (content.id) - that.resetPath(tree); - prevmover(); - }; - //Change an element CSS class - //onmouseout - var prevmovout = leaf.onmouseout; - leaf.onmouseout = function(e){ - leaf.className = leaf.className.split(" ")[0]; - content.className = content.className.split(" ")[0]; - that.resetPath(); - prevmovout(); - }; - //Add left and right click handlers - leaf.onmouseup = function(e){ - var rightClick = (e.which == 3 || e.button == 2); - if (rightClick) - tm.out(); - else - tm.enter(leaf); - - //Stop event propagation - if (e.stopPropagation) - e.stopPropagation(); - else - e.cancelBubble = true; - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - }; - }, - //Remove all events for the element before destroying it. + //Remove all element events before destroying it. onDestroyElement: function(content, tree, isLeaf, leaf){ - leaf.onmouseout = leaf.onmousemove = leaf.onmouseover = null; + if(leaf.clearAttributes) leaf.clearAttributes(); } }); diff --git a/Tests/Treemap/test5.js b/Tests/Treemap/test5.js index 87f15da..3641de3 100644 --- a/Tests/Treemap/test5.js +++ b/Tests/Treemap/test5.js @@ -671,6 +671,16 @@ function init(){ orientation: "h", offset: 0, + //Add click handlers for + //zooming the Treemap in and out + addLeftClickHandler: true, + addRightClickHandler: true, + + //When hovering a node highlight the nodes + //between the root node and the hovered node. This + //is done by adding the 'in-path' CSS class to each node. + selectPathOnHover: true, + Color: { //Allow coloring allow: true, @@ -686,114 +696,36 @@ function init(){ maxColorValue: [255, 0, 50] }, - //Here we manually create the tooltip and add tooltip event - //handlers for each DOM node. - //This code might seem a little bit complicated because - //its made library agnostic (i.e with pure JS and not some JS lib). - //I encourage anyone that uses the treemap to also use - //some DOM manipulation framework that has tooltip and event support - //like JQuery with some tooltip plugin or MooTools. - //You'll see that by using some DOM manipulation library - //this code gets really simpler. - makeTip: function(elem, json){ - var title = json.name; - //create tooltip inner html - var html = this.makeHTMLFromData(json.data); - var tooltip = document.getElementById('tooltip'); - //Add mousemove event handlers. - elem.onmousemove = function(e){ - //get mouse position - var page = { - x: e.pageX || e.clientX + document.scrollLeft, - y: e.pageY || e.clientY + document.scrollTop - }; - tooltip.style.display = ''; - //get window dimensions - var win = { - 'height': document.body.clientHeight, - 'width': document.body.clientWidth - }; - //get tooltip dimensions - var obj = { - 'width': tooltip.offsetWidth, - 'height': tooltip.offsetHeight - }; - //set tooltip position - var style = tooltip.style; - style.top = ((page.y + 20 + obj.height > win.height)? - (page.y - obj.height - 20) : page.y + 20) + 'px'; - style.left = ((page.x + obj.width + 20 > win.width)? - (page.x - obj.width - 20) : page.x + 20) + 'px'; - }; - //show tooltip onmouseover - elem.onmouseover = function(e){ - tooltip.style.display = ''; - tooltip.innerHTML = '
' + title + '
'; - tooltip.innerHTML += '
' + html + '
'; - }; - //hide tooltip onmouseout - elem.onmouseout = function(e){ - tooltip.style.display = 'none'; - }; - }, + //Allow tips + Tips: { + allow: true, + //add positioning offsets + offsetX: 20, + offsetY: 20, + //implement the onShow method to + //add content to the tooltip when a node + //is hovered + onShow: function(tip, node, isLeaf, domElement) { + tip.innerHTML = "
" + node.name + "
" + + "
" + this.makeHTMLFromData(node.data) + "
"; + }, - //Build the tooltip inner html by taking each node data property - makeHTMLFromData: function(data){ - var html = ''; - html += "playcount" + ': ' + data.$area + '
'; - if ("$color" in data) - html += "rank" + ': ' + data.$color + '
'; - if ("image" in data) - html += ""; - return html; + //Build the tooltip inner html by taking each node data property + makeHTMLFromData: function(data){ + var html = ''; + html += "playcount" + ': ' + data.$area + '
'; + if ("$color" in data) + html += "rank" + ': ' + data.$color + '
'; + if ("image" in data) + html += ""; + return html; + } }, //This method is invoked when a DOM element is created. - //Its useful to set all kind of DOM event handlers here. - //The code in this method could be a lot simpler if you - //used some event javascript framework like JQuery or MooTools, - //but unfortunately I have to make also these examples - //library agnostic. I'll probably post this example with - //JQuery and MooTools in my blog. + //Its useful to set DOM event handlers here or manipulate + //the DOM Treemap nodes. onCreateElement: function(content, tree, isLeaf, leaf){ - var that = tm; - //Add tip events - if (tree) - this.makeTip(leaf, tree); - //Change an element CSS class - //onmouseover - var prevmover = leaf.onmouseover; - leaf.onmouseover = function(e){ - if (isLeaf) leaf.className += ' over-leaf'; - prevmover(); - }; - //Change an element CSS class - //onmouseout - var prevmovout = leaf.onmouseout; - leaf.onmouseout = function(e){ - leaf.className = leaf.className.split(" ")[0]; - prevmovout(); - }; - //Add left and right click handlers - leaf.onmouseup = function(e){ - var rightClick = (e.which == 3 || e.button == 2); - if (rightClick) - tm.out(); - else - tm.enter(leaf); - - //Stop event propagation - if (e.stopPropagation) - e.stopPropagation(); - else - e.cancelBubble = true; - - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - }; - //Add background image if(isLeaf) { var style = leaf.style, @@ -809,9 +741,10 @@ function init(){ style.height = height + "px"; } }, + //Remove all events for the element before destroying it. onDestroyElement: function(content, tree, isLeaf, leaf){ - leaf.onmouseout = leaf.onmousemove = leaf.onmouseover = null; + if(leaf.clearAttributes) leaf.clearAttributes(); } }); diff --git a/Tests/css/Other.css b/Tests/css/Other.css new file mode 100644 index 0000000..ed6dacc --- /dev/null +++ b/Tests/css/Other.css @@ -0,0 +1,8 @@ +#right-container { + display:none; +} + +#infovis { + width:800px; + background-color:#1a1a1a; +} diff --git a/Tests/css/Treemap.css b/Tests/css/Treemap.css index 72a7bfe..44f480b 100644 --- a/Tests/css/Treemap.css +++ b/Tests/css/Treemap.css @@ -55,10 +55,9 @@ } /*TOOLTIPS*/ -.tool-tip { +.tip { color: #fff; width: 139px; - z-index: 13000; background-color: black; opacity:0.9; filter:alpha(opacity=90); @@ -67,22 +66,6 @@ padding:7px; } -.tip-title { - font-weight: bold; - font-size: 11px; - margin: 0; - color: #9FD4FF; - padding: 8px 8px 4px; - background-color: black; - -} - -.tip-text { - font-size: 11px; - padding: 4px 8px 8px; - background-color: black; -} - .album { width:100px; margin:3px; diff --git a/Tests/css/base.css b/Tests/css/base.css index cac0350..b21390e 100644 --- a/Tests/css/base.css +++ b/Tests/css/base.css @@ -23,6 +23,10 @@ h4 { color:#23A4FF; } +a { + color:#23A4FF; +} + #container { width: 1000px; height: 600px; @@ -98,5 +102,5 @@ h4 { width:600px; height:600px; margin:auto; - + overflow:hidden; } \ No newline at end of file diff --git a/Tests/js/common.js b/Tests/js/common.js new file mode 100644 index 0000000..4169664 --- /dev/null +++ b/Tests/js/common.js @@ -0,0 +1,14 @@ +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 addEvent(obj, type, fn) { + if (obj.addEventListener) obj.addEventListener(type, fn, false); + else obj.attachEvent('on' + type, fn); +}; diff --git a/make.py b/make.py index c2c189b..1a7ae31 100644 --- a/make.py +++ b/make.py @@ -1,10 +1,20 @@ from os import system, walk +from shutil import copy import sys +import re -PROJECT_ROOT = '/home/nicolas/workspace/jit/' +from tests import tests_model +from serve import render +from build import Build + +YC = 'yuicompressor-2.4.2.jar' def main(): if 'docs' in sys.argv: make_docs() + if 'examples' in sys.argv: make_examples() + if 'examples-fancy' in sys.argv: make_examples(fancy=True) + if 'build' in sys.argv: make_build() + if 'build-fancy' in sys.argv: make_build(fancy=True) def make_docs(): system("perl " @@ -13,5 +23,92 @@ def make_docs(): + PROJECT_ROOT + "Source/ -o HTML " + PROJECT_ROOT +"Docs/ -p " + PROJECT_ROOT + "NaturalDocs-1.4 -img NaturalDocs-1.4/img -s docstyle -r") + +def make_examples(fancy=False): +#clean examples folder + system("rm -rf Examples/*") +#create example folders + system('mkdir Examples/Hypertree Examples/RGraph Examples/Treemap Examples/Spacetree Examples/Other') +#copy css base files + system('cp -r Tests/css Examples/css') +#iterate over the examples + for viz, tests in tests_model.items(): + count = 1 + for i in range(len(tests)): + model = tests[i] + if 'Example' in model and model['Example']: + make_example(viz, model, i, count, fancy) + count += 1 +#copy some extra files + if fancy: + system('cp -r Extras/sh Examples/') + system('cp Extras/code.css Examples/css/code.css') + +def make_example(viz, ex, i, count, fancy): + name = viz + stri = str(i + 1) + model = ex + title = model['Title'] + extras = model['Extras'][:] + example = 'example' + str(count) + strdir = 'Examples/' + viz + '/' + +#insert the example js file + fcommon = open('Tests/js/common.js', 'r') + ftest = open('Tests/' + viz + '/test' + stri + '.js', 'r') + fout = open(strdir + example + '.js', 'w') + fout.write('\n\n'.join([fcommon.read(), ftest.read().replace('/Tests/css', '../css')])) + fcommon.close() + ftest.close() + fout.close() + +#render the html file + includes = { + 'left': getattr(render['TestCases'], viz + '/' + 'left')(model, viz, 1, 1), + 'right': getattr(render['TestCases'], viz + '/' + 'test' + stri)(model), + } + + fhtml = open(strdir + example + '.html', 'w') + html = render['TestCases'].baseexamples(name, title, extras, example, '', includes, fancy).__body__ + fhtml.write(html) + fhtml.close() + +#create syntax highlighted code page + if fancy: + begin, end, res = re.compile("[\s]*//init ([a-zA-Z0-9]+)[\s]*"), re.compile('[\s]*//end[\s]*'), [] + ftest = open('Tests/' + viz + '/test' + stri + '.js', 'r') + for l in ftest: + if begin.match(l): + name, lines = begin.match(l).group(1), [] + for blockline in ftest: + if end.match(blockline): break + lines.append(blockline) + + res.append({ + 'name': name, + 'code': ''.join(lines) + }) + + fcode = open(strdir + example + '.code.html', 'w') + html = render['TestCases'].basecode(name, title, res, example).__body__ + fcode.write(html) + fcode.close() + + +def make_build(fancy=False): + system('rm -rf Jit/*') + print "Building Examples..." + make_examples(fancy) + system('cp -r Examples/ Jit/') + print "Done. Building Extras..." + system('mkdir Jit/Extras && cp Extras/excanvas.js Jit/Extras/excanvas.js') + print "Done. Building Library..." + lib = Build().build() + f = open('Jit/jit.js', 'w') + f.write(lib) + f.close() + print "Done. Compressing Library..." + system('java -jar Extras/' + YC + ' Jit/jit.js > Jit/jit-yc.js') + print "Done, I guess." if __name__ == "__main__": main() diff --git a/serve.py b/serve.py index 8383150..542cae4 100644 --- a/serve.py +++ b/serve.py @@ -4,14 +4,13 @@ from build import Build urls = ( - '/testcase/(RGraph|Treemap|Hypertree|Spacetree)/([0-9]+)/', 'testcase', + '/testcase/(RGraph|Treemap|Hypertree|Spacetree|Other)/([0-9]+)/', 'testcase', ) app = web.application(urls, globals()) render = { - 'TestCases': template.render('Templates/Tests/'), - 'Examples': template.render('Templates/Examples/') + 'TestCases': template.render('Templates/'), } class testcase: @@ -28,8 +27,9 @@ def GET(self, type, number): title = model['Title'] extras = model['Extras'][:] - build_config = getattr(model, 'Build', [type]) - + if 'Build' in model: build_config = model['Build'] + else: build_config = [type] + build = Build().build(build_config) includes = { @@ -37,6 +37,6 @@ def GET(self, type, number): 'right': getattr(render['TestCases'], type + '/' + 'test' + number)(model), } - return render['TestCases'].base(name, title, extras, test, build, includes) + return render['TestCases'].basetests(name, title, extras, test, build, includes) if __name__ == "__main__": app.run() diff --git a/tests.py b/tests.py index f05961d..cb13921 100644 --- a/tests.py +++ b/tests.py @@ -290,6 +290,28 @@ """, 'Extras': ['excanvas.js'], 'Example': True + }, + { + 'Title': 'SpaceTree with on-demand nodes', + 'Description': + """ + This example shows how you can use the request controller method to create a SpaceTree with on demand nodes

+ The basic JSON Tree structure is cloned and appended on demand on each node to create an infinite large SpaceTree

+ You can select the tree orientation by changing the select box in the right column. + """, + 'Extras': ['excanvas.js'], + 'Example': True + }, + { + 'Title': 'Add/Remove Subtrees', + 'Description': + """ + This example shows how to add/remove subtrees with the SpaceTree.

+ Add a subtree by clicking on the Add button located in the right column.

+ Remove a subtree by clicking on a red colored node + """, + 'Extras': ['excanvas.js'], + 'Example': True } ], @@ -355,5 +377,50 @@ 'Extras': [], 'Example':True } + ], + + 'Other': [ + { + 'Title': 'Implementing Node Types', + 'Description': + """ + In this example some custom node types are created for rendering pie charts with the RGraph.

+ Multiple instances of the RGraph are created using these node types. (top)

+ The SpaceTree is loaded with some custom data that individually changes nodes dimensions, making a bar chart (bottom). + + """, + 'Extras': [], + 'Build': ['RGraph', 'Spacetree'], + 'Example': True + + }, + { + 'Title': 'Composing Visualizations', + 'Description': + """ + In this example a RGraph is composed with another RGraph (for node rendering).

+ The RGraph used for node rendering implements a custom node type defined in the "Implementing Node Types" example.

+ This example shows that many visualizations can be composed to create new visualizations. + + """, + 'Extras': [], + 'Build': ['RGraph'], + 'Example': True + + }, + { + 'Title': 'Composing Visualizations 2', + 'Description': + """ + In this example a SpaceTree is composed with a RGraph (for node rendering).

+ The RGraph used for node rendering implements a custom node type defined in the "Implementing Node Types" example.

+ This example shows that many visualizations can be composed to create new visualizations. + + """, + 'Extras': [], + 'Build': ['RGraph', 'Spacetree'], + 'Example': True + + } ] }