提交 5442583e 编写于 作者: J Jason Park

allow multiple tracers

上级 f6474a08
......@@ -150,6 +150,7 @@ section {
left: 0;
right: 0;
overflow: hidden;
border: none;
}
.tab_container {
......
......@@ -107,6 +107,7 @@
<script src="js/sigma/sigma.min.js"></script>
<script src="js/sigma/plugins/sigma.plugins.dragNodes.min.js"></script>
<script src="js/ace/ace.js"></script>
<script src="js/module/tracer_manager.js"></script>
<script src="js/module/tracer.js"></script>
<script src="js/module/directed_graph.js"></script>
<script src="js/module/undirected_graph.js"></script>
......
......@@ -12,7 +12,7 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
constructor: Array2DTracer,
init: function () {
$table = $('<div class="mtbl-table">');
$module_container.append($table);
this.$container.append($table);
},
resize: function () {
Tracer.prototype.resize.call(this);
......
var s = null, graph = null, sigmaCanvas = null;
function DirectedGraphTracer(module) {
if (Tracer.call(this, module || DirectedGraphTracer)) {
DirectedGraphTracer.prototype.init.call(this);
......@@ -13,14 +11,9 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
init: function () {
var tracer = this;
if (sigmaCanvas == null) {
sigmaCanvas = $.extend(true, {}, sigma.canvas);
} else {
sigma.canvas = $.extend(true, {}, sigmaCanvas);
}
s = new sigma({
this.s = this.capsule.s = new sigma({
renderer: {
container: $module_container[0],
container: this.$container[0],
type: 'canvas'
},
settings: {
......@@ -36,25 +29,26 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
minNodeSize: .5,
maxNodeSize: 12,
labelSize: 'proportional',
labelSizeRatio: 1.3
labelSizeRatio: 1.3,
funcLabelsDef: function (node, context, settings) {
tracer.drawLabel(node, context, settings);
},
funcHoversDef: function (node, context, settings, next) {
tracer.drawOnHover(node, context, settings, next);
},
funcEdgesArrow: function (edge, source, target, context, settings) {
var color = tracer.getColor(edge, source, target, settings);
tracer.drawArrow(edge, source, target, color, context, settings);
}
}
});
graph = s.graph;
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 = tracer.getColor(edge, source, target, settings);
tracer.drawArrow(edge, source, target, color, context, settings);
};
sigma.plugins.dragNodes(s, s.renderers[0]);
sigma.plugins.dragNodes(this.s, this.s.renderers[0]);
this.graph = this.capsule.graph = this.s.graph;
},
resize: function () {
Tracer.prototype.resize.call(this);
this.s.renderers[0].resize();
this.refresh();
},
clear: function () {
......@@ -82,7 +76,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
if (this._setData(G, root)) return true;
var place = function (node, x, y) {
var temp = graph.nodes(tracer.n(node));
var temp = tracer.graph.nodes(tracer.n(node));
temp.x = x;
temp.y = y;
};
......@@ -107,7 +101,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
_setData: function (G) {
if (Tracer.prototype._setData.call(this, arguments)) return true;
graph.clear();
this.graph.clear();
var nodes = [];
var edges = [];
var unitAngle = 2 * Math.PI / G.length;
......@@ -135,11 +129,11 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
}
}
graph.read({
this.graph.read({
nodes: nodes,
edges: edges
});
s.camera.goTo({
this.s.camera.goTo({
x: 0,
y: 0,
angle: 0,
......@@ -160,14 +154,14 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
case 'visit':
case 'leave':
var visit = step.type == 'visit';
var targetNode = graph.nodes(this.n(step.target));
var targetNode = this.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);
var edge = this.graph.edges(edgeId);
edge.color = color;
graph.dropEdge(edgeId).addEdge(edge);
this.graph.dropEdge(edgeId).addEdge(edge);
}
var source = step.source;
if (source === undefined) source = '';
......@@ -178,7 +172,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
refresh: function () {
Tracer.prototype.refresh.call(this);
s.refresh();
this.s.refresh();
},
prevStep: function () {
this.clear();
......@@ -202,10 +196,10 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
clearGraphColor: function () {
var tracer = this;
graph.nodes().forEach(function (node) {
this.graph.nodes().forEach(function (node) {
node.color = tracer.color.default;
});
graph.edges().forEach(function (edge) {
this.graph.edges().forEach(function (edge) {
edge.color = tracer.color.default;
});
},
......@@ -308,17 +302,17 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
context.setLineDash([5, 5]);
var nodeIdx = node.id.substring(1);
graph.edges().forEach(function (edge) {
this.graph.edges().forEach(function (edge) {
var ends = edge.id.substring(1).split("_");
if (ends[0] == nodeIdx) {
var color = '#0ff';
var source = node;
var target = graph.nodes('n' + ends[1]);
var target = tracer.graph.nodes('n' + ends[1]);
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 source = tracer.graph.nodes('n' + ends[0]);
var target = node;
tracer.drawArrow(edge, source, target, color, context, settings);
if (next) next(edge, source, target, color, context, settings);
......@@ -342,4 +336,29 @@ var DirectedGraph = {
}
return G;
}
};
sigma.canvas.labels.def = function (node, context, settings) {
var func = settings('funcLabelsDef');
if (func) {
func(node, context, settings);
}
};
sigma.canvas.hovers.def = function (node, context, settings) {
var func = settings('funcHoversDef');
if (func) {
func(node, context, settings);
}
};
sigma.canvas.edges.def = function (edge, source, target, context, settings) {
var func = settings('funcEdgesDef');
if (func) {
func(edge, source, target, context, settings);
}
};
sigma.canvas.edges.arrow = function (edge, source, target, context, settings) {
var func = settings('funcEdgesArrow');
if (func) {
func(edge, source, target, context, settings);
}
};
\ No newline at end of file
var timer = null;
var lastModule = null, lastData = null;
var stepLimit = 1e6;
var Tracer = function (module) {
this.module = module || Tracer;
this.traces = [];
this.pause = false;
this.traceOptions = null;
this.traceIndex = -1;
this.stepCnt = 0;
this.capsule = tm.allocate(this);
var moduleChanged = lastModule != module;
if (moduleChanged) $module_container.empty();
return moduleChanged;
$.extend(this, this.capsule);
return this.new;
};
Tracer.prototype = {
......@@ -29,8 +27,8 @@ Tracer.prototype = {
},
_setData: function (arguments) {
var data = JSON.stringify(arguments);
if (lastModule == this.module && lastData == data) return true;
lastData = data;
if (!this.new && this.lastData == data) return true;
this.capsule.lastData = data;
return false;
},
pushStep: function (step, delay) {
......@@ -66,17 +64,14 @@ Tracer.prototype = {
this.traceIndex = -1;
this.resumeStep();
},
isPause: function () {
return this.pause;
},
pauseStep: function () {
if (this.traceIndex < 0) return;
this.pause = true;
tm.pause = true;
if (timer) clearTimeout(timer);
$('#btn_pause').addClass('active');
},
resumeStep: function () {
this.pause = false;
tm.pause = false;
this.step(this.traceIndex + 1);
$('#btn_pause').removeClass('active');
},
......@@ -112,7 +107,7 @@ Tracer.prototype = {
this.refresh();
this.scrollToEnd(Math.min(50, this.traceOptions.interval));
}
if (this.pause) return;
if (tm.pause) return;
timer = setTimeout(function () {
tracer.step(i + 1, options);
}, sleepDuration || this.traceOptions.interval);
......
var TracerManager = function () {
this.pause = false;
this.capsules = [];
};
TracerManager.prototype = {
add: function (tracer) {
var $container = $('<section class="module_wrapper">');
$module_container.append($container);
var capsule = {
module: tracer.module,
tracer: tracer,
allocated: true,
$container: $container,
new: true
};
this.capsules.push(capsule);
return capsule;
},
allocate: function (newTracer) {
var selectedCapsule = null;
$.each(this.capsules, function (i, capsule) {
if (!capsule.allocated && capsule.module == newTracer.module) {
capsule.tracer = newTracer;
capsule.allocated = true;
capsule.new = false;
selectedCapsule = capsule;
return false;
}
});
console.log('allocated ' + selectedCapsule);
if (selectedCapsule == null) {
selectedCapsule = this.add(newTracer);
}
return selectedCapsule;
},
deallocateAll: function () {
$.each(this.capsules, function (i, capsule) {
capsule.allocated = false;
});
},
removeUnallocated: function () {
var changed = false;
this.capsules = $.grep(this.capsules, function (capsule) {
var removed = !capsule.allocated;
if (capsule.new || removed) changed = true;
if (removed) {
capsule.$container.remove();
}
return !removed;
});
if (changed) this.place();
},
place: function () {
var capsules = this.capsules;
$.each(capsules, function (i, capsule) {
var width = $module_container.width() / capsules.length;
var height = $module_container.height();
var left = width * i;
capsule.$container.css({
top: 0,
left: left,
width: width,
height: height
});
capsule.tracer.resize();
});
},
command: function () {
var args = Array.prototype.slice.call(arguments);
var functionName = args.shift();
$.each(this.capsules, function (i, capsule) {
if (capsule.allocated) {
capsule.tracer.module.prototype[functionName].apply(capsule.tracer, args);
}
});
},
isPause: function () {
return this.pause;
}
};
\ No newline at end of file
......@@ -11,18 +11,18 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
init: function () {
var tracer = this;
s.settings({
defaultEdgeType: 'def'
this.s.settings({
defaultEdgeType: 'def',
funcEdgesDef: function (edge, source, target, context, settings) {
var color = tracer.getColor(edge, source, target, settings);
tracer.drawEdge(edge, source, target, color, context, settings);
}
});
sigma.canvas.edges.def = function (edge, source, target, context, settings) {
var color = tracer.getColor(edge, source, target, settings);
tracer.drawEdge(edge, source, target, color, context, settings);
};
},
_setData: function (G) {
if (Tracer.prototype._setData.call(this, arguments)) return true;
graph.clear();
this.graph.clear();
var nodes = [];
var edges = [];
var unitAngle = 2 * Math.PI / G.length;
......@@ -52,11 +52,11 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
}
}
graph.read({
this.graph.read({
nodes: nodes,
edges: edges
});
s.camera.goTo({
this.s.camera.goTo({
x: 0,
y: 0,
angle: 0,
......@@ -79,17 +79,17 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
context.setLineDash([5, 5]);
var nodeIdx = node.id.substring(1);
graph.edges().forEach(function (edge) {
this.graph.edges().forEach(function (edge) {
var ends = edge.id.substring(1).split("_");
if (ends[0] == nodeIdx) {
var color = '#0ff';
var source = node;
var target = graph.nodes('n' + ends[1]);
var target = tracer.graph.nodes('n' + ends[1]);
tracer.drawEdge(edge, source, target, color, context, settings);
if (next) next(edge, source, target, color, context, settings);
} else if (ends[1] == nodeIdx) {
var color = '#0ff';
var source = graph.nodes('n' + ends[0]);
var source = tracer.graph.nodes('n' + ends[0]);
var target = node;
tracer.drawEdge(edge, source, target, color, context, settings);
if (next) next(edge, source, target, color, context, settings);
......
......@@ -11,23 +11,23 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
init: function () {
var tracer = this;
s.settings({
this.s.settings({
edgeLabelSize: 'proportional',
defaultEdgeLabelSize: 20,
edgeLabelSizePowRatio: 0.8
edgeLabelSizePowRatio: 0.8,
funcLabelsDef: function (node, context, settings) {
tracer.drawNodeWeight(node, context, settings);
tracer.drawLabel(node, context, settings);
},
funcHoversDef: function (node, context, settings) {
tracer.drawOnHover(node, context, settings, tracer.drawEdgeWeight);
},
funcEdgesArrow: 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.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);
......@@ -37,7 +37,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
_setData: function (G) {
if (Tracer.prototype._setData.call(this, arguments)) return true;
graph.clear();
this.graph.clear();
var nodes = [];
var edges = [];
var unitAngle = 2 * Math.PI / G.length;
......@@ -67,11 +67,11 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
}
}
graph.read({
this.graph.read({
nodes: nodes,
edges: edges
});
s.camera.goTo({
this.s.camera.goTo({
x: 0,
y: 0,
angle: 0,
......@@ -93,21 +93,21 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
processStep: function (step, options) {
switch (step.type) {
case 'weight':
var targetNode = graph.nodes(this.n(step.target));
var targetNode = this.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 targetNode = this.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);
var edge = this.graph.edges(edgeId);
edge.color = color;
graph.dropEdge(edgeId).addEdge(edge);
this.graph.dropEdge(edgeId).addEdge(edge);
}
var source = step.source;
if (source === undefined) source = '';
......@@ -118,7 +118,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
}
},
clearWeights: function () {
graph.nodes().forEach(function (node) {
this.graph.nodes().forEach(function (node) {
node.weight = 0;
});
},
......
......@@ -11,19 +11,19 @@ WeightedUndirectedGraphTracer.prototype = $.extend(true, Object.create(WeightedD
init: function () {
var tracer = this;
s.settings({
defaultEdgeType: 'def'
this.s.settings({
defaultEdgeType: 'def',
funcEdgesDef: function (edge, source, target, context, settings) {
var color = tracer.getColor(edge, source, target, settings);
tracer.drawEdge(edge, source, target, color, context, settings);
tracer.drawEdgeWeight(edge, source, target, color, context, settings);
}
});
sigma.canvas.edges.def = function (edge, source, target, context, settings) {
var color = tracer.getColor(edge, source, target, settings);
tracer.drawEdge(edge, source, target, color, context, settings);
tracer.drawEdgeWeight(edge, source, target, color, context, settings);
};
},
_setData: function (G) {
if (Tracer.prototype._setData.call(this, arguments)) return true;
graph.clear();
this.graph.clear();
var nodes = [];
var edges = [];
var unitAngle = 2 * Math.PI / G.length;
......@@ -55,11 +55,11 @@ WeightedUndirectedGraphTracer.prototype = $.extend(true, Object.create(WeightedD
}
}
graph.read({
this.graph.read({
nodes: nodes,
edges: edges
});
s.camera.goTo({
this.s.camera.goTo({
x: 0,
y: 0,
angle: 0,
......@@ -79,8 +79,6 @@ WeightedUndirectedGraphTracer.prototype = $.extend(true, Object.create(WeightedD
source = target;
target = temp;
}
console.log(source);
console.log(target);
WeightedDirectedGraphTracer.prototype.drawEdgeWeight.call(this, edge, source, target, color, context, settings);
}
});
......
......@@ -8,8 +8,9 @@ $(document).on('click', 'a', function (e) {
}
});
var tm = new TracerManager();
var $module_container = $('.module_container');
var _tracer = new Tracer();
var initEditor = function (id) {
var editor = ace.edit(id);
editor.setTheme("ace/theme/tomorrow_night_eighties");
......@@ -24,12 +25,14 @@ dataEditor.on('change', function () {
var data = dataEditor.getValue();
if (lastDir) cachedFile[lastDir].data = data;
try {
tm.deallocateAll();
eval(data);
lastModule = tracer && tracer.module;
_tracer = tracer;
} catch (err) {
console.error(err);
} finally {
tm.command('reset');
tm.removeUnallocated();
}
_tracer.reset();
});
codeEditor.on('change', function () {
var code = codeEditor.getValue();
......@@ -40,7 +43,6 @@ var cachedFile = {};
var loading = false;
var loadFile = function (category, algorithm, file, explanation) {
if (checkLoading()) return;
lastData = null;
$('#explanation').html(explanation);
var dir = lastDir = './algorithm/' + category + '/' + algorithm + '/' + file + '/';
......@@ -178,7 +180,7 @@ $('#navigation').click(function () {
$sidemenu.css('right', 0);
$workspace.css('left', 0);
}
_tracer.resize();
tm.command('resize');
});
var showErrorToast = function (err) {
......@@ -193,31 +195,32 @@ var showErrorToast = function (err) {
$('#btn_run').click(function () {
try {
tm.deallocateAll();
eval(dataEditor.getValue());
lastModule = tracer && tracer.module;
_tracer = tracer;
_tracer.reset();
tm.command('reset');
eval(codeEditor.getValue());
_tracer.visualize();
tm.command('visualize');
} catch (err) {
console.error(err);
showErrorToast(err);
} finally {
tm.removeUnallocated();
}
});
$('#btn_pause').click(function () {
if (_tracer.isPause()) {
_tracer.resumeStep();
if (tm.isPause()) {
tm.command('resumeStep');
} else {
_tracer.pauseStep();
tm.command('pauseStep');
}
});
$('#btn_prev').click(function () {
_tracer.pauseStep();
_tracer.prevStep();
tm.command('pauseStep');
tm.command('prevStep');
});
$('#btn_next').click(function () {
_tracer.pauseStep();
_tracer.nextStep();
tm.command('pauseStep');
tm.command('nextStep');
});
$('#btn_desc').click(function () {
......@@ -233,7 +236,9 @@ $('#btn_trace').click(function () {
$(this).addClass('active');
});
$(window).resize(_tracer.resize);
$(window).resize(function () {
tm.command('resize');
});
var dividers = [
['v', $('.sidemenu'), $('.workspace')],
......@@ -251,6 +256,7 @@ for (var i = 0; i < dividers.length; i++) {
var thickness = 5;
var $divider = $('<div class="divider">');
var dragging = false;
if (vertical) {
$divider.addClass('vertical');
var _left = -thickness / 2;
......@@ -260,7 +266,7 @@ for (var i = 0; i < dividers.length; i++) {
left: _left,
width: thickness
});
var x, dragging = false;
var x;
$divider.mousedown(function (e) {
x = e.pageX;
dragging = true;
......@@ -273,7 +279,7 @@ for (var i = 0; i < dividers.length; i++) {
$first.css('right', (100 - percent) + '%');
$second.css('left', percent + '%');
x = e.pageX;
_tracer.resize();
tm.command('resize');
}
});
$(document).mouseup(function (e) {
......@@ -288,7 +294,7 @@ for (var i = 0; i < dividers.length; i++) {
left: 0,
right: 0
});
var y, dragging = false;
var y;
$divider.mousedown(function (e) {
y = e.pageY;
dragging = true;
......@@ -301,7 +307,7 @@ for (var i = 0; i < dividers.length; i++) {
$first.css('bottom', (100 - percent) + '%');
$second.css('top', percent + '%');
y = e.pageY;
_tracer.resize();
tm.command('resize');
}
});
$(document).mouseup(function (e) {
......@@ -314,14 +320,14 @@ for (var i = 0; i < dividers.length; i++) {
}
$module_container.mousedown(function (e) {
_tracer.mousedown(e);
tm.command('mousedown', e);
});
$module_container.mousemove(function (e) {
_tracer.mousemove(e);
tm.command('mousemove', e);
});
$(document).mouseup(function (e) {
_tracer.mouseup(e);
tm.command('mouseup', e);
});
$module_container.bind('DOMMouseScroll mousewheel', function (e) {
_tracer.mousewheel(e);
tm.command('mousewheel', e);
});
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册