“20bfdbba7212d19613b93dcea93f26cb65af91fe”上不存在“README.md”
提交 4be4bc66 编写于 作者: R Raghav Dua

Merge pull request #1 from parkjs814/gh-pages

update
# Algorithm Visualizer
[![Join the chat at https://gitter.im/parkjs814/AlgorithmVisualizer](https://badges.gitter.im/parkjs814/AlgorithmVisualizer.svg)](https://gitter.im/parkjs814/AlgorithmVisualizer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
http://parkjs814.github.io/AlgorithmVisualizer
![Algorithm Visualizer](http://i.giphy.com/3o6EhJFgsyShX6MHeM.gif)
......
......@@ -109,7 +109,7 @@
<script src="js/ace/ace.js"></script>
<script src="js/module/tracer.js"></script>
<script src="js/module/directed_graph.js"></script>
<script src="js/module/directed_weighted_graph.js"></script>
<script src="js/module/weighted_directed_graph.js"></script>
<script src="js/module/array2d.js"></script>
<script src="js/module/array1d.js"></script>
<script src="js/script.js"></script>
......
......@@ -2,70 +2,59 @@ function Array1DTracer(module) {
return Array2DTracer.call(this, module || Array1DTracer);
}
Array1DTracer.prototype = Object.create(Array2DTracer.prototype);
Array1DTracer.prototype.constructor = Array1DTracer;
// Override
Array1DTracer.prototype._setData = function(D) {
return Array2DTracer.prototype._setData.call(this, [D]);
};
// Override
Array1DTracer.prototype._notify = function(idx1, idx2) {
if (idx2 === undefined) {
Array2DTracer.prototype._notify.call(this, 0, idx1);
} else {
Array2DTracer.prototype._notify.call(this, 0, idx1, 0, idx2);
}
};
// Override
Array1DTracer.prototype._select = function(s, e) {
if (e === undefined) {
Array2DTracer.prototype._select.call(this, 0, s);
} else {
Array2DTracer.prototype._selectRow.call(this, 0, s, e);
}
};
// Override
Array1DTracer.prototype._selectSet = function(indexes) {
var coords = [];
indexes.forEach(function(index) {
coords.push({
x: 0,
y: index
Array1DTracer.prototype = $.extend(true, Object.create(Array2DTracer.prototype), {
constructor: Array1DTracer,
_setData: function (D) {
return Array2DTracer.prototype._setData.call(this, [D]);
},
_notify: function (idx1, idx2) {
if (idx2 === undefined) {
Array2DTracer.prototype._notify.call(this, 0, idx1);
} else {
Array2DTracer.prototype._notify.call(this, 0, idx1, 0, idx2);
}
},
_select: function (s, e) {
if (e === undefined) {
Array2DTracer.prototype._select.call(this, 0, s);
} else {
Array2DTracer.prototype._selectRow.call(this, 0, s, e);
}
},
_selectSet: function (indexes) {
var coords = [];
indexes.forEach(function (index) {
coords.push({
x: 0,
y: index
});
});
});
Array2DTracer.prototype._selectSet.call(this, coords);
};
// Override
Array1DTracer.prototype._deselect = function(s, e) {
if (e === undefined) {
Array2DTracer.prototype._deselect.call(this, 0, s);
} else {
Array2DTracer.prototype._deselectRow.call(this, 0, s, e);
}
};
// Override
Array1DTracer.prototype._deselectSet = function(indexes) {
var coords = [];
indexes.forEach(function(index) {
coords.push({
x: 0,
y: index
Array2DTracer.prototype._selectSet.call(this, coords);
},
_deselect: function (s, e) {
if (e === undefined) {
Array2DTracer.prototype._deselect.call(this, 0, s);
} else {
Array2DTracer.prototype._deselectRow.call(this, 0, s, e);
}
},
_deselectSet: function (indexes) {
var coords = [];
indexes.forEach(function (index) {
coords.push({
x: 0,
y: index
});
});
});
Array2DTracer.prototype._deselectSet.call(this, coords);
};
Array2DTracer.prototype._deselectSet.call(this, coords);
}
});
var Array1D = {
random: function(N, min, max) {
random: function (N, min, max) {
return Array2D.random(1, N, min, max)[0];
},
randomSorted: function(N, min, max) {
randomSorted: function (N, min, max) {
return Array2D.randomSorted(1, N, min, max)[0];
}
};
\ No newline at end of file
......@@ -2,281 +2,275 @@ var $table = null;
function Array2DTracer(module) {
if (Tracer.call(this, module || Array2DTracer)) {
Array2D.initTable();
Array2DTracer.prototype.init.call(this);
return true;
}
return false;
}
Array2DTracer.prototype = Object.create(Tracer.prototype);
Array2DTracer.prototype.constructor = Array2DTracer;
// Override
Array2DTracer.prototype.resize = function () {
Tracer.prototype.resize.call(this);
this.refresh();
};
// Override
Array2DTracer.prototype.clear = function () {
Tracer.prototype.clear.call(this);
Array2D.clearTableColor();
};
Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
constructor: Array2DTracer,
init: function () {
$table = $('<div class="mtbl-table">');
$module_container.append($table);
},
resize: function () {
Tracer.prototype.resize.call(this);
// Override
Array2DTracer.prototype._setData = function (D) {
this.D = D;
this.viewX = this.viewY = 0;
this.paddingH = 6;
this.paddingV = 3;
this.fontSize = 16;
this.refresh();
},
clear: function () {
Tracer.prototype.clear.call(this);
if (Tracer.prototype._setData.call(this, arguments)) {
$('.mtbl-row').each(function (i) {
$(this).children().each(function (j) {
$(this).text(D[i][j]);
this.clearColor();
},
_setData: function (D) {
this.D = D;
this.viewX = this.viewY = 0;
this.paddingH = 6;
this.paddingV = 3;
this.fontSize = 16;
if (Tracer.prototype._setData.call(this, arguments)) {
$('.mtbl-row').each(function (i) {
$(this).children().each(function (j) {
$(this).text(D[i][j]);
});
});
});
return true;
}
$table.empty();
for (var i = 0; i < D.length; i++) {
var $row = $('<div class="mtbl-row">');
$table.append($row);
for (var j = 0; j < D[i].length; j++) {
var $cell = $('<div class="mtbl-cell">')
.css(this.getCellCss())
.text(D[i][j]);
$row.append($cell);
return true;
}
}
this.resize();
return false;
};
Array2DTracer.prototype._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);
};
Array2DTracer.prototype._select = function (sx, sy, ex, ey) {
this.pushSelectingStep('select', null, arguments);
};
Array2DTracer.prototype._selectRow = function (x, sy, ey) {
this.pushSelectingStep('select', 'row', arguments);
};
Array2DTracer.prototype._selectCol = function (y, sx, ex) {
this.pushSelectingStep('select', 'col', arguments);
};
Array2DTracer.prototype._selectSet = function (coords) {
this.pushSelectingStep('select', 'set', arguments);
};
Array2DTracer.prototype._deselect = function (sx, sy, ex, ey) {
this.pushSelectingStep('deselect', null, arguments);
};
Array2DTracer.prototype._deselectRow = function (x, sy, ey) {
this.pushSelectingStep('deselect', 'row', arguments);
};
Array2DTracer.prototype._deselectCol = function (y, sx, ex) {
this.pushSelectingStep('deselect', 'col', arguments);
};
Array2DTracer.prototype._deselectSet = function (coords) {
this.pushSelectingStep('deselect', 'set', arguments);
};
$table.empty();
for (var i = 0; i < D.length; i++) {
var $row = $('<div class="mtbl-row">');
$table.append($row);
for (var j = 0; j < D[i].length; j++) {
var $cell = $('<div class="mtbl-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) {
var tracer = this;
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;
tracer.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 +293,5 @@ var Array2D = {
return a - b;
});
});
},
initTable: function () {
$table = $('<div class="mtbl-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
......@@ -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
......@@ -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($('<span>').append(message + '<br/>'));
},
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($('<span>').append(message + '<br/>'));
};
var scrollToEnd = function (duration) {
$('#tab_trace').animate({scrollTop: $('#tab_trace')[0].scrollHeight}, duration);
};
\ No newline at end of file
function WeightedDirectedGraphTracer(module) {
if (DirectedGraphTracer.call(this, module || WeightedDirectedGraphTracer)) {
WeightedDirectedGraph.initWeightedGraph();
WeightedDirectedGraphTracer.prototype.init.call(this);
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
WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTracer.prototype), {
constructor: WeightedDirectedGraphTracer,
init: function () {
var tracer = this;
s.settings({
edgeLabelSize: 'proportional',
defaultEdgeLabelSize: 20,
edgeLabelSizePowRatio: 0.8
});
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]
});
}
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);
}
}
graph.read({
nodes: nodes,
edges: edges
});
s.camera.goTo({
x: 0,
y: 0,
angle: 0,
ratio: 1
});
this.refresh();
},
clear: function () {
DirectedGraphTracer.prototype.clear.call(this);
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);
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]
});
}
}
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);
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);
}
return G;
},
clearWeights: function () {
graph.nodes().forEach(function (node) {
......@@ -191,22 +182,6 @@ var WeightedDirectedGraph = {
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') || '',
......@@ -232,4 +207,26 @@ var WeightedDirectedGraph = {
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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
新手
引导
客服 返回
顶部