');
+ $table.append($row);
+ for (var j = 0; j < D[i].length; j++) {
+ var $cell = $('
')
+ .css(this.getCellCss())
+ .text(D[i][j]);
+ $row.append($cell);
+ }
+ }
+ this.resize();
-Array2DTracer.prototype.pushSelectingStep = function () {
- var args = Array.prototype.slice.call(arguments);
- var type = args.shift();
- var mode = args.shift();
- args = Array.prototype.slice.call(args.shift());
- var coord;
- switch (mode) {
- case 'row':
- coord = {
- x: args[0],
- sy: args[1],
- ey: args[2]
- };
- break;
- case 'col':
- coord = {
- y: args[0],
- sx: args[1],
- ex: args[2]
- };
- break;
- case 'set':
- coord = {
- coords: args[0]
- };
- break;
- default:
- if (args[2] === undefined && args[3] === undefined) {
+ return false;
+ },
+ _notify: function (x1, y1, x2, y2) {
+ var second = x2 !== undefined && y2 !== undefined;
+ this.pushStep({
+ type: 'notifying',
+ x: x1,
+ y: y1,
+ value: this.D[x1][y1]
+ }, !second);
+ if (second) this.pushStep({
+ type: 'notifying',
+ x: x2,
+ y: y2,
+ value: this.D[x2][y2]
+ }, true);
+ this.pushStep({
+ type: 'notified',
+ x: x1,
+ y: y1
+ }, false);
+ if (second) this.pushStep({
+ type: 'notified',
+ x: x2,
+ y: y2
+ }, false);
+ },
+ _select: function (sx, sy, ex, ey) {
+ this.pushSelectingStep('select', null, arguments);
+ },
+ _selectRow: function (x, sy, ey) {
+ this.pushSelectingStep('select', 'row', arguments);
+ },
+ _selectCol: function (y, sx, ex) {
+ this.pushSelectingStep('select', 'col', arguments);
+ },
+ _selectSet: function (coords) {
+ this.pushSelectingStep('select', 'set', arguments);
+ },
+ _deselect: function (sx, sy, ex, ey) {
+ this.pushSelectingStep('deselect', null, arguments);
+ },
+ _deselectRow: function (x, sy, ey) {
+ this.pushSelectingStep('deselect', 'row', arguments);
+ },
+ _deselectCol: function (y, sx, ex) {
+ this.pushSelectingStep('deselect', 'col', arguments);
+ },
+ _deselectSet: function (coords) {
+ this.pushSelectingStep('deselect', 'set', arguments);
+ },
+ pushSelectingStep: function () {
+ var args = Array.prototype.slice.call(arguments);
+ var type = args.shift();
+ var mode = args.shift();
+ args = Array.prototype.slice.call(args.shift());
+ var coord;
+ switch (mode) {
+ case 'row':
coord = {
x: args[0],
- y: args[1]
+ sy: args[1],
+ ey: args[2]
};
- } else {
+ break;
+ case 'col':
coord = {
- sx: args[0],
- sy: args[1],
- ex: args[2],
- ey: args[3]
+ y: args[0],
+ sx: args[1],
+ ex: args[2]
};
- }
- }
- var step = {
- type: type
- };
- $.extend(step, coord);
- this.pushStep(step, type == 'select');
-};
-
-Array2DTracer.prototype.processStep = function (step, options) {
- switch (step.type) {
- case 'notifying':
- var $row = $table.find('.mtbl-row').eq(step.x);
- $row.find('.mtbl-cell').eq(step.y).text(step.value);
- case 'notified':
- case 'select':
- case 'deselect':
- var colorClass = step.type == 'select' || step.type == 'deselect' ? Array2D.tableColorClass.selected : Array2D.tableColorClass.notifying;
- var addClass = step.type == 'select' || step.type == 'notifying';
- if (step.coords) {
- step.coords.forEach(function (coord) {
- var x = coord.x;
- var y = coord.y;
- Array2D.paintColor(x, y, x, y, colorClass, addClass);
- });
- } else {
- var sx = step.sx;
- var sy = step.sy;
- var ex = step.ex;
- var ey = step.ey;
- if (sx === undefined) sx = step.x;
- if (sy === undefined) sy = step.y;
- if (ex === undefined) ex = step.x;
- if (ey === undefined) ey = step.y;
- Array2D.paintColor(sx, sy, ex, ey, colorClass, addClass);
- }
- break;
- }
-};
-
-Array2DTracer.prototype.getCellCss = function () {
- return {
- padding: this.paddingV.toFixed(1) + 'px ' + this.paddingH.toFixed(1) + 'px',
- 'font-size': this.fontSize.toFixed(1) + 'px'
- };
-};
-
-// Override
-Array2DTracer.prototype.refresh = function () {
- Tracer.prototype.refresh.call(this);
-
- var $parent = $table.parent();
- var top = $parent.height() / 2 - $table.height() / 2 + this.viewY;
- var left = $parent.width() / 2 - $table.width() / 2 + this.viewX;
- $table.css('margin-top', top);
- $table.css('margin-left', left);
-};
-
-// Override
-Array2DTracer.prototype.prevStep = function () {
- this.clear();
- $('#tab_trace .wrapper').empty();
- var finalIndex = this.traceIndex - 1;
- if (finalIndex < 0) {
- this.traceIndex = -1;
- return;
- }
- for (var i = 0; i < finalIndex; i++) {
- this.step(i, {
- virtual: true
- });
- }
- this.step(finalIndex);
-};
-
-// Override
-Array2DTracer.prototype.mousedown = function (e) {
- Tracer.prototype.mousedown.call(this, e);
-
- this.dragX = e.pageX;
- this.dragY = e.pageY;
- this.dragging = true;
-};
-
-// Override
-Array2DTracer.prototype.mousemove = function (e) {
- Tracer.prototype.mousemove.call(this, e);
+ break;
+ case 'set':
+ coord = {
+ coords: args[0]
+ };
+ break;
+ default:
+ if (args[2] === undefined && args[3] === undefined) {
+ coord = {
+ x: args[0],
+ y: args[1]
+ };
+ } else {
+ coord = {
+ sx: args[0],
+ sy: args[1],
+ ex: args[2],
+ ey: args[3]
+ };
+ }
+ }
+ var step = {
+ type: type
+ };
+ $.extend(step, coord);
+ this.pushStep(step, type == 'select');
+ },
+ processStep: function (step, options) {
+ switch (step.type) {
+ case 'notifying':
+ var $row = $table.find('.mtbl-row').eq(step.x);
+ $row.find('.mtbl-cell').eq(step.y).text(step.value);
+ case 'notified':
+ case 'select':
+ case 'deselect':
+ var colorClass = step.type == 'select' || step.type == 'deselect' ? this.colorClass.selected : this.colorClass.notifying;
+ var addClass = step.type == 'select' || step.type == 'notifying';
+ if (step.coords) {
+ step.coords.forEach(function (coord) {
+ var x = coord.x;
+ var y = coord.y;
+ this.paintColor(x, y, x, y, colorClass, addClass);
+ });
+ } else {
+ var sx = step.sx;
+ var sy = step.sy;
+ var ex = step.ex;
+ var ey = step.ey;
+ if (sx === undefined) sx = step.x;
+ if (sy === undefined) sy = step.y;
+ if (ex === undefined) ex = step.x;
+ if (ey === undefined) ey = step.y;
+ this.paintColor(sx, sy, ex, ey, colorClass, addClass);
+ }
+ break;
+ }
+ },
+ getCellCss: function () {
+ return {
+ padding: this.paddingV.toFixed(1) + 'px ' + this.paddingH.toFixed(1) + 'px',
+ 'font-size': this.fontSize.toFixed(1) + 'px'
+ };
+ },
+ refresh: function () {
+ Tracer.prototype.refresh.call(this);
+
+ var $parent = $table.parent();
+ var top = $parent.height() / 2 - $table.height() / 2 + this.viewY;
+ var left = $parent.width() / 2 - $table.width() / 2 + this.viewX;
+ $table.css('margin-top', top);
+ $table.css('margin-left', left);
+ },
+ prevStep: function () {
+ this.clear();
+ $('#tab_trace .wrapper').empty();
+ var finalIndex = this.traceIndex - 1;
+ if (finalIndex < 0) {
+ this.traceIndex = -1;
+ return;
+ }
+ for (var i = 0; i < finalIndex; i++) {
+ this.step(i, {
+ virtual: true
+ });
+ }
+ this.step(finalIndex);
+ },
+ mousedown: function (e) {
+ Tracer.prototype.mousedown.call(this, e);
- if (this.dragging) {
- this.viewX += e.pageX - this.dragX;
- this.viewY += e.pageY - this.dragY;
this.dragX = e.pageX;
this.dragY = e.pageY;
+ this.dragging = true;
+ },
+ mousemove: function (e) {
+ Tracer.prototype.mousemove.call(this, e);
+
+ if (this.dragging) {
+ this.viewX += e.pageX - this.dragX;
+ this.viewY += e.pageY - this.dragY;
+ this.dragX = e.pageX;
+ this.dragY = e.pageY;
+ this.refresh();
+ }
+ },
+ mouseup: function (e) {
+ Tracer.prototype.mouseup.call(this, e);
+
+ this.dragging = false;
+ },
+ mousewheel: function (e) {
+ Tracer.prototype.mousewheel.call(this, e);
+
+ e.preventDefault();
+ e = e.originalEvent;
+ var delta = (e.wheelDelta !== undefined && e.wheelDelta) ||
+ (e.detail !== undefined && -e.detail);
+ var weight = 1.01;
+ var ratio = delta > 0 ? 1 / weight : weight;
+ if (this.fontSize < 4 && ratio < 1) return;
+ if (this.fontSize > 40 && ratio > 1) return;
+ this.paddingV *= ratio;
+ this.paddingH *= ratio;
+ this.fontSize *= ratio;
+ $('.mtbl-cell').css(this.getCellCss());
this.refresh();
+ },
+ paintColor: function (sx, sy, ex, ey, colorClass, addClass) {
+ for (var i = sx; i <= ex; i++) {
+ var $row = $table.find('.mtbl-row').eq(i);
+ for (var j = sy; j <= ey; j++) {
+ var $cell = $row.find('.mtbl-cell').eq(j);
+ if (addClass) $cell.addClass(colorClass);
+ else $cell.removeClass(colorClass);
+ }
+ }
+ },
+ clearColor: function () {
+ $table.find('.mtbl-cell').removeClass(Object.keys(this.colorClass).join(' '));
+ },
+ colorClass: {
+ selected: 'selected',
+ notifying: 'notifying'
}
-};
-
-// Override
-Array2DTracer.prototype.mouseup = function (e) {
- Tracer.prototype.mouseup.call(this, e);
-
- this.dragging = false;
-};
-
-// Override
-Array2DTracer.prototype.mousewheel = function (e) {
- Tracer.prototype.mousewheel.call(this, e);
-
- e.preventDefault();
- e = e.originalEvent;
- var delta = (e.wheelDelta !== undefined && e.wheelDelta) ||
- (e.detail !== undefined && -e.detail);
- var weight = 1.01;
- var ratio = delta > 0 ? 1 / weight : weight;
- if (this.fontSize < 4 && ratio < 1) return;
- if (this.fontSize > 40 && ratio > 1) return;
- this.paddingV *= ratio;
- this.paddingH *= ratio;
- this.fontSize *= ratio;
- $('.mtbl-cell').css(this.getCellCss());
- this.refresh();
-};
+});
var Array2D = {
random: function (N, M, min, max) {
@@ -299,26 +291,5 @@ var Array2D = {
return a - b;
});
});
- },
- initTable: function () {
- $table = $('
');
- $module_container.append($table);
- },
- paintColor: function (sx, sy, ex, ey, colorClass, addClass) {
- for (var i = sx; i <= ex; i++) {
- var $row = $table.find('.mtbl-row').eq(i);
- for (var j = sy; j <= ey; j++) {
- var $cell = $row.find('.mtbl-cell').eq(j);
- if (addClass) $cell.addClass(colorClass);
- else $cell.removeClass(colorClass);
- }
- }
- },
- clearTableColor: function () {
- $table.find('.mtbl-cell').removeClass(Object.keys(Array2D.tableColorClass).join(' '));
- },
- tableColorClass: {
- selected: 'selected',
- notifying: 'notifying'
}
};
\ No newline at end of file
diff --git a/js/module/directed_graph.js b/js/module/directed_graph.js
index ad4e91d09a0840d30e0c14a15949cf042bcd849c..977e402451ee4d28cead6124f2e1baa16a0241b4 100644
--- a/js/module/directed_graph.js
+++ b/js/module/directed_graph.js
@@ -2,185 +2,17 @@ var s = null, graph = null, sigmaCanvas = null;
function DirectedGraphTracer(module) {
if (Tracer.call(this, module || DirectedGraphTracer)) {
- DirectedGraph.initGraph();
+ DirectedGraphTracer.prototype.init.call(this);
return true;
}
return false;
}
-DirectedGraphTracer.prototype = Object.create(Tracer.prototype);
-DirectedGraphTracer.prototype.constructor = DirectedGraphTracer;
+DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
+ constructor: DirectedGraphTracer,
+ init: function () {
+ var tracer = this;
-// Override
-DirectedGraphTracer.prototype.resize = function () {
- Tracer.prototype.resize.call(this);
-
- this.refresh();
-};
-
-// Override
-DirectedGraphTracer.prototype.clear = function () {
- Tracer.prototype.clear.call(this);
-
- DirectedGraph.clearGraphColor();
-};
-
-DirectedGraphTracer.prototype._setTreeData = function (G, root) {
- root = root || 0;
- var maxDepth = -1;
-
- var chk = [];
- for (var i = 0; i < G.length; i++) chk.push(false);
- var getDepth = function (node, depth) {
- if (chk[node]) throw "the given graph is not a tree because it forms a circuit";
- chk[node] = true;
- if (maxDepth < depth) maxDepth = depth;
- for (var i = 0; i < G[node].length; i++) {
- if (G[node][i]) getDepth(i, depth + 1);
- }
- };
- getDepth(root, 1);
-
- if (this._setData(G, root)) return true;
-
- var place = function (node, x, y) {
- var temp = graph.nodes(DirectedGraph.n(node));
- temp.x = x;
- temp.y = y;
- };
-
- var wgap = 1 / (maxDepth - 1);
- var dfs = function (node, depth, top, bottom) {
- place(node, depth * wgap, (top + bottom) / 2);
- var children = 0;
- for (var i = 0; i < G[node].length; i++) {
- if (G[node][i]) children++;
- }
- var vgap = (bottom - top) / children;
- var cnt = 0;
- for (var i = 0; i < G[node].length; i++) {
- if (G[node][i]) dfs(i, depth + 1, top + vgap * cnt, top + vgap * ++cnt);
- }
- };
- dfs(root, 0, 0, 1);
-
- this.refresh();
-};
-
-// Override
-DirectedGraphTracer.prototype._setData = function (G) {
- if (Tracer.prototype._setData.call(this, arguments)) return true;
-
- graph.clear();
- var nodes = [];
- var edges = [];
- var unitAngle = 2 * Math.PI / G.length;
- var currentAngle = 0;
- for (var i = 0; i < G.length; i++) {
- currentAngle += unitAngle;
- nodes.push({
- id: DirectedGraph.n(i),
- label: '' + i,
- x: .5 + Math.sin(currentAngle) / 2,
- y: .5 + Math.cos(currentAngle) / 2,
- size: 1,
- color: DirectedGraph.graphColor.default
- });
- for (var j = 0; j < G[i].length; j++) {
- if (G[i][j]) {
- edges.push({
- id: DirectedGraph.e(i, j),
- source: DirectedGraph.n(i),
- target: DirectedGraph.n(j),
- color: DirectedGraph.graphColor.default,
- size: 1
- });
- }
- }
- }
-
- graph.read({
- nodes: nodes,
- edges: edges
- });
- s.camera.goTo({
- x: 0,
- y: 0,
- angle: 0,
- ratio: 1
- });
- this.refresh();
-
- return false;
-};
-
-DirectedGraphTracer.prototype._visit = function (target, source) {
- this.pushStep({type: 'visit', target: target, source: source}, true);
-};
-
-DirectedGraphTracer.prototype._leave = function (target, source) {
- this.pushStep({type: 'leave', target: target, source: source}, true);
-};
-
-DirectedGraphTracer.prototype.processStep = function (step, options) {
- switch (step.type) {
- case 'visit':
- case 'leave':
- var visit = step.type == 'visit';
- var targetNode = graph.nodes(DirectedGraph.n(step.target));
- var color = visit ? DirectedGraph.graphColor.visited : DirectedGraph.graphColor.left;
- targetNode.color = color;
- if (step.source !== undefined) {
- var edgeId = DirectedGraph.e(step.source, step.target);
- var edge = graph.edges(edgeId);
- edge.color = color;
- graph.dropEdge(edgeId).addEdge(edge);
- }
- var source = step.source;
- if (source === undefined) source = '';
- printTrace(visit ? source + ' -> ' + step.target : source + ' <- ' + step.target);
- break;
- }
-};
-
-// Override
-DirectedGraphTracer.prototype.refresh = function () {
- Tracer.prototype.refresh.call(this);
-
- s.refresh();
-};
-
-// Override
-DirectedGraphTracer.prototype.prevStep = function () {
- this.clear();
- $('#tab_trace .wrapper').empty();
- var finalIndex = this.traceIndex - 1;
- if (finalIndex < 0) {
- this.traceIndex = -1;
- this.refresh();
- return;
- }
- for (var i = 0; i < finalIndex; i++) {
- this.step(i, {virtual: true});
- }
- this.step(finalIndex);
-};
-
-var DirectedGraph = {
- random: function (N, ratio) {
- if (!N) N = 5;
- if (!ratio) ratio = .3;
- var G = [];
- for (var i = 0; i < N; i++) {
- G.push([]);
- for (var j = 0; j < N; j++) {
- if (i == j) G[i].push(0);
- else G[i].push((Math.random() * (1 / ratio) | 0) == 0 ? 1 : 0);
- }
- }
- return G;
- },
- initGraph: function () {
if (sigmaCanvas == null) {
sigmaCanvas = $.extend(true, {}, sigma.canvas);
} else {
@@ -204,32 +36,178 @@ var DirectedGraph = {
minNodeSize: .5,
maxNodeSize: 12,
labelSize: 'proportional',
- labelSizeRatio: 1.3,
- edgeLabelSize: 'proportional',
- defaultEdgeLabelSize: 20,
- edgeLabelSizePowRatio: 0.8
+ labelSizeRatio: 1.3
}
});
graph = s.graph;
- sigma.canvas.labels.def = DirectedGraph.drawLabel;
- sigma.canvas.hovers.def = DirectedGraph.drawOnHover;
+ sigma.canvas.labels.def = function (node, context, settings) {
+ tracer.drawLabel(node, context, settings);
+ };
+ sigma.canvas.hovers.def = function (node, context, settings, next) {
+ tracer.drawOnHover(node, context, settings, next);
+ };
sigma.canvas.edges.arrow = function (edge, source, target, context, settings) {
- var color = DirectedGraph.getColor(edge, source, target, settings);
- DirectedGraph.drawArrow(edge, source, target, color, context, settings);
+ var color = tracer.getColor(edge, source, target, settings);
+ tracer.drawArrow(edge, source, target, color, context, settings);
};
sigma.plugins.dragNodes(s, s.renderers[0]);
},
- graphColor: {
+ resize: function () {
+ Tracer.prototype.resize.call(this);
+
+ this.refresh();
+ },
+ clear: function () {
+ Tracer.prototype.clear.call(this);
+
+ this.clearGraphColor();
+ },
+ _setTreeData: function (G, root) {
+ var tracer = this;
+
+ root = root || 0;
+ var maxDepth = -1;
+
+ var chk = [];
+ for (var i = 0; i < G.length; i++) chk.push(false);
+ var getDepth = function (node, depth) {
+ if (chk[node]) throw "the given graph is not a tree because it forms a circuit";
+ chk[node] = true;
+ if (maxDepth < depth) maxDepth = depth;
+ for (var i = 0; i < G[node].length; i++) {
+ if (G[node][i]) getDepth(i, depth + 1);
+ }
+ };
+ getDepth(root, 1);
+
+ if (this._setData(G, root)) return true;
+
+ var place = function (node, x, y) {
+ var temp = graph.nodes(tracer.n(node));
+ temp.x = x;
+ temp.y = y;
+ };
+
+ var wgap = 1 / (maxDepth - 1);
+ var dfs = function (node, depth, top, bottom) {
+ place(node, depth * wgap, (top + bottom) / 2);
+ var children = 0;
+ for (var i = 0; i < G[node].length; i++) {
+ if (G[node][i]) children++;
+ }
+ var vgap = (bottom - top) / children;
+ var cnt = 0;
+ for (var i = 0; i < G[node].length; i++) {
+ if (G[node][i]) dfs(i, depth + 1, top + vgap * cnt, top + vgap * ++cnt);
+ }
+ };
+ dfs(root, 0, 0, 1);
+
+ this.refresh();
+ },
+ _setData: function (G) {
+ if (Tracer.prototype._setData.call(this, arguments)) return true;
+
+ graph.clear();
+ var nodes = [];
+ var edges = [];
+ var unitAngle = 2 * Math.PI / G.length;
+ var currentAngle = 0;
+ for (var i = 0; i < G.length; i++) {
+ currentAngle += unitAngle;
+ nodes.push({
+ id: this.n(i),
+ label: '' + i,
+ x: .5 + Math.sin(currentAngle) / 2,
+ y: .5 + Math.cos(currentAngle) / 2,
+ size: 1,
+ color: this.color.default
+ });
+ for (var j = 0; j < G[i].length; j++) {
+ if (G[i][j]) {
+ edges.push({
+ id: this.e(i, j),
+ source: this.n(i),
+ target: this.n(j),
+ color: this.color.default,
+ size: 1
+ });
+ }
+ }
+ }
+
+ graph.read({
+ nodes: nodes,
+ edges: edges
+ });
+ s.camera.goTo({
+ x: 0,
+ y: 0,
+ angle: 0,
+ ratio: 1
+ });
+ this.refresh();
+
+ return false;
+ },
+ _visit: function (target, source) {
+ this.pushStep({type: 'visit', target: target, source: source}, true);
+ },
+ _leave: function (target, source) {
+ this.pushStep({type: 'leave', target: target, source: source}, true);
+ },
+ processStep: function (step, options) {
+ switch (step.type) {
+ case 'visit':
+ case 'leave':
+ var visit = step.type == 'visit';
+ var targetNode = graph.nodes(this.n(step.target));
+ var color = visit ? this.color.visited : this.color.left;
+ targetNode.color = color;
+ if (step.source !== undefined) {
+ var edgeId = this.e(step.source, step.target);
+ var edge = graph.edges(edgeId);
+ edge.color = color;
+ graph.dropEdge(edgeId).addEdge(edge);
+ }
+ var source = step.source;
+ if (source === undefined) source = '';
+ this.printTrace(visit ? source + ' -> ' + step.target : source + ' <- ' + step.target);
+ break;
+ }
+ },
+ refresh: function () {
+ Tracer.prototype.refresh.call(this);
+
+ s.refresh();
+ },
+ prevStep: function () {
+ this.clear();
+ $('#tab_trace .wrapper').empty();
+ var finalIndex = this.traceIndex - 1;
+ if (finalIndex < 0) {
+ this.traceIndex = -1;
+ this.refresh();
+ return;
+ }
+ for (var i = 0; i < finalIndex; i++) {
+ this.step(i, {virtual: true});
+ }
+ this.step(finalIndex);
+ },
+ color: {
visited: '#f00',
left: '#000',
default: '#888'
},
clearGraphColor: function () {
+ var tracer = this;
+
graph.nodes().forEach(function (node) {
- node.color = DirectedGraph.graphColor.default;
+ node.color = tracer.color.default;
});
graph.edges().forEach(function (edge) {
- edge.color = DirectedGraph.graphColor.default;
+ edge.color = tracer.color.default;
});
},
n: function (v) {
@@ -326,6 +304,8 @@ var DirectedGraph = {
context.fill();
},
drawOnHover: function (node, context, settings, next) {
+ var tracer = this;
+
var nodeIdx = node.id.substring(1);
graph.edges().forEach(function (edge) {
var ends = edge.id.substring(1).split("_");
@@ -334,15 +314,31 @@ var DirectedGraph = {
var color = '#0ff';
var source = node;
var target = graph.nodes('n' + ends[1]);
- DirectedGraph.drawArrow(edge, source, target, color, context, settings);
+ tracer.drawArrow(edge, source, target, color, context, settings);
if (next) next(edge, source, target, color, context, settings);
} else if (ends[1] == nodeIdx) {
var color = '#ff0';
var source = graph.nodes('n' + ends[0]);
var target = node;
- DirectedGraph.drawArrow(edge, source, target, color, context, settings);
+ tracer.drawArrow(edge, source, target, color, context, settings);
if (next) next(edge, source, target, color, context, settings);
}
});
}
+});
+
+var DirectedGraph = {
+ random: function (N, ratio) {
+ if (!N) N = 5;
+ if (!ratio) ratio = .3;
+ var G = [];
+ for (var i = 0; i < N; i++) {
+ G.push([]);
+ for (var j = 0; j < N; j++) {
+ if (i == j) G[i].push(0);
+ else G[i].push((Math.random() * (1 / ratio) | 0) == 0 ? 1 : 0);
+ }
+ }
+ return G;
+ }
};
\ No newline at end of file
diff --git a/js/module/directed_weighted_graph.js b/js/module/directed_weighted_graph.js
deleted file mode 100644
index 99c889b813f6606f8d9dae21f5ce4370460e639b..0000000000000000000000000000000000000000
--- a/js/module/directed_weighted_graph.js
+++ /dev/null
@@ -1,235 +0,0 @@
-function WeightedDirectedGraphTracer(module) {
- if (DirectedGraphTracer.call(this, module || WeightedDirectedGraphTracer)) {
- WeightedDirectedGraph.initWeightedGraph();
- return true;
- }
- return false;
-}
-
-WeightedDirectedGraphTracer.prototype = Object.create(DirectedGraphTracer.prototype);
-WeightedDirectedGraphTracer.prototype.constructor = WeightedDirectedGraphTracer;
-
-// Override
-WeightedDirectedGraphTracer.prototype.clear = function () {
- DirectedGraphTracer.prototype.clear.call(this);
-
- WeightedDirectedGraph.clearWeights();
-};
-
-// Override
-WeightedDirectedGraphTracer.prototype._setData = function (G) {
- if (Tracer.prototype._setData.call(this, arguments)) return true;
-
- graph.clear();
- var nodes = [];
- var edges = [];
- var unitAngle = 2 * Math.PI / G.length;
- var currentAngle = 0;
- for (var i = 0; i < G.length; i++) {
- currentAngle += unitAngle;
- nodes.push({
- id: DirectedGraph.n(i),
- label: '' + i,
- x: .5 + Math.sin(currentAngle) / 2,
- y: .5 + Math.cos(currentAngle) / 2,
- size: 1,
- color: DirectedGraph.graphColor.default,
- weight: 0
- });
- for (var j = 0; j < G[i].length; j++) {
- if (G[i][j]) {
- edges.push({
- id: DirectedGraph.e(i, j),
- source: DirectedGraph.n(i),
- target: DirectedGraph.n(j),
- color: DirectedGraph.graphColor.default,
- size: 1,
- weight: G[i][j]
- });
- }
- }
- }
-
- graph.read({
- nodes: nodes,
- edges: edges
- });
- s.camera.goTo({
- x: 0,
- y: 0,
- angle: 0,
- ratio: 1
- });
- this.refresh();
-
- return false;
-};
-
-DirectedGraphTracer.prototype._weight = function (target, weight, delay) {
- this.pushStep({type: 'weight', target: target, weight: weight}, delay);
-};
-
-DirectedGraphTracer.prototype._visit = function (target, source, weight) {
- this.pushStep({type: 'visit', target: target, source: source, weight: weight}, true);
-};
-
-DirectedGraphTracer.prototype._leave = function (target, source, weight) {
- this.pushStep({type: 'leave', target: target, source: source, weight: weight}, true);
-};
-
-//Override
-WeightedDirectedGraphTracer.prototype.processStep = function (step, options) {
- switch (step.type) {
- case 'weight':
- var targetNode = graph.nodes(DirectedGraph.n(step.target));
- if (step.weight !== undefined) targetNode.weight = step.weight;
- break;
- case 'visit':
- case 'leave':
- var visit = step.type == 'visit';
- var targetNode = graph.nodes(DirectedGraph.n(step.target));
- var color = visit ? DirectedGraph.graphColor.visited : DirectedGraph.graphColor.left;
- targetNode.color = color;
- if (step.weight !== undefined) targetNode.weight = step.weight;
- if (step.source !== undefined) {
- var edgeId = DirectedGraph.e(step.source, step.target);
- var edge = graph.edges(edgeId);
- edge.color = color;
- graph.dropEdge(edgeId).addEdge(edge);
- }
- var source = step.source;
- if (source === undefined) source = '';
- printTrace(visit ? source + ' -> ' + step.target : source + ' <- ' + step.target);
- break;
- default:
- DirectedGraphTracer.prototype.processStep.call(this, step, options);
- }
-};
-
-var WeightedDirectedGraph = {
- random: function (N, ratio, min, max) {
- if (!N) N = 5;
- if (!ratio) ratio = .3;
- if (!min) min = 1;
- if (!max) max = 5;
- var G = [];
- for (var i = 0; i < N; i++) {
- G.push([]);
- for (var j = 0; j < N; j++) {
- if (i == j) G[i].push(0);
- else if ((Math.random() * (1 / ratio) | 0) == 0) {
- G[i].push((Math.random() * (max - min + 1) | 0) + min);
- } else {
- G[i].push(0);
- }
- }
- }
- return G;
- },
- clearWeights: function () {
- graph.nodes().forEach(function (node) {
- node.weight = 0;
- });
- },
- drawEdgeWeight: function (edge, source, target, color, context, settings) {
- if (source == target)
- return;
-
- var prefix = settings('prefix') || '',
- size = edge[prefix + 'size'] || 1;
-
- if (size < settings('edgeLabelThreshold'))
- return;
-
- if (0 === settings('edgeLabelSizePowRatio'))
- throw '"edgeLabelSizePowRatio" must not be 0.';
-
- var fontSize,
- x = (source[prefix + 'x'] + target[prefix + 'x']) / 2,
- y = (source[prefix + 'y'] + target[prefix + 'y']) / 2,
- dX = target[prefix + 'x'] - source[prefix + 'x'],
- dY = target[prefix + 'y'] - source[prefix + 'y'],
- angle = Math.atan2(dY, dX);
-
- fontSize = (settings('edgeLabelSize') === 'fixed') ?
- settings('defaultEdgeLabelSize') :
- settings('defaultEdgeLabelSize') *
- size *
- Math.pow(size, -1 / settings('edgeLabelSizePowRatio'));
-
- context.save();
-
- if (edge.active) {
- context.font = [
- settings('activeFontStyle'),
- fontSize + 'px',
- settings('activeFont') || settings('font')
- ].join(' ');
-
- context.fillStyle = color;
- }
- else {
- context.font = [
- settings('fontStyle'),
- fontSize + 'px',
- settings('font')
- ].join(' ');
-
- context.fillStyle = color;
- }
-
- context.textAlign = 'center';
- context.textBaseline = 'alphabetic';
-
- context.translate(x, y);
- context.rotate(angle);
- context.fillText(
- edge.weight,
- 0,
- (-size / 2) - 3
- );
-
- context.restore();
- },
- initWeightedGraph: function () {
- sigma.canvas.edges.arrow = function (edge, source, target, context, settings) {
- var color = DirectedGraph.getColor(edge, source, target, settings);
- DirectedGraph.drawArrow(edge, source, target, color, context, settings);
- WeightedDirectedGraph.drawEdgeWeight(edge, source, target, color, context, settings);
- };
- sigma.canvas.hovers.def = function (node, context, settings) {
- DirectedGraph.drawOnHover(node, context, settings, function (edge, source, target, color, context, settings) {
- WeightedDirectedGraph.drawEdgeWeight(edge, source, target, color, context, settings);
- });
- };
- sigma.canvas.labels.def = function (node, context, settings) {
- WeightedDirectedGraph.drawNodeWeight(node, context, settings);
- DirectedGraph.drawLabel(node, context, settings);
- }
- },
- drawNodeWeight: function (node, context, settings) {
- var fontSize,
- prefix = settings('prefix') || '',
- size = node[prefix + 'size'];
-
- if (size < settings('labelThreshold'))
- return;
-
- fontSize = (settings('labelSize') === 'fixed') ?
- settings('defaultLabelSize') :
- settings('labelSizeRatio') * size;
-
- context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
- fontSize + 'px ' + settings('font');
- context.fillStyle = (settings('labelColor') === 'node') ?
- (node.color || settings('defaultNodeColor')) :
- settings('defaultLabelColor');
-
- context.textAlign = 'left';
- context.fillText(
- node.weight,
- Math.round(node[prefix + 'x'] + size * 1.5),
- Math.round(node[prefix + 'y'] + fontSize / 3)
- );
- }
-};
\ No newline at end of file
diff --git a/js/module/tracer.js b/js/module/tracer.js
index 0cc0f8a5b6100e6c84d241dca00a0128fc62ce0d..8fedaead6e36b7466abed83c880c4c74fca4a151 100644
--- a/js/module/tracer.js
+++ b/js/module/tracer.js
@@ -15,147 +15,128 @@ var Tracer = function (module) {
return moduleChanged;
};
-Tracer.prototype.resize = function () {
-};
-
-Tracer.prototype.clear = function () {
-};
-
-Tracer.prototype.reset = function () {
- this.traces = [];
- this.stepCnt = 0;
- if (timer) clearTimeout(timer);
- $('#tab_trace .wrapper').empty();
- this.clear();
-};
-
-Tracer.prototype._setData = function (arguments) {
- var data = JSON.stringify(arguments);
- if (lastModule == this.module && lastData == data) return true;
- lastData = data;
- return false;
-};
-
-Tracer.prototype.pushStep = function (step, delay) {
- if (this.stepCnt++ > stepLimit) throw "Tracer's stack overflow";
- var len = this.traces.length;
- var last = [];
- if (len == 0) {
- this.traces.push(last);
- } else {
- last = this.traces[len - 1];
- }
- last.push(step);
- if (delay) this.traces.push([]);
-};
-
-Tracer.prototype._sleep = function (duration) {
- this.pushStep({type: 'sleep', duration: duration}, true);
-};
-
-Tracer.prototype._print = function (msg, delay) {
- this.pushStep({type: 'print', msg: msg}, delay);
-};
-
-Tracer.prototype._pace = function (interval) {
- this.pushStep({type: 'pace', interval: interval}, false);
-};
-
-Tracer.prototype._clear = function () {
- this.pushStep({type: 'clear'}, true);
-};
-
-Tracer.prototype.visualize = function (options) {
- options = options || {};
- options.interval = options.interval || 500;
-
- $('#btn_trace').click();
- this.traceOptions = options;
- this.traceIndex = -1;
- this.resumeStep();
-};
-
-Tracer.prototype.isPause = function () {
- return this.pause;
-};
-
-Tracer.prototype.pauseStep = function () {
- if (this.traceIndex < 0) return;
- this.pause = true;
- if (timer) clearTimeout(timer);
- $('#btn_pause').addClass('active');
-};
-
-Tracer.prototype.resumeStep = function () {
- this.pause = false;
- this.step(this.traceIndex + 1);
- $('#btn_pause').removeClass('active');
-};
-
-Tracer.prototype.step = function (i, options) {
- if (isNaN(i) || i >= this.traces.length || i < 0) return;
- options = options || {};
-
- this.traceIndex = i;
- var trace = this.traces[i];
- var tracer = this;
- var sleepDuration = 0;
- trace.forEach(function (step) {
- switch (step.type) {
- case 'sleep':
- sleepDuration = step.duration;
- break;
- case 'print':
- printTrace(step.msg);
- break;
- case 'pace':
- tracer.traceOptions.interval = step.interval;
- break;
- case 'clear':
- tracer.clear();
- printTrace('clear traces');
- break;
- default:
- tracer.module.prototype.processStep.call(tracer, step, options);
+Tracer.prototype = {
+ resize: function () {
+ },
+ clear: function () {
+ },
+ reset: function () {
+ this.traces = [];
+ this.stepCnt = 0;
+ if (timer) clearTimeout(timer);
+ $('#tab_trace .wrapper').empty();
+ this.clear();
+ },
+ _setData: function (arguments) {
+ var data = JSON.stringify(arguments);
+ if (lastModule == this.module && lastData == data) return true;
+ lastData = data;
+ return false;
+ },
+ pushStep: function (step, delay) {
+ if (this.stepCnt++ > stepLimit) throw "Tracer's stack overflow";
+ var len = this.traces.length;
+ var last = [];
+ if (len == 0) {
+ this.traces.push(last);
+ } else {
+ last = this.traces[len - 1];
}
- });
- if (!options.virtual) {
- this.refresh();
- scrollToEnd(Math.min(50, this.traceOptions.interval));
+ last.push(step);
+ if (delay) this.traces.push([]);
+ },
+ _sleep: function (duration) {
+ this.pushStep({type: 'sleep', duration: duration}, true);
+ },
+ _print: function (msg, delay) {
+ this.pushStep({type: 'print', msg: msg}, delay);
+ },
+ _pace: function (interval) {
+ this.pushStep({type: 'pace', interval: interval}, false);
+ },
+ _clear: function () {
+ this.pushStep({type: 'clear'}, true);
+ },
+ visualize: function (options) {
+ options = options || {};
+ options.interval = options.interval || 500;
+
+ $('#btn_trace').click();
+ this.traceOptions = options;
+ this.traceIndex = -1;
+ this.resumeStep();
+ },
+ isPause: function () {
+ return this.pause;
+ },
+ pauseStep: function () {
+ if (this.traceIndex < 0) return;
+ this.pause = true;
+ if (timer) clearTimeout(timer);
+ $('#btn_pause').addClass('active');
+ },
+ resumeStep: function () {
+ this.pause = false;
+ this.step(this.traceIndex + 1);
+ $('#btn_pause').removeClass('active');
+ },
+ step: function (i, options) {
+ var tracer = this;
+
+ if (isNaN(i) || i >= this.traces.length || i < 0) return;
+ options = options || {};
+
+ this.traceIndex = i;
+ var trace = this.traces[i];
+ var sleepDuration = 0;
+ trace.forEach(function (step) {
+ switch (step.type) {
+ case 'sleep':
+ sleepDuration = step.duration;
+ break;
+ case 'print':
+ tracer.printTrace(step.msg);
+ break;
+ case 'pace':
+ tracer.traceOptions.interval = step.interval;
+ break;
+ case 'clear':
+ tracer.clear();
+ tracer.printTrace('clear traces');
+ break;
+ default:
+ tracer.module.prototype.processStep.call(tracer, step, options);
+ }
+ });
+ if (!options.virtual) {
+ this.refresh();
+ this.scrollToEnd(Math.min(50, this.traceOptions.interval));
+ }
+ if (this.pause) return;
+ timer = setTimeout(function () {
+ tracer.step(i + 1, options);
+ }, sleepDuration || this.traceOptions.interval);
+ },
+ refresh: function () {
+ },
+ prevStep: function () {
+ this.step(this.traceIndex - 1);
+ },
+ nextStep: function () {
+ this.step(this.traceIndex + 1);
+ },
+ mousedown: function (e) {
+ },
+ mousemove: function (e) {
+ },
+ mouseup: function (e) {
+ },
+ mousewheel: function (e) {
+ },
+ printTrace: function (message) {
+ $('#tab_trace .wrapper').append($('').append(message + '
'));
+ },
+ scrollToEnd: function (duration) {
+ $('#tab_trace').animate({scrollTop: $('#tab_trace')[0].scrollHeight}, duration);
}
- if (this.pause) return;
- timer = setTimeout(function () {
- tracer.step(i + 1, options);
- }, sleepDuration || this.traceOptions.interval);
-};
-
-Tracer.prototype.refresh = function () {
-};
-
-Tracer.prototype.prevStep = function () {
- this.step(this.traceIndex - 1);
-};
-
-Tracer.prototype.nextStep = function () {
- this.step(this.traceIndex + 1);
-};
-
-Tracer.prototype.mousedown = function (e) {
-};
-
-Tracer.prototype.mousemove = function (e) {
-};
-
-Tracer.prototype.mouseup = function (e) {
-};
-
-Tracer.prototype.mousewheel = function (e) {
-};
-
-var printTrace = function (message) {
- $('#tab_trace .wrapper').append($('').append(message + '
'));
-};
-
-var scrollToEnd = function (duration) {
- $('#tab_trace').animate({scrollTop: $('#tab_trace')[0].scrollHeight}, duration);
};
\ No newline at end of file
diff --git a/js/module/weighted_directed_graph.js b/js/module/weighted_directed_graph.js
new file mode 100644
index 0000000000000000000000000000000000000000..7f0e34ac315dbd148322ff108610dcc49ffbd85e
--- /dev/null
+++ b/js/module/weighted_directed_graph.js
@@ -0,0 +1,232 @@
+function WeightedDirectedGraphTracer(module) {
+ if (DirectedGraphTracer.call(this, module || WeightedDirectedGraphTracer)) {
+ WeightedDirectedGraphTracer.prototype.init.call(this);
+ return true;
+ }
+ return false;
+}
+
+WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTracer.prototype), {
+ constructor: WeightedDirectedGraphTracer,
+ init: function () {
+ var tracer = this;
+
+ s.settings({
+ edgeLabelSize: 'proportional',
+ defaultEdgeLabelSize: 20,
+ edgeLabelSizePowRatio: 0.8
+ });
+ sigma.canvas.edges.arrow = function (edge, source, target, context, settings) {
+ var color = tracer.getColor(edge, source, target, settings);
+ tracer.drawArrow(edge, source, target, color, context, settings);
+ tracer.drawEdgeWeight(edge, source, target, color, context, settings);
+ };
+ sigma.canvas.hovers.def = function (node, context, settings) {
+ tracer.drawOnHover(node, context, settings, tracer.drawEdgeWeight);
+ };
+ sigma.canvas.labels.def = function (node, context, settings) {
+ tracer.drawNodeWeight(node, context, settings);
+ tracer.drawLabel(node, context, settings);
+ }
+ },
+ clear: function () {
+ DirectedGraphTracer.prototype.clear.call(this);
+
+ this.clearWeights();
+ },
+ _setData: function (G) {
+ if (Tracer.prototype._setData.call(this, arguments)) return true;
+
+ graph.clear();
+ var nodes = [];
+ var edges = [];
+ var unitAngle = 2 * Math.PI / G.length;
+ var currentAngle = 0;
+ for (var i = 0; i < G.length; i++) {
+ currentAngle += unitAngle;
+ nodes.push({
+ id: this.n(i),
+ label: '' + i,
+ x: .5 + Math.sin(currentAngle) / 2,
+ y: .5 + Math.cos(currentAngle) / 2,
+ size: 1,
+ color: this.color.default,
+ weight: 0
+ });
+ for (var j = 0; j < G[i].length; j++) {
+ if (G[i][j]) {
+ edges.push({
+ id: this.e(i, j),
+ source: this.n(i),
+ target: this.n(j),
+ color: this.color.default,
+ size: 1,
+ weight: G[i][j]
+ });
+ }
+ }
+ }
+
+ graph.read({
+ nodes: nodes,
+ edges: edges
+ });
+ s.camera.goTo({
+ x: 0,
+ y: 0,
+ angle: 0,
+ ratio: 1
+ });
+ this.refresh();
+
+ return false;
+ },
+ _weight: function (target, weight, delay) {
+ this.pushStep({type: 'weight', target: target, weight: weight}, delay);
+ },
+ _visit: function (target, source, weight) {
+ this.pushStep({type: 'visit', target: target, source: source, weight: weight}, true);
+ },
+ _leave: function (target, source, weight) {
+ this.pushStep({type: 'leave', target: target, source: source, weight: weight}, true);
+ },
+ processStep: function (step, options) {
+ switch (step.type) {
+ case 'weight':
+ var targetNode = graph.nodes(this.n(step.target));
+ if (step.weight !== undefined) targetNode.weight = step.weight;
+ break;
+ case 'visit':
+ case 'leave':
+ var visit = step.type == 'visit';
+ var targetNode = graph.nodes(this.n(step.target));
+ var color = visit ? this.color.visited : this.color.left;
+ targetNode.color = color;
+ if (step.weight !== undefined) targetNode.weight = step.weight;
+ if (step.source !== undefined) {
+ var edgeId = this.e(step.source, step.target);
+ var edge = graph.edges(edgeId);
+ edge.color = color;
+ graph.dropEdge(edgeId).addEdge(edge);
+ }
+ var source = step.source;
+ if (source === undefined) source = '';
+ this.printTrace(visit ? source + ' -> ' + step.target : source + ' <- ' + step.target);
+ break;
+ default:
+ DirectedGraphTracer.prototype.processStep.call(this, step, options);
+ }
+ },
+ clearWeights: function () {
+ graph.nodes().forEach(function (node) {
+ node.weight = 0;
+ });
+ },
+ drawEdgeWeight: function (edge, source, target, color, context, settings) {
+ if (source == target)
+ return;
+
+ var prefix = settings('prefix') || '',
+ size = edge[prefix + 'size'] || 1;
+
+ if (size < settings('edgeLabelThreshold'))
+ return;
+
+ if (0 === settings('edgeLabelSizePowRatio'))
+ throw '"edgeLabelSizePowRatio" must not be 0.';
+
+ var fontSize,
+ x = (source[prefix + 'x'] + target[prefix + 'x']) / 2,
+ y = (source[prefix + 'y'] + target[prefix + 'y']) / 2,
+ dX = target[prefix + 'x'] - source[prefix + 'x'],
+ dY = target[prefix + 'y'] - source[prefix + 'y'],
+ angle = Math.atan2(dY, dX);
+
+ fontSize = (settings('edgeLabelSize') === 'fixed') ?
+ settings('defaultEdgeLabelSize') :
+ settings('defaultEdgeLabelSize') *
+ size *
+ Math.pow(size, -1 / settings('edgeLabelSizePowRatio'));
+
+ context.save();
+
+ if (edge.active) {
+ context.font = [
+ settings('activeFontStyle'),
+ fontSize + 'px',
+ settings('activeFont') || settings('font')
+ ].join(' ');
+
+ context.fillStyle = color;
+ }
+ else {
+ context.font = [
+ settings('fontStyle'),
+ fontSize + 'px',
+ settings('font')
+ ].join(' ');
+
+ context.fillStyle = color;
+ }
+
+ context.textAlign = 'center';
+ context.textBaseline = 'alphabetic';
+
+ context.translate(x, y);
+ context.rotate(angle);
+ context.fillText(
+ edge.weight,
+ 0,
+ (-size / 2) - 3
+ );
+
+ context.restore();
+ },
+ drawNodeWeight: function (node, context, settings) {
+ var fontSize,
+ prefix = settings('prefix') || '',
+ size = node[prefix + 'size'];
+
+ if (size < settings('labelThreshold'))
+ return;
+
+ fontSize = (settings('labelSize') === 'fixed') ?
+ settings('defaultLabelSize') :
+ settings('labelSizeRatio') * size;
+
+ context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
+ fontSize + 'px ' + settings('font');
+ context.fillStyle = (settings('labelColor') === 'node') ?
+ (node.color || settings('defaultNodeColor')) :
+ settings('defaultLabelColor');
+
+ context.textAlign = 'left';
+ context.fillText(
+ node.weight,
+ Math.round(node[prefix + 'x'] + size * 1.5),
+ Math.round(node[prefix + 'y'] + fontSize / 3)
+ );
+ }
+});
+
+var WeightedDirectedGraph = {
+ random: function (N, ratio, min, max) {
+ if (!N) N = 5;
+ if (!ratio) ratio = .3;
+ if (!min) min = 1;
+ if (!max) max = 5;
+ var G = [];
+ for (var i = 0; i < N; i++) {
+ G.push([]);
+ for (var j = 0; j < N; j++) {
+ if (i == j) G[i].push(0);
+ else if ((Math.random() * (1 / ratio) | 0) == 0) {
+ G[i].push((Math.random() * (max - min + 1) | 0) + min);
+ } else {
+ G[i].push(0);
+ }
+ }
+ }
+ return G;
+ }
+};
\ No newline at end of file