From: Maxious Date: Sat, 11 Aug 2012 11:05:42 +0000 Subject: Merge branch 'master' of /git/disclosr X-Git-Url: https://maxious.lambdacomplex.org/git/?p=disclosr.git&a=commitdiff&h=8f60a3b07648dca91dbc1e25d6a80b56c711c768 --- Merge branch 'master' of /git/disclosr Former-commit-id: 9fbbad67fbd89b844e133a0d8f8e7dc4c529d0f7 --- --- a/about.php +++ b/about.php @@ -7,10 +7,9 @@

Lorem ipsum.

What is this?

-Disclosr is a project to monitor Australian Federal Government agencies +Disclo.gs is a project to monitor Australian Federal Government agencies compliance with their "proactive disclosure requirements". -OGRE (Open Government Realization Evaluation) is a ranking of compliance with these requirements. -Prometheus is the agent which polls agency websites to assess compliance. +

Open everything

All documents released CC-BY 3 AU --- a/admin/exportEmployees.csv.php +++ b/admin/exportEmployees.csv.php @@ -5,6 +5,7 @@ $format = "csv"; //$format = "json"; if (isset($_REQUEST['format'])) $format = $_REQUEST['format']; + setlocale(LC_CTYPE, 'C'); if ($format == "csv") { $headers = Array("name"); --- a/getAgency.php +++ b/getAgency.php @@ -137,7 +137,7 @@ } } - $mode = "edit"; + $mode = "view"; $rowArray = object_to_array($obj); ksort($rowArray); if ($mode == "edit") { --- /dev/null +++ b/index.php @@ -1,1 +1,9 @@ + --- a/javascripts/bubbletree +++ b/javascripts/bubbletree --- a/javascripts/flotr2 +++ b/javascripts/flotr2 --- a/javascripts/sigma +++ b/javascripts/sigma --- a/javascripts/sigma.min.js +++ b/javascripts/sigma.min.js @@ -1,3552 +1,63 @@ -// Define packages: -var sigma = {}; -sigma.tools = {}; -sigma.classes = {}; -sigma.instances = {}; +/* sigmajs.org - an open-source light-weight JavaScript graph drawing library - Version: 0.1 - Author: Alexis Jacomy - License: MIT */ +var sigma={tools:{},classes:{},instances:{}}; +(function(){if(!Array.prototype.some)Array.prototype.some=function(i,n){var g=this.length;if("function"!=typeof i)throw new TypeError;for(var j=0;j";a+="

LOCAL :

";for(b in d.p.localProbes)a+="

"+b+" : "+d.p.localProbes[b]()+"

";d.p.dom.innerHTML= +a;return d}sigma.classes.Cascade.call(this);var d=this;this.instance=b;this.monitoring=!1;this.p={fps:40,dom:h,globalProbes:{"Time (ms)":sigma.chronos.getExecutionTime,Queue:sigma.chronos.getQueuedTasksCount,Tasks:sigma.chronos.getTasksCount,FPS:sigma.chronos.getFPS},localProbes:{"Nodes count":function(){return d.instance.graph.nodes.length},"Edges count":function(){return d.instance.graph.edges.length}}};this.activate=function(){if(!d.monitoring)d.monitoring=window.setInterval(e,1E3/d.p.fps);return d}; +this.desactivate=function(){if(d.monitoring)window.clearInterval(d.monitoring),d.monitoring=null,d.p.dom.innerHTML="";return d}}function j(b){function h(b){if(a.p.mouseEnabled&&(e(a.mouseX,a.mouseY,a.ratio*(0<(void 0!=b.wheelDelta&&b.wheelDelta||void 0!=b.detail&&-b.detail)?a.p.zoomMultiply:1/a.p.zoomMultiply)),a.p.blockScroll))b.preventDefault?b.preventDefault():b.returnValue=!1}function e(b,c,e){if(!a.isMouseDown&&(window.clearInterval(a.interpolationID),n=void 0!=e,i=a.stageX,j=b,k=a.stageY,l= +c,f=e||a.ratio,f=Math.min(Math.max(f,a.p.minRatio),a.p.maxRatio),u=a.p.directZooming?1-(n?a.p.zoomDelta:a.p.dragDelta):0,a.ratio!=f||a.stageX!=j||a.stageY!=l))d(),a.interpolationID=window.setInterval(d,50),a.dispatch("startinterpolate")}function d(){u+=n?a.p.zoomDelta:a.p.dragDelta;u=Math.min(u,1);var b=sigma.easing.quadratic.easeout(u),c=a.ratio;a.ratio=c*(1-b)+f*b;n?(a.stageX=j+(a.stageX-j)*a.ratio/c,a.stageY=l+(a.stageY-l)*a.ratio/c):(a.stageX=i*(1-b)+j*b,a.stageY=k*(1-b)+l*b);a.dispatch("interpolate"); +if(1<=u)window.clearInterval(a.interpolationID),b=a.ratio,n?(a.ratio=f,a.stageX=j+(a.stageX-j)*a.ratio/b,a.stageY=l+(a.stageY-l)*a.ratio/b):(a.stageX=j,a.stageY=l),a.dispatch("stopinterpolate")}sigma.classes.Cascade.call(this);sigma.classes.EventDispatcher.call(this);var a=this;this.p={minRatio:1,maxRatio:32,marginRatio:1,zoomDelta:0.1,dragDelta:0.3,zoomMultiply:2,directZooming:!1,blockScroll:!0,inertia:1.1,mouseEnabled:!0};var g=0,c=0,i=0,k=0,f=1,j=0,l=0,s=0,q=0,z=0,m=0,u=0,n=!1;this.stageY=this.stageX= +0;this.ratio=1;this.mouseY=this.mouseX=0;this.isMouseDown=!1;b.addEventListener("DOMMouseScroll",h,!0);b.addEventListener("mousewheel",h,!0);b.addEventListener("mousemove",function(b){a.mouseX=void 0!=b.offsetX&&b.offsetX||void 0!=b.layerX&&b.layerX||void 0!=b.clientX&&b.clientX;a.mouseY=void 0!=b.offsetY&&b.offsetY||void 0!=b.layerY&&b.layerY||void 0!=b.clientY&&b.clientY;if(a.isMouseDown){var d=a.mouseX-g+i,f=a.mouseY-c+k;if(d!=a.stageX||f!=a.stageY)q=s,m=z,s=d,z=f,a.stageX=d,a.stageY=f,a.dispatch("drag")}a.dispatch("move"); +b.preventDefault?b.preventDefault():b.returnValue=!1},!0);b.addEventListener("mousedown",function(b){if(a.p.mouseEnabled)a.isMouseDown=!0,a.dispatch("mousedown"),i=a.stageX,k=a.stageY,g=a.mouseX,c=a.mouseY,q=s=a.stageX,m=z=a.stageY,a.dispatch("startdrag"),b.preventDefault?b.preventDefault():b.returnValue=!1},!0);document.addEventListener("mouseup",function(b){if(a.p.mouseEnabled&&a.isMouseDown)a.isMouseDown=!1,a.dispatch("mouseup"),(i!=a.stageX||k!=a.stageY)&&e(a.stageX+a.p.inertia*(a.stageX-q),a.stageY+ +a.p.inertia*(a.stageY-m)),b.preventDefault?b.preventDefault():b.returnValue=!1},!0);this.checkBorders=function(){return a};this.interpolate=e}function m(b,h,e,d,a,g,c){function i(a){var b=d,c="fixed"==f.p.labelSize?f.p.defaultLabelSize:f.p.labelSizeRatio*a.displaySize;b.font=(f.p.hoverFontStyle||f.p.fontStyle||"")+" "+c+"px "+(f.p.hoverFont||f.p.font||"");b.fillStyle="node"==f.p.labelHoverBGColor?a.color||f.p.defaultNodeColor:f.p.defaultHoverLabelBGColor;b.beginPath();if(f.p.labelHoverShadow)b.shadowOffsetX= +0,b.shadowOffsetY=0,b.shadowBlur=4,b.shadowColor=f.p.labelHoverShadowColor;sigma.tools.drawRoundRect(b,Math.round(a.displayX-c/2-2),Math.round(a.displayY-c/2-2),Math.round(b.measureText(a.label).width+1.5*a.displaySize+c/2+4),Math.round(c+4),Math.round(c/2+2),"left");b.closePath();b.fill();b.shadowOffsetX=0;b.shadowOffsetY=0;b.shadowBlur=0;b.beginPath();b.fillStyle="node"==f.p.nodeBorderColor?a.color||f.p.defaultNodeColor:f.p.defaultNodeBorderColor;b.arc(Math.round(a.displayX),Math.round(a.displayY), +a.displaySize+f.p.borderSize,0,2*Math.PI,!0);b.closePath();b.fill();b.beginPath();b.fillStyle="node"==f.p.nodeHoverColor?a.color||f.p.defaultNodeColor:f.p.defaultNodeHoverColor;b.arc(Math.round(a.displayX),Math.round(a.displayY),a.displaySize,0,2*Math.PI,!0);b.closePath();b.fill();b.fillStyle="node"==f.p.labelHoverColor?a.color||f.p.defaultNodeColor:f.p.defaultLabelHoverColor;b.fillText(a.label,Math.round(a.displayX+1.5*a.displaySize),Math.round(a.displayY+c/2-3));return f}function k(a){if(isNaN(a.x)|| +isNaN(a.y))throw Error("A node's coordinate is not a number (id: "+a.id+")");return!a.hidden&&a.displayX+a.displaySize>-j/3&&a.displayX-a.displaySize<4*j/3&&a.displayY+a.displaySize>-l/3&&a.displayY-a.displaySize<4*l/3}sigma.classes.Cascade.call(this);var f=this;this.p={labelColor:"default",defaultLabelColor:"#000",labelHoverBGColor:"default",defaultHoverLabelBGColor:"#fff",labelHoverShadow:!0,labelHoverShadowColor:"#000",labelHoverColor:"default",defaultLabelHoverColor:"#000",labelActiveBGColor:"default", +defaultActiveLabelBGColor:"#fff",labelActiveShadow:!0,labelActiveShadowColor:"#000",labelActiveColor:"default",defaultLabelActiveColor:"#000",labelSize:"fixed",defaultLabelSize:12,labelSizeRatio:2,labelThreshold:6,font:"Arial",hoverFont:"",activeFont:"",fontStyle:"",hoverFontStyle:"",activeFontStyle:"",edgeColor:"source",defaultEdgeColor:"#aaa",defaultEdgeType:"line",defaultNodeColor:"#aaa",nodeHoverColor:"node",defaultNodeHoverColor:"#fff",nodeActiveColor:"node",defaultNodeActiveColor:"#fff",borderSize:0, +nodeBorderColor:"node",defaultNodeBorderColor:"#fff",edgesSpeed:200,nodesSpeed:200,labelsSpeed:200};var j=g,l=c;this.currentLabelIndex=this.currentNodeIndex=this.currentEdgeIndex=0;this.task_drawLabel=function(){for(var b=a.nodes.length,c=0;c++=f.p.labelThreshold){var k="fixed"==f.p.labelSize?f.p.defaultLabelSize:f.p.labelSizeRatio*d.displaySize;h.font= +f.p.fontStyle+k+"px "+f.p.font;h.fillStyle="node"==f.p.labelColor?d.color||f.p.defaultNodeColor:f.p.defaultLabelColor;h.fillText(d.label,Math.round(d.displayX+1.5*d.displaySize),Math.round(d.displayY+k/2-3))}}else f.currentLabelIndex++;return f.currentLabelIndex(b*=2)?0.5*b*b:-0.5*(--b*(b-2)-1)};sigma.tools.drawRoundRect=function(b,h,e,d,a,g,c){var g=g?g:0,i=c?c:[],i="string"==typeof i?i.split(" "):i,c=g&&(0<=i.indexOf("topleft")||0<=i.indexOf("top")||0<=i.indexOf("left")),j=g&&(0<=i.indexOf("topright")||0<=i.indexOf("top")||0<=i.indexOf("right")),f=g&&(0<=i.indexOf("bottomleft")||0<=i.indexOf("bottom")||0<=i.indexOf("left")),i=g&&(0<=i.indexOf("bottomright")|| +0<=i.indexOf("bottom")||0<=i.indexOf("right"));b.moveTo(h,e+g);c?b.arcTo(h,e,h+g,e,g):b.lineTo(h,e);j?(b.lineTo(h+d-g,e),b.arcTo(h+d,e,h+d,e+g,g)):b.lineTo(h+d,e);i?(b.lineTo(h+d,e+a-g),b.arcTo(h+d,e+a,h+d-g,e+a,g)):b.lineTo(h+d,e+a);f?(b.lineTo(h+g,e+a),b.arcTo(h,e+a,h,e+a-g,g)):b.lineTo(h,e+a);b.lineTo(h,e+g)};sigma.tools.getRGB=function(b,g){var b=b.toString(),e={r:0,g:0,b:0};if(3<=b.length&&"#"==b.charAt(0)){var d=b.length-1;6==d?e={r:parseInt(b.charAt(1)+b.charAt(2),16),g:parseInt(b.charAt(3)+ +b.charAt(4),16),b:parseInt(b.charAt(5)+b.charAt(5),16)}:3==d&&(e={r:parseInt(b.charAt(1)+b.charAt(1),16),g:parseInt(b.charAt(2)+b.charAt(2),16),b:parseInt(b.charAt(3)+b.charAt(3),16)})}g&&(e=[e.r,e.g,e.b]);return e};sigma.tools.rgbToHex=function(b,g,e){return sigma.tools.toHex(b)+sigma.tools.toHex(g)+sigma.tools.toHex(e)};sigma.tools.toHex=function(b){b=parseInt(b,10);if(isNaN(b))return"00";b=Math.max(0,Math.min(b,255));return"0123456789ABCDEF".charAt((b-b%16)/16)+"0123456789ABCDEF".charAt(b%16)}; +sigma.publicPrototype=p.prototype})(); -// Adding Array helpers, if not present yet: -(function() { - if (!Array.prototype.some) { - Array.prototype.some = function(fun /*, thisp*/) { - var len = this.length; - if (typeof fun != 'function') { - throw new TypeError(); - } - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in this && - fun.call(thisp, this[i], i, this)) { - return true; - } - } - - return false; - }; - } - - if (!Array.prototype.forEach) { - Array.prototype.forEach = function(fun /*, thisp*/) { - var len = this.length; - if (typeof fun != 'function') { - throw new TypeError(); - } - - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in this) { - fun.call(thisp, this[i], i, this); - } - } - }; - } - - if (!Array.prototype.map) { - Array.prototype.map = function(fun /*, thisp*/) { - var len = this.length; - if (typeof fun != 'function') { - throw new TypeError(); - } - - var res = new Array(len); - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in this) { - res[i] = fun.call(thisp, this[i], i, this); - } - } - - return res; - }; - } - - if (!Array.prototype.filter) { - Array.prototype.filter = function(fun /*, thisp*/) { - var len = this.length; - if (typeof fun != 'function') - throw new TypeError(); - - var res = new Array(); - var thisp = arguments[1]; - for (var i = 0; i < len; i++) { - if (i in this) { - var val = this[i]; // in case fun mutates this - if (fun.call(thisp, val, i, this)) { - res.push(val); - } - } - } - - return res; - }; - } - - if (!Object.keys) { - Object.keys = (function() { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; - - return function(obj) { - if (typeof obj !== 'object' && - typeof obj !== 'function' || - obj === null - ) { - throw new TypeError('Object.keys called on non-object'); - } - - var result = []; - - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) result.push(prop); - } - - if (hasDontEnumBug) { - for (var i = 0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) { - result.push(dontEnums[i]); - } - } - } - return result; - } - })(); - } -})(); - -/** - * A jQuery like properties management class. It works like jQuery .css() - * method: You can call it with juste one string to get the corresponding - * property, with a string and anything else to set the corresponding property, - * or directly with an object, and then each pair string / object (or any type) - * will be set in the properties. - * @constructor - * @this {sigma.classes.Cascade} - */ -sigma.classes.Cascade = function() { - /** - * This instance properties. - * @protected - * @type {Object} - */ - this.p = {}; - - /** - * The method to use to set/get any property of this instance. - * @param {(string|Object)} a1 If it is a string and if a2 is undefined, - * then it will return the corresponding - * property. - * If it is a string and if a2 is set, then it - * will set a2 as the property corresponding to - * a1, and return this. - * If it is an object, then each pair string / - * object (or any other type) will be set as a - * property. - * @param {*?} a2 The new property corresponding to a1 if a1 is - * a string. - * @return {(*|sigma.classes.Cascade)} Returns itself or the corresponding - * property. - */ - this.config = function(a1, a2) { - if (typeof a1 == 'string' && a2 == undefined) { - return this.p[a1]; - } else { - var o = (typeof a1 == 'object' && a2 == undefined) ? a1 : {}; - if (typeof a1 == 'string') { - o[a1] = a2; - } - - for (var k in o) { - if (this.p[k] != undefined) { - this.p[k] = o[k]; - } - } - return this; - } - }; -}; - -/** - * sigma.js custom event dispatcher class. - * @constructor - * @this {sigma.classes.EventDispatcher} - */ -sigma.classes.EventDispatcher = function() { - /** - * An object containing all the different handlers bound to one or many - * events, indexed by these events. - * @private - * @type {Object.} - */ - var _h = {}; - - /** - * Represents "this", without the well-known scope issue. - * @private - * @type {sigma.classes.EventDispatcher} - */ - var _self = this; - - /** - * Will execute the handler the next (and only the next) time that the - * indicated event (or the indicated events) will be triggered. - * @param {string} events The name of the event (or the events - * separated by spaces). - * @param {function(Object)} handler The handler to bind. - * @return {sigma.classes.EventDispatcher} Returns itself. - */ - function one(events, handler) { - if (!handler || !events) { - return _self; - } - - var eArray = ((typeof events) == 'string') ? events.split(' ') : events; - - eArray.forEach(function(event) { - if (!_h[event]) { - _h[event] = []; - } - - _h[event].push({ - 'h': handler, - 'one': true - }); - }); - - return _self; - } - - /** - * Will execute the handler everytime that the indicated event (or the - * indicated events) will be triggered. - * @param {string} events The name of the event (or the events - * separated by spaces). - * @param {function(Object)} handler The handler to bind. - * @return {sigma.classes.EventDispatcher} Returns itself. - */ - function bind(events, handler) { - if (!handler || !events) { - return _self; - } - - var eArray = ((typeof events) == 'string') ? events.split(' ') : events; - - eArray.forEach(function(event) { - if (!_h[event]) { - _h[event] = []; - } - - _h[event].push({ - 'h': handler, - 'one': false - }); - }); - - return _self; - } - - /** - * Unbinds the handler from a specified event (or specified events). - * @param {?string} events The name of the event (or the events - * separated by spaces). If undefined, - * then all handlers are unbound. - * @param {?function(Object)} handler The handler to unbind. If undefined, - * each handler bound to the event or the - * events will be unbound. - * @return {sigma.classes.EventDispatcher} Returns itself. - */ - function unbind(events, handler) { - if (!events) { - _h = {}; - } - - var eArray = typeof events == 'string' ? events.split(' ') : events; - - if (handler) { - eArray.forEach(function(event) { - if (_h[event]) { - _h[event] = _h[event].filter(function(e) { - return e['h'] != handler; - }); - } - - if (_h[event] && _h[event].length == 0) { - delete _h[event]; - } - }); - }else { - eArray.forEach(function(event) { - delete _h[event]; - }); - } - - return _self; - } - - /** - * Executes each handler bound to the event - * @param {string} type The type of the event. - * @param {?Object} content The content of the event (optional). - * @return {sigma.classes.EventDispatcher} Returns itself. - */ - function dispatch(type, content) { - if (_h[type]) { - _h[type].forEach(function(e) { - e['h']({ - 'type': type, - 'content': content, - 'target': _self - }); - }); - - _h[type] = _h[type].filter(function(e) { - return !e['one']; - }); - } - - return _self; - } - - /* PUBLIC INTERFACE: */ - this.one = one; - this.bind = bind; - this.unbind = unbind; - this.dispatch = dispatch; -}; - -(function() { -// Define local shortcut: -var id = 0; - -// Define local package: -var local = {}; -local.plugins = []; - -sigma.init = function(dom) { - var inst = new Sigma(dom, (++id).toString()); - sigma.instances[id] = new SigmaPublic(inst); - return sigma.instances[id]; -}; - -/** - * This class listen to all the different mouse events, to normalize them and - * dispatch action events instead (from "startinterpolate" to "isdragging", - * etc). - * @constructor - * @extends sigma.classes.Cascade - * @extends sigma.classes.EventDispatcher - * @param {element} dom The DOM element to bind the handlers on. - * @this {MouseCaptor} - */ -function MouseCaptor(dom) { - sigma.classes.Cascade.call(this); - sigma.classes.EventDispatcher.call(this); - - /** - * Represents "this", without the well-known scope issue. - * @private - * @type {MouseCaptor} - */ - var self = this; - - /** - * The DOM element to bind the handlers on. - * @type {element} - */ - var dom = dom; - - /** - * The different parameters that define how this instance should work. - * @see sigma.classes.Cascade - * @type {Object} - */ - this.p = { - minRatio: 1, - maxRatio: 32, - marginRatio: 1, - zoomDelta: 0.1, - dragDelta: 0.3, - zoomMultiply: 2, - directZooming: false, - blockScroll: true, - inertia: 1.1, - mouseEnabled: true - }; - - var oldMouseX = 0; - var oldMouseY = 0; - var startX = 0; - var startY = 0; - - var oldStageX = 0; - var oldStageY = 0; - var oldRatio = 1; - - var targetRatio = 1; - var targetStageX = 0; - var targetStageY = 0; - - var lastStageX = 0; - var lastStageX2 = 0; - var lastStageY = 0; - var lastStageY2 = 0; - - var progress = 0; - var isZooming = false; - - this.stageX = 0; - this.stageY = 0; - this.ratio = 1; - - this.mouseX = 0; - this.mouseY = 0; - - this.isMouseDown = false; - - /** - * Extract the local X position from a mouse event. - * @private - * @param {event} e A mouse event. - * @return {number} The local X value of the mouse. - */ - function getX(e) { - return e.offsetX != undefined && e.offsetX || - e.layerX != undefined && e.layerX || - e.clientX != undefined && e.clientX; - }; - - /** - * Extract the local Y position from a mouse event. - * @private - * @param {event} e A mouse event. - * @return {number} The local Y value of the mouse. - */ - function getY(e) { - return e.offsetY != undefined && e.offsetY || - e.layerY != undefined && e.layerY || - e.clientY != undefined && e.clientY; - }; - - /** - * Extract the wheel delta from a mouse event. - * @private - * @param {event} e A mouse event. - * @return {number} The wheel delta of the mouse. - */ - function getDelta(e) { - return e.wheelDelta != undefined && e.wheelDelta || - e.detail != undefined && -e.detail; - }; - - /** - * The handler listening to the 'move' mouse event. It will set the mouseX - * and mouseY values as the mouse position values, prevent the default event, - * and dispatch a 'move' event. - * @private - * @param {event} event A 'move' mouse event. - */ - function moveHandler(event) { - oldMouseX = self.mouseX; - oldMouseY = self.mouseY; - - self.mouseX = getX(event); - self.mouseY = getY(event); - - self.isMouseDown && drag(event); - self.dispatch('move'); - - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - }; - - /** - * The handler listening to the 'up' mouse event. It will set the isMouseDown - * value as false, dispatch a 'mouseup' event, and trigger stopDrag(). - * @private - * @param {event} event A 'up' mouse event. - */ - function upHandler(event) { - if (self.p.mouseEnabled && self.isMouseDown) { - self.isMouseDown = false; - self.dispatch('mouseup'); - stopDrag(); - - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - } - }; - - /** - * The handler listening to the 'down' mouse event. It will set the - * isMouseDown value as true, dispatch a 'mousedown' event, and trigger - * startDrag(). - * @private - * @param {event} event A 'down' mouse event. - */ - function downHandler(event) { - if (self.p.mouseEnabled) { - self.isMouseDown = true; - oldMouseX = self.mouseX; - oldMouseY = self.mouseY; - - self.dispatch('mousedown'); - - startDrag(); - - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - } - }; - - /** - * The handler listening to the 'wheel' mouse event. It will trigger - * {@link startInterpolate} with the event delta as parameter. - * @private - * @param {event} event A 'wheel' mouse event. - */ - function wheelHandler(event) { - if (self.p.mouseEnabled) { - startInterpolate( - self.mouseX, - self.mouseY, - self.ratio * (getDelta(event) > 0 ? - self.p.zoomMultiply : - 1 / self.p.zoomMultiply) - ); - - if (self.p['blockScroll']) { - if (event.preventDefault) { - event.preventDefault(); - } else { - event.returnValue = false; - } - } - } - }; - - /** - * Will start computing the scene X and Y, until {@link stopDrag} is - * triggered. - */ - function startDrag() { - oldStageX = self.stageX; - oldStageY = self.stageY; - startX = self.mouseX; - startY = self.mouseY; - - lastStageX = self.stageX; - lastStageX2 = self.stageX; - lastStageY = self.stageY; - lastStageY2 = self.stageY; - - self.dispatch('startdrag'); - }; - - /** - * Stops computing the scene position. - */ - function stopDrag() { - if (oldStageX != self.stageX || oldStageY != self.stageY) { - startInterpolate( - self.stageX + self.p.inertia * (self.stageX - lastStageX2), - self.stageY + self.p.inertia * (self.stageY - lastStageY2) - ); - } - }; - - /** - * Computes the position of the scene, relatively to the mouse position, and - * dispatches a "drag" event. - */ - function drag() { - var newStageX = self.mouseX - startX + oldStageX; - var newStageY = self.mouseY - startY + oldStageY; - - if (newStageX != self.stageX || newStageY != self.stageY) { - lastStageX2 = lastStageX; - lastStageY2 = lastStageY; - - lastStageX = newStageX; - lastStageY = newStageY; - - self.stageX = newStageX; - self.stageY = newStageY; - self.dispatch('drag'); - } - }; - - /** - * Will start computing the scene zoom ratio, until {@link stopInterpolate} is - * triggered. - * @param {number} x The new stage X. - * @param {number} y The new stage Y. - * @param {number} ratio The new zoom ratio. - */ - function startInterpolate(x, y, ratio) { - if (self.isMouseDown) { - return; - } - - window.clearInterval(self.interpolationID); - isZooming = ratio != undefined; - - oldStageX = self.stageX; - targetStageX = x; - - oldStageY = self.stageY; - targetStageY = y; - - oldRatio = self.ratio; - targetRatio = ratio || self.ratio; - targetRatio = Math.min( - Math.max(targetRatio, self.p.minRatio), - self.p.maxRatio - ); - - progress = - self.p.directZooming ? - 1 - (isZooming ? self.p.zoomDelta : self.p.dragDelta) : - 0; - - if ( - self.ratio != targetRatio || - self.stageX != targetStageX || - self.stageY != targetStageY - ) { - interpolate(); - self.interpolationID = window.setInterval(interpolate, 50); - self.dispatch('startinterpolate'); - } - }; - - /** - * Stops the move interpolation. - */ - function stopInterpolate() { - var oldRatio = self.ratio; - - if (isZooming) { - self.ratio = targetRatio; - self.stageX = targetStageX + - (self.stageX - targetStageX) * - self.ratio / - oldRatio; - self.stageY = targetStageY + - (self.stageY - targetStageY) * - self.ratio / - oldRatio; - }else { - self.stageX = targetStageX; - self.stageY = targetStageY; - } - - self.dispatch('stopinterpolate'); - }; - - /** - * Computes the interpolate ratio and the position of the scene, relatively - * to the last mouse event delta received, and dispatches a "interpolate" - * event. - */ - function interpolate() { - progress += (isZooming ? self.p.zoomDelta : self.p.dragDelta); - progress = Math.min(progress, 1); - - var k = sigma.easing.quadratic.easeout(progress); - var oldRatio = self.ratio; - - self.ratio = oldRatio * (1 - k) + targetRatio * k; - - if (isZooming) { - self.stageX = targetStageX + - (self.stageX - targetStageX) * - self.ratio / - oldRatio; - - self.stageY = targetStageY + - (self.stageY - targetStageY) * - self.ratio / - oldRatio; - } else { - self.stageX = oldStageX * (1 - k) + targetStageX * k; - self.stageY = oldStageY * (1 - k) + targetStageY * k; - } - - self.dispatch('interpolate'); - if (progress >= 1) { - window.clearInterval(self.interpolationID); - stopInterpolate(); - } - }; - - /** - * Checks that there is always a part of the graph that is displayed, to - * avoid the user to drag the graph out of the stage. - * @param {Object} b An object containing the borders of the graph. - * @param {number} width The width of the stage. - * @param {number} height The height of the stage. - * @return {MouseCaptor} Returns itself. - */ - function checkBorders(b, width, height) { - // TODO : Find the good formula - /*if (!isNaN(b.minX) && !isNaN(b.maxX)) { - self.stageX = Math.min( - self.stageX = Math.max( - self.stageX, - (b.minX - width) * self.ratio + - self.p.marginRatio*(b.maxX - b.minX) - ), - (b.maxX - width) * self.ratio + - width - - self.p.marginRatio*(b.maxX - b.minX) - ); - } - - if (!isNaN(b.minY) && !isNaN(b.maxY)) { - self.stageY = Math.min( - self.stageY = Math.max( - self.stageY, - (b.minY - height) * self.ratio + - self.p.marginRatio*(b.maxY - b.minY) - ), - (b.maxY - height) * self.ratio + - height - - self.p.marginRatio*(b.maxY - b.minY) - ); - }*/ - - return self; - }; - - // ADD CALLBACKS - dom.addEventListener('DOMMouseScroll', wheelHandler, true); - dom.addEventListener('mousewheel', wheelHandler, true); - dom.addEventListener('mousemove', moveHandler, true); - dom.addEventListener('mousedown', downHandler, true); - document.addEventListener('mouseup', upHandler, true); - - this.checkBorders = checkBorders; - this.interpolate = startInterpolate; -} - -/** - * A class to monitor some local / global probes directly on an instance, - * inside a div DOM element. - * It executes different methods (called "probes") regularly, and displays - * the results on the element. - * @constructor - * @extends sigma.classes.Cascade - * @param {Sigma} instance The instance to monitor. - * @param {element} dom The div DOM element to draw write on. - * @this {Monitor} - */ -function Monitor(instance, dom) { - sigma.classes.Cascade.call(this); - - /** - * Represents "this", without the well-known scope issue. - * @private - * @type {Monitor} - */ - var self = this; - - /** - * {@link Sigma} instance owning this Monitor instance. - * @type {Sigma} - */ - this.instance = instance; - - /** - * Determines if the monitoring is activated or not. - * @type {Boolean} - */ - this.monitoring = false; - - /** - * The different parameters that define how this instance should work. It - * also contains the different probes. - * @see sigma.classes.Cascade - * @type {Object} - */ - this.p = { - fps: 40, - dom: dom, - globalProbes: { - 'Time (ms)': sigma.chronos.getExecutionTime, - 'Queue': sigma.chronos.getQueuedTasksCount, - 'Tasks': sigma.chronos.getTasksCount, - 'FPS': sigma.chronos.getFPS - }, - localProbes: { - 'Nodes count': function() { return self.instance.graph.nodes.length; }, - 'Edges count': function() { return self.instance.graph.edges.length; } - } - }; - - /** - * Activates the monitoring: Some texts describing some values about sigma.js - * or the owning {@link Sigma} instance will appear over the graph, but - * beneath the mouse sensible DOM element. - * @return {Monitor} Returns itself. - */ - function activate() { - if (!self.monitoring) { - self.monitoring = window.setInterval(routine, 1000 / self.p.fps); - } - - return self; - } - - /** - * Desactivates the monitoring: Will disappear, and stop computing the - * different probes. - * @return {Monitor} Returns itself. - */ - function desactivate() { - if (self.monitoring) { - window.clearInterval(self.monitoring); - self.monitoring = null; - - self.p.dom.innerHTML = ''; - } - - return self; - } - - /** - * The private method dedicated to compute the different values to observe. - * @private - * @return {Monitor} Returns itself. - */ - function routine() { - var s = ''; - - s += '

GLOBAL :

'; - for (var k in self.p.globalProbes) { - s += '

' + k + ' : ' + self.p.globalProbes[k]() + '

'; - } - - s += '

LOCAL :

'; - for (var k in self.p.localProbes) { - s += '

' + k + ' : ' + self.p.localProbes[k]() + '

'; - } - - self.p.dom.innerHTML = s; - - return self; - } - - this.activate = activate; - this.desactivate = desactivate; -} - -/** - * Sigma is the main class. It represents the core of any instance id sigma.js. - * It is private and can be initialized only from inside sigma.js. To see its - * public interface, see {@link SigmaPublic}. - * It owns its own {@link Graph}, {@link MouseCaptor}, {@link Plotter} - * and {@link Monitor}. - * @constructor - * @extends sigma.classes.Cascade - * @extends sigma.classes.EventDispatcher - * @param {element} root The DOM root of this instance (a div, for example). - * @param {string} id The ID of this instance. - * @this {Sigma} - */ -function Sigma(root, id) { - sigma.classes.Cascade.call(this); - sigma.classes.EventDispatcher.call(this); - - /** - * Represents "this", without the well-known scope issue. - * @private - * @type {Sigma} - */ - var self = this; - - /** - * The ID of the instance. - * @type {string} - */ - this.id = id.toString(); - - /** - * The different parameters that define how this instance should work. - * @see sigma.classes.Cascade - * @type {Object} - */ - this.p = { - auto: true, - drawNodes: 2, - drawEdges: 1, - drawLabels: 2, - lastNodes: 2, - lastEdges: 0, - lastLabels: 2, - drawHoverNodes: true, - drawActiveNodes: true - }; - - /** - * The root DOM element of this instance, containing every other elements. - * @type {element} - */ - this.domRoot = root; - - /** - * The width of this instance - initially, the root's width. - * @type {number} - */ - this.width = this.domRoot.offsetWidth; - - /** - * The height of this instance - initially, the root's height. - * @type {number} - */ - this.height = this.domRoot.offsetHeight; - - /** - * The graph of this instance - initiallyempty. - * @type {Graph} - */ - this.graph = new Graph(); - - /** - * An object referencing every DOM elements used by this instance. - * @type {Object} - */ - this.domElements = {}; - - initDOM('edges', 'canvas'); - initDOM('nodes', 'canvas'); - initDOM('labels', 'canvas'); - initDOM('hover', 'canvas'); - initDOM('monitor', 'div'); - initDOM('mouse', 'canvas'); - - /** - * The class dedicated to manage the drawing process of the graph of the - * different canvas. - * @type {Plotter} - */ - this.plotter = new Plotter( - this.domElements.nodes.getContext('2d'), - this.domElements.edges.getContext('2d'), - this.domElements.labels.getContext('2d'), - this.domElements.hover.getContext('2d'), - this.graph, - this.width, - this.height - ); - - /** - * The class dedicated to monitor different probes about the running - * processes or the data, such as the number of nodes or edges, or how - * many times the graph is drawn per second. - * @type {Monitor} - */ - this.monitor = new Monitor( - this, - this.domElements.monitor - ); - - /** - * The class dedicated to manage the different mouse events. - * @type {MouseCaptor} - */ - this.mousecaptor = new MouseCaptor( - this.domElements.mouse, - this.id - ); - - // Interaction listeners: - this.mousecaptor.bind('drag interpolate', function(e) { - self.draw( - self.p.auto ? 2 : self.p.drawNodes, - self.p.auto ? 0 : self.p.drawEdges, - self.p.auto ? 2 : self.p.drawLabels, - true - ); - }).bind('stopdrag stopinterpolate', function(e) { - self.draw( - self.p.auto ? 2 : self.p.drawNodes, - self.p.auto ? 1 : self.p.drawEdges, - self.p.auto ? 2 : self.p.drawLabels, - true - ); - }).bind('mousedown mouseup', function(e) { - var targeted = self.graph.nodes.filter(function(n) { - return !!n['hover']; - }).map(function(n) { - return n.id; - }); - - self.dispatch( - e['type'] == 'mousedown' ? - 'downgraph' : - 'upgraph' - ); - - if (targeted.length) { - self.dispatch( - e['type'] == 'mousedown' ? - 'downnodes' : - 'upnodes', - targeted - ); - } - }).bind('move', function() { - self.domElements.hover.getContext('2d').clearRect( - 0, - 0, - self.domElements.hover.width, - self.domElements.hover.height - ); - - drawHover(); - drawActive(); - }); - - sigma.chronos.bind('startgenerators', function() { - if (sigma.chronos.getGeneratorsIDs().some(function(id) { - return !!id.match(new RegExp('_ext_' + self.id + '$', '')); - })) { - self.draw( - self.p.auto ? 2 : self.p.drawNodes, - self.p.auto ? 0 : self.p.drawEdges, - self.p.auto ? 2 : self.p.drawLabels - ); - } - }).bind('stopgenerators', function() { - self.draw(); - }); - - /** - * Resizes the element, and redraws the graph with the last settings. - * @param {?number} w The new width (if undefined, it will use the root - * width). - * @param {?number} h The new height (if undefined, it will use the root - * height). - * @return {Sigma} Returns itself. - */ - function resize(w, h) { - var oldW = self.width, oldH = self.height; - - if (w != undefined && h != undefined) { - self.width = w; - self.height = h; - }else { - self.width = self.domRoot.offsetWidth; - self.height = self.domRoot.offsetHeight; - } - - if (oldW != self.width || oldH != self.height) { - for (var k in self.domElements) { - self.domElements[k].setAttribute('width', self.width + 'px'); - self.domElements[k].setAttribute('height', self.height + 'px'); - } - - self.plotter.resize(self.width, self.height); - - self.draw( - self.p.lastNodes, - self.p.lastEdges, - self.p.lastLabels, - true - ); - } - return self; - }; - - /** - * Kills every drawing task currently running. Basically, it stops this - * instance's drawing process. - * @return {Sigma} Returns itself. - */ - function clearSchedule() { - sigma.chronos.removeTask( - 'node_' + self.id, 2 - ).removeTask( - 'edge_' + self.id, 2 - ).removeTask( - 'label_' + self.id, 2 - ).stopTasks(); - return self; - }; - - /** - * Initialize a DOM element, that will be stores by this instance, to make - * automatic these elements resizing. - * @private - * @param {string} id The element's ID. - * @param {string} type The element's nodeName (Example : canvas, div, ...). - * @return {Sigma} Returns itself. - */ - function initDOM(id, type) { - self.domElements[id] = document.createElement(type); - self.domElements[id].style.position = 'absolute'; - self.domElements[id].setAttribute('id', 'sigma_' + id + '_' + self.id); - self.domElements[id].setAttribute('class', 'sigma_' + id + '_' + type); - self.domElements[id].setAttribute('width', self.width + 'px'); - self.domElements[id].setAttribute('height', self.height + 'px'); - - self.domRoot.appendChild(self.domElements[id]); - return self; - }; - - /** - * Starts the graph drawing process. The three first parameters indicate - * how the different layers have to be drawn: - * . -1: The layer is not drawn, but it is not erased. - * . 0: The layer is not drawn. - * . 1: The layer is drawn progressively. - * . 2: The layer is drawn directly. - * @param {?number} nodes Determines if and how the nodes must be drawn. - * @param {?number} edges Determines if and how the edges must be drawn. - * @param {?number} labels Determines if and how the labels must be drawn. - * @param {?boolean} safe If true, nothing will happen if any generator - * affiliated to this instance is currently running - * (an iterative layout, for example). - * @return {Sigma} Returns itself. - */ - function draw(nodes, edges, labels, safe) { - if (safe && sigma.chronos.getGeneratorsIDs().some(function(id) { - return !!id.match(new RegExp('_ext_' + self.id + '$', '')); - })) { - return self; - } - - var n = (nodes == undefined) ? self.p.drawNodes : nodes; - var e = (edges == undefined) ? self.p.drawEdges : edges; - var l = (labels == undefined) ? self.p.drawLabels : labels; - - var params = { - nodes: n, - edges: e, - labels: l - }; - - self.p.lastNodes = n; - self.p.lastEdges = e; - self.p.lastLabels = l; - - // Remove tasks: - clearSchedule(); - - // Rescale graph: - self.graph.rescale( - self.width, - self.height, - n > 0, - e > 0 - ).setBorders(); - - self.mousecaptor.checkBorders( - self.graph.borders, - self.width, - self.height - ); - - self.graph.translate( - self.mousecaptor.stageX, - self.mousecaptor.stageY, - self.mousecaptor.ratio, - n > 0, - e > 0 - ); - - self.dispatch( - 'graphscaled' - ); - - // Clear scene: - for (var k in self.domElements) { - if ( - self.domElements[k].nodeName.toLowerCase() == 'canvas' && - (params[k] == undefined || params[k] >= 0) - ) { - self.domElements[k].getContext('2d').clearRect( - 0, - 0, - self.domElements[k].width, - self.domElements[k].height - ); - } - } - - self.plotter.currentEdgeIndex = 0; - self.plotter.currentNodeIndex = 0; - self.plotter.currentLabelIndex = 0; - - var previous = null; - var start = false; - - if (n) { - if (n > 1) { - while (self.plotter.task_drawNode()) {} - }else { - sigma.chronos.addTask( - self.plotter.task_drawNode, - 'node_' + self.id, - false - ); - - start = true; - previous = 'node_' + self.id; - } - } - - if (l) { - if (l > 1) { - while (self.plotter.task_drawLabel()) {} - } else { - if (previous) { - sigma.chronos.queueTask( - self.plotter.task_drawLabel, - 'label_' + self.id, - previous - ); - } else { - sigma.chronos.addTask( - self.plotter.task_drawLabel, - 'label_' + self.id, -