提交 3da7ea7e 编写于 作者: N nem035

Finished converting to es6

上级 3c00822c
.idea
.DS_Store
\ No newline at end of file
.DS_Store
node_modules
_*
......@@ -103,7 +103,7 @@ nav h3 {
padding: 0 4px;
}
#navigation span:empty + .nav-arrow {
#category:empty + .nav-arrow {
display: none;
}
......@@ -294,8 +294,7 @@ section {
}
.files_bar > .wrapper.shadow-left.shadow-right {
box-shadow: inset 16px 0 16px -16px rgba(0, 0, 0, .6),
inset -16px 0 16px -16px rgba(0, 0, 0, .6);
box-shadow: inset 16px 0 16px -16px rgba(0, 0, 0, .6), inset -16px 0 16px -16px rgba(0, 0, 0, .6);
}
.explanation_container {
......@@ -430,4 +429,58 @@ pre {
.mtbl-col.notified {
background: #f00;
}
#loading-slider {
position: absolute;
width: 100%;
height: 2px;
}
#loading-slider.loaded {
visibility: hidden;
}
.line {
position: absolute;
background: #4a8df8;
width: 100%;
left: 0;
right: 0;
top: 0;
height: 3px;
}
.break {
position: absolute;
background: #222;
width: 6px;
height: 2px;
}
.dot1 {
animation: loading 2s infinite;
}
.dot2 {
animation: loading 2s 0.5s infinite;
}
.dot3 {
animation: loading 2s 1s infinite;
}
@keyframes loading {
from {
left: 0;
}
to {
left: 100%;
}
}
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
\ No newline at end of file
'use strict';
import path from 'path';
import gulp from 'gulp';
import uglify from 'gulp-uglify';
import cleanCSS from 'gulp-clean-css';
import autoprefixer from 'gulp-autoprefixer';
import concat from 'gulp-concat';
import header from 'gulp-header';
import babel from 'gulp-babel';
import gutil from 'gulp-util';
import sourcemaps from 'gulp-sourcemaps';
import connect from 'gulp-connect';
import browserify from 'browserify';
import babelify from 'babelify';
import source from 'vinyl-source-stream';
import buffer from 'vinyl-buffer';
import pkg from './package.json';
const appName = 'algorithm_visualizer';
const appEntryPoint = './js/index.js';
const outputPaths = {
javascript: './public',
css: './public',
sourceMaps: './'
};
const banner = [
'/**',
' * <%= pkg.name %> - <%= pkg.description %>',
' * @version v<%= pkg.version %>',
' * @author <%= pkg.author %>',
' * @link <%= pkg.homepage %>',
' * @license <%= pkg.license %>',
' */',
''
].join('\n');
// build directories
const cssDir = path.join(__dirname, 'css', '**', '*.css');
const jsDir = path.join(__dirname, 'js', '**', '*.js');
// CSS
gulp.task('minify-css', () => {
gutil.log('\n\nBuild CSS Paths: \n', cssDir, '\n\n');
return gulp.src(cssDir)
.pipe(autoprefixer())
.pipe(cleanCSS({
compatibility: 'ie8'
}))
.pipe(concat(`${appName}.min.css`))
.pipe(header(banner, {
pkg
}))
.pipe(gulp.dest(outputPaths.css))
.pipe(connect.reload());
});
gulp.task('build-css', () => {
gutil.log('\n\nBuild CSS Paths: \n', cssDir, '\n\n');
return gulp.src(cssDir)
.pipe(autoprefixer())
.pipe(concat(`${appName}.css`))
.pipe(header(banner, {
pkg
}))
.pipe(gulp.dest(outputPaths.css))
.pipe(connect.reload());
});
// JS
gulp.task('minify-js', () => {
gutil.log('\n\nBuild JS Paths: \n', jsDir, '\n\n');
return browserify({
entries: './js/index.js',
debug: true
})
.transform('babelify', {
presets: ['es2015']
})
.bundle()
.pipe(source(`${appName}.min.js`))
.pipe(header(banner, {
pkg
}))
.pipe(buffer())
.pipe(sourcemaps.init())
.pipe(uglify())
.pipe(sourcemaps.write(outputPaths.sourceMaps))
.pipe(gulp.dest(outputPaths.javascript))
.pipe(connect.reload());
});
gulp.task('build-js', () => {
gutil.log('\n\nBuild JS Paths: \n', jsDir, '\n\n');
return browserify({
entries: './js/index.js',
debug: true
})
.transform('babelify', {
presets: ['es2015']
})
.bundle()
.pipe(source(`${appName}.js`))
.pipe(header(banner, {
pkg
}))
.pipe(buffer())
.pipe(sourcemaps.init())
.pipe(sourcemaps.write(outputPaths.sourceMaps))
.pipe(gulp.dest(outputPaths.javascript))
.pipe(connect.reload());
});
// Build
gulp.task('compile-css', ['build-css', 'minify-css']);
gulp.task('compile-js', ['build-js', 'minify-js']);
gulp.task('build', ['compile-css', 'compile-js']);
// Server
gulp.task('connect', function() {
connect.server({
livereload: true
});
});
// Watch
gulp.task('watch', ['build'], function() {
gulp.watch(jsDir, ['compile-js']);
gulp.watch(cssDir, ['compile-css']);
});
// Default
gulp.task('default', ['connect', 'watch']);
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="description" content="Tool for visualizing algorithms."/>
<meta property="og:title" content="Algorithm Visualizer"/>
<meta property="og:description" content="Tool for visualizing algorithms."/>
<meta property="og:image" content="img/image.png"/>
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon"/>
<meta name="description" content="Tool for visualizing algorithms." />
<meta property="og:title" content="Algorithm Visualizer" />
<meta property="og:description" content="Tool for visualizing algorithms." />
<meta property="og:image" content="img/image.png" />
<link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon" />
<title>Algorithm Visualizer</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/gh-fork-ribbon.css"/>
<link rel="stylesheet" href="css/stylesheet.css">
<link rel="stylesheet" href="public/algorithm_visualizer.min.css">
</head>
<body>
<nav>
<button id="navigation">
<div id="loading-slider">
<div class="line"></div>
<div class="break dot1"></div>
<div class="break dot2"></div>
<div class="break dot3"></div>
</div>
<nav>
<button id="navigation">
<h3>
Algorithm Visualizer
<i class="fa fa-angle-right nav-arrow" aria-hidden="true"></i>
......@@ -25,118 +31,120 @@
<i class="fa fa-caret-up nav-dropdown" aria-hidden="true"></i>
</h3>
</button>
<div class="buttons">
<div class="btn" id="btn_share">
<div class="wrapper">
<i class="fa fa-share" aria-hidden="true"></i> Share <input type="text" class="collapse" id="shared">
<div class="buttons">
<div class="btn" id="btn_share">
<div class="wrapper">
<i class="fa fa-share" aria-hidden="true"></i> Share <input type="text" class="collapse" id="shared">
</div>
</div>
</div>
<button id="btn_run"><i class="fa fa-play" aria-hidden="true"></i> Run</button>
<button id="btn_prev"><i class="fa fa-chevron-left" aria-hidden="true"></i> Prev</button>
<button id="btn_pause"><i class="fa fa-pause" aria-hidden="true"></i> Pause</button>
<button id="btn_next">Next <i class="fa fa-chevron-right" aria-hidden="true"></i></button>
<div class="btn">
<div class="wrapper">
Interval: <input type="text" value="0.5" id="interval"> sec
<button id="btn_run">
<i class="fa fa-play" aria-hidden="true"></i>
<span class="btn-text">Run</span>
</button>
<button id="btn_prev">
<i class="fa fa-chevron-left" aria-hidden="true"></i>
<span class="btn-text">Prev</span>
</button>
<button id="btn_pause">
<i class="fa fa-pause" aria-hidden="true"></i>
<span class="btn-text">Pause</span>
</button>
<button id="btn_next">
<span class="btn-text">Next</span>
<i class="fa fa-chevron-right" aria-hidden="true"></i>
</button>
<div class="btn">
<div class="wrapper">
Interval: <input type="number" value="" id="interval"> sec
</div>
</div>
</div>
</div>
</nav>
<section class="sidemenu active">
<div id="list">
</div>
<div id="footer">
<button id="scratch-paper"><i class="fa fa-code"></i> Scratch Paper</button>
<a href="https://github.com/parkjs814/AlgorithmVisualizer/wiki">
<button><i class="fa fa-book"></i> Documentation</button>
</a>
<button class="category" id="powered-by"><i class="fa fa-github"></i> Powered by ...</button>
<div id="powered-by-list">
<a href="https://github.com/jquery/jquery">
<button class="indent collapse">jquery/jquery</button>
</a>
<a href="https://github.com/ajaxorg/ace">
<button class="indent collapse">ajaxorg/ace</button>
</a>
<a href="https://github.com/jacomyal/sigma.js">
<button class="indent collapse">jacomyal/sigma.js</button>
</a>
<a href="https://github.com/FortAwesome/Font-Awesome">
<button class="indent collapse">FortAwesome/Font-Awesome</button>
</a>
<a href="https://github.com/simonwhitaker/github-fork-ribbon-css">
<button class="indent collapse">simonwhitaker/github-fork-ribbon-css</button>
</nav>
<section class="sidemenu active">
<div id="list">
</div>
<div id="footer">
<button id="scratch-paper"><i class="fa fa-code"></i> Scratch Paper</button>
<a href="https://github.com/parkjs814/AlgorithmVisualizer/wiki">
<button><i class="fa fa-book"></i> Documentation</button>
</a>
<button class="category" id="powered-by"><i class="fa fa-github"></i> Powered by ...</button>
<div id="powered-by-list">
<a href="https://github.com/jquery/jquery">
<button class="indent collapse">jquery/jquery</button>
</a>
<a href="https://github.com/ajaxorg/ace">
<button class="indent collapse">ajaxorg/ace</button>
</a>
<a href="https://github.com/jacomyal/sigma.js">
<button class="indent collapse">jacomyal/sigma.js</button>
</a>
<a href="https://github.com/FortAwesome/Font-Awesome">
<button class="indent collapse">FortAwesome/Font-Awesome</button>
</a>
<a href="https://github.com/simonwhitaker/github-fork-ribbon-css">
<button class="indent collapse">simonwhitaker/github-fork-ribbon-css</button>
</a>
</div>
</div>
</div>
<a class="github-fork-ribbon left-bottom" href="http://github.com/parkjs814/AlgorithmVisualizer"
title="Fork me on GitHub">Fork me on GitHub</a>
</section>
<div class="workspace">
<div class="viewer_container">
<section class="tab_bar">
<button class="active" id="btn_desc">Description</button>
<button id="btn_trace">Trace</button>
</section>
<section class="tab_container">
<div class="tab active" id="tab_desc">
<div class="wrapper">
<a class="github-fork-ribbon left-bottom" href="http://github.com/parkjs814/AlgorithmVisualizer" title="Fork me on GitHub">Fork me on GitHub</a>
</section>
<div class="workspace">
<div class="viewer_container">
<section class="tab_bar">
<button class="active" id="btn_desc">Description</button>
<button id="btn_trace">Trace</button>
</section>
<section class="tab_container">
<div class="tab active" id="tab_desc">
<div class="wrapper">
</div>
</div>
</div>
<div class="tab module_container" id="tab_module">
</div>
</section>
<div class="tab module_container" id="tab_module">
</div>
</section>
</div>
<div class="editor_container">
<section class="files_bar">
<button class="btn-left"><i class="fa fa-angle-left" aria-hidden="true"></i></button>
<div class="wrapper"></div>
<button class="btn-right"><i class="fa fa-angle-right" aria-hidden="true"></i></button>
</section>
<section class="explanation_container">
<span id="explanation"></span>
</section>
<section class="data_container">
<pre id="data"></pre>
</section>
<section class="code_container">
<pre id="code"></pre>
</section>
</div>
</div>
<div class="editor_container">
<section class="files_bar">
<button class="btn-left"><i class="fa fa-angle-left" aria-hidden="true"></i></button>
<div class="wrapper"></div>
<button class="btn-right"><i class="fa fa-angle-right" aria-hidden="true"></i></button>
</section>
<section class="explanation_container">
<span id="explanation"></span>
</section>
<section class="data_container">
<pre id="data"></pre>
</section>
<section class="code_container">
<pre id="code"></pre>
</section>
<div class="toast_container">
</div>
</div>
<div class="toast_container">
</div>
<script src="js/lib/jquery-2.2.3.min.js"></script>
<script src="js/lib/sigma/sigma.min.js"></script>
<script src="js/lib/sigma/plugins/sigma.plugins.dragNodes.min.js"></script>
<script src="js/lib/ace/ace.js"></script>
<script src="js/lib/ace/ext-language_tools.js"></script>
<script src="js/lib/Chart-2.1.3.min.js"></script>
<script src="js/tracer_manager.js"></script>
<script src="js/module/tracer.js"></script>
<script src="js/module/log_tracer.js"></script>
<script src="js/module/array2d.js"></script>
<script src="js/module/array1d.js"></script>
<script src="js/module/directed_graph.js"></script>
<script src="js/module/undirected_graph.js"></script>
<script src="js/module/weighted_directed_graph.js"></script>
<script src="js/module/weighted_undirected_graph.js"></script>
<script src="js/module/chart.js"></script>
<script src="js/script.js"></script>
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
<script src="public/lib/jquery-2.2.3.min.js"></script>
<script src="public/lib/sigma/sigma.min.js"></script>
<script src="public/lib/sigma/plugins/sigma.plugins.dragNodes.min.js"></script>
<script src="public/lib/ace/ace.js"></script>
<script src="public/lib/ace/ext-language_tools.js"></script>
<script src="public/lib/Chart-2.1.3.min.js"></script>
<script src="public/algorithm_visualizer.min.js"></script>
<script>
(function(i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-78128848-1', 'auto');
ga('send', 'pageview');
</script>
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', 'https://www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-78128848-1', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>
\ No newline at end of file
'use strict';
const {
extend
} = $;
const cache = {
lastFileUsed: '',
files: {}
};
const assertFileName = (name) => {
if (!name) {
throw 'Missing file name';
}
};
/**
* Global application cache
*/
module.exports = {
getCachedFile(name) {
assertFileName(name);
return cache.files[name];
},
updateCachedFile(name, updates) {
assertFileName(name);
if (!cache.files[name]) {
cache.files[name] = {};
}
extend(cache.files[name], updates);
},
getLastFileUsed() {
return cache.lastFileUsed;
},
setLastFileUsed(file) {
cache.lastFileUsed = file;
}
};
\ No newline at end of file
'use strict';
const Editor = require('../editor');
const TracerManager = require('../tracer_manager');
const DOM = require('../dom/setup');
const {
getFileDir
} = require('../utils');
const Cache = require('./cache');
const {
each
} = $;
const state = {
isLoading: null,
editor: null,
tracerManager: null,
categories: null
};
const initState = (tracerManager) => {
state.isLoading = false;
state.editor = new Editor(tracerManager);
state.tracerManager = tracerManager;
state.categories = {};
};
/**
* Global application singleton.
*/
const App = function() {
this.getIsLoading = () => {
return state.isLoading;
};
this.setIsLoading = (loading) => {
state.isLoading = loading;
if (loading) {
$('#loading-slider').removeClass('loaded');
} else {
$('#loading-slider').addClass('loaded');
}
};
this.getEditor = () => {
return state.editor;
};
this.getCategories = () => {
return state.categories;
};
this.getCategory = (name) => {
return state.categories[name];
};
this.setCategories = (categories) => {
state.categories = categories;
};
this.updateCategory = (name, updates) => {
$.extend(state.categories[name], updates);
};
this.getTracerManager = () => {
return state.tracerManager;
};
const tracerManager = TracerManager.init();
initState(tracerManager);
DOM.setup(tracerManager);
};
App.prototype = Cache;
module.exports = App;
\ No newline at end of file
'use strict';
/**
* This is the main application instance.
* Gets populated on page load.
*/
module.exports = {};
\ No newline at end of file
'use strict';
const showAlgorithm = require('./show_algorithm');
const showCategories = require('./show_categories');
const showDescription = require('./show_description');
const showFiles = require('./show_files');
const showFirstAlgorithm = require('./show_first_algorithm');
module.exports = {
showAlgorithm,
showCategories,
showDescription,
showFiles,
showFirstAlgorithm
};
\ No newline at end of file
const setupDividers = require('./setup_dividers');
const setupDocument = require('./setup_document');
const setupFilesBar = require('./setup_files_bar');
const setupInterval = require('./setup_interval');
const setupModuleContainer = require('./setup_module_container');
const setupPoweredBy = require('./setup_powered_by');
const setupScratchPaper = require('./setup_scratch_paper');
const setupSideMenu = require('./setup_side_menu');
const setupTopMenu = require('./setup_top_menu');
const setupWindow = require('./setup_window');
/**
* Initializes elements once the app loads in the DOM.
*/
const setup = () => {
$('.btn input').click((e) => {
e.stopPropagation();
});
// dividers
setupDividers();
// document
setupDocument();
// files bar
setupFilesBar();
// interval
setupInterval();
// module container
setupModuleContainer();
// powered by
setupPoweredBy();
// scratch paper
setupScratchPaper();
// side menu
setupSideMenu();
// top menu
setupTopMenu();
// window
setupWindow();
};
module.exports = {
setup
};
\ No newline at end of file
const appInstance = require('../../app');
const addDividerToDom = (divider) => {
const [vertical, $first, $second] = divider;
const $parent = $first.parent();
const thickness = 5;
const $divider = $('<div class="divider">');
let dragging = false;
if (vertical) {
$divider.addClass('vertical');
let _left = -thickness / 2;
$divider.css({
top: 0,
bottom: 0,
left: _left,
width: thickness
});
let x;
$divider.mousedown(({
pageX
}) => {
x = pageX;
dragging = true;
});
$(document).mousemove(({
pageX
}) => {
if (dragging) {
const new_left = $second.position().left + pageX - x;
let percent = new_left / $parent.width() * 100;
percent = Math.min(90, Math.max(10, percent));
$first.css('right', (100 - percent) + '%');
$second.css('left', percent + '%');
x = pageX;
appInstance.getTracerManager().resize();
$('.files_bar > .wrapper').scroll();
}
});
$(document).mouseup(function(e) {
dragging = false;
});
} else {
$divider.addClass('horizontal');
const _top = -thickness / 2;
$divider.css({
top: _top,
height: thickness,
left: 0,
right: 0
});
let y;
$divider.mousedown(function({
pageY
}) {
y = pageY;
dragging = true;
});
$(document).mousemove(function({
pageY
}) {
if (dragging) {
const new_top = $second.position().top + pageY - y;
let percent = new_top / $parent.height() * 100;
percent = Math.min(90, Math.max(10, percent));
$first.css('bottom', (100 - percent) + '%');
$second.css('top', percent + '%');
y = pageY;
appInstance.getTracerManager().resize();
}
});
$(document).mouseup(function(e) {
dragging = false;
});
}
$second.append($divider);
};
module.exports = () => {
const dividers = [
['v', $('.sidemenu'), $('.workspace')],
['v', $('.viewer_container'), $('.editor_container')],
['h', $('.data_container'), $('.code_container')]
];
for (let i = 0; i < dividers.length; i++) {
addDividerToDom(dividers[i]);
}
}
\ No newline at end of file
const appInstance = require('../../app');
module.exports = () => {
$(document).on('click', 'a', (e) => {
e.preventDefault();
if (!window.open($(this).attr('href'), '_blank')) {
alert('Please allow popups for this site');
}
});
$(document).mouseup(function(e) {
appInstance.getTracerManager().command('mouseup', e);
});
};
\ No newline at end of file
const definitelyBigger = (x, y) => x > (y + 2);
module.exports = () => {
$('.files_bar > .btn-left').click(() => {
const $wrapper = $('.files_bar > .wrapper');
const clipWidth = $wrapper.width();
const scrollLeft = $wrapper.scrollLeft();
$($wrapper.children('button').get().reverse()).each(function() {
const left = $(this).position().left;
const right = left + $(this).outerWidth();
if (0 > left) {
$wrapper.scrollLeft(scrollLeft + right - clipWidth);
return false;
}
});
});
$('.files_bar > .btn-right').click(() => {
const $wrapper = $('.files_bar > .wrapper');
const clipWidth = $wrapper.width();
const scrollLeft = $wrapper.scrollLeft();
$wrapper.children('button').each(function() {
const left = $(this).position().left;
const right = left + $(this).outerWidth();
if (clipWidth < right) {
$wrapper.scrollLeft(scrollLeft + left);
return false;
}
});
});
$('.files_bar > .wrapper').scroll(function() {
const $wrapper = $('.files_bar > .wrapper');
const clipWidth = $wrapper.width();
const $left = $wrapper.children('button:first-child');
const $right = $wrapper.children('button:last-child');
const left = $left.position().left;
const right = $right.position().left + $right.outerWidth();
if (definitelyBigger(0, left) && definitelyBigger(clipWidth, right)) {
const scrollLeft = $wrapper.scrollLeft();
$wrapper.scrollLeft(scrollLeft + clipWidth - right);
return;
}
const lefter = definitelyBigger(0, left);
const righter = definitelyBigger(right, clipWidth);
$wrapper.toggleClass('shadow-left', lefter);
$wrapper.toggleClass('shadow-right', righter);
$('.files_bar > .btn-left').attr('disabled', !lefter);
$('.files_bar > .btn-right').attr('disabled', !righter);
});
}
\ No newline at end of file
const appInstance = require('../../app');
const Toast = require('../toast');
const {
parseFloat
} = Number;
const minInterval = 0.1;
const maxInterval = 10;
const startInterval = 0.5;
const stepInterval = 0.1;
const normalize = (sec) => {
let interval;
let message;
if (sec < minInterval) {
interval = minInterval;
message = `Interval of ${sec} seconds is too low. Setting to min allowed interval of ${minInterval} second(s).`;
} else if (sec > maxInterval) {
interval = minInterval;
message = `Interval of ${sec} seconds is too high. Setting to max allowed interval of ${maxInterval} second(s).`;
} else {
interval = sec;
message = `Interval has been set to ${sec} second(s).`
}
return [interval, message];
};
module.exports = () => {
const $interval = $('#interval');
$interval.val(startInterval);
$interval.attr({
max: maxInterval,
min: minInterval,
step: stepInterval
});
$('#interval').on('change', function() {
const tracerManager = appInstance.getTracerManager();
const [seconds, message] = normalize(parseFloat($(this).val()));
$(this).val(seconds);
tracerManager.interval = seconds * 1000;
Toast.showInfoToast(message);
});
};
\ No newline at end of file
const appInstance = require('../../app');
module.exports = () => {
const $module_container = $('.module_container');
$module_container.on('mousedown', '.module_wrapper', function(e) {
appInstance.getTracerManager().findOwner(this).mousedown(e);
});
$module_container.on('mousemove', '.module_wrapper', function(e) {
appInstance.getTracerManager().findOwner(this).mousemove(e);
});
$module_container.on('DOMMouseScroll mousewheel', '.module_wrapper', function(e) {
appInstance.getTracerManager().findOwner(this).mousewheel(e);
});
}
\ No newline at end of file
module.exports = () => {
$('#powered-by').click(function() {
$('#powered-by-list button').toggleClass('collapse');
});
};
\ No newline at end of file
const Server = require('../../server');
const showAlgorithm = require('../show_algorithm');
module.exports = () => {
$('#scratch-paper').click(function() {
const category = null;
const algorithm = 'scratch_paper';
Server.loadAlgorithm(category, algorithm).then((data) => {
showAlgorithm(category, algorithm, data);
});
});
};
\ No newline at end of file
const appInstance = require('../../app');
let sidemenu_percent;
module.exports = () => {
$('#navigation').click(() => {
const $sidemenu = $('.sidemenu');
const $workspace = $('.workspace');
$sidemenu.toggleClass('active');
$('.nav-dropdown').toggleClass('fa-caret-down fa-caret-up');
if ($sidemenu.hasClass('active')) {
$sidemenu.css('right', (100 - sidemenu_percent) + '%');
$workspace.css('left', sidemenu_percent + '%');
} else {
sidemenu_percent = $workspace.position().left / $('body').width() * 100;
$sidemenu.css('right', 0);
$workspace.css('left', 0);
}
appInstance.getTracerManager().resize();
});
}
\ No newline at end of file
const appInstance = require('../../app');
const Server = require('../../server');
const Toast = require('../toast');
module.exports = () => {
// shared
$('#shared').mouseup(function() {
$(this).select();
});
$('#btn_share').click(function() {
const $icon = $(this).find('.fa-share');
$icon.addClass('fa-spin fa-spin-faster');
Server.shareScratchPaper().then((url) => {
$icon.removeClass('fa-spin fa-spin-faster');
$('#shared').removeClass('collapse');
$('#shared').val(url);
Toast.showInfoToast('Shareable link is created.');
});
});
// control
$('#btn_run').click(() => {
$('#btn_trace').click();
var err = appInstance.getEditor().execute();
if (err) {
console.error(err);
Toast.showErrorToast(err);
}
});
$('#btn_pause').click(function() {
if (appInstance.getTracerManager().isPause()) {
appInstance.getTracerManager().resumeStep();
} else {
appInstance.getTracerManager().pauseStep();
}
});
$('#btn_prev').click(() => {
appInstance.getTracerManager().pauseStep();
appInstance.getTracerManager().prevStep();
});
$('#btn_next').click(() => {
appInstance.getTracerManager().pauseStep();
appInstance.getTracerManager().nextStep();
});
// description & trace
$('#btn_desc').click(function() {
$('.tab_container > .tab').removeClass('active');
$('#tab_desc').addClass('active');
$('.tab_bar > button').removeClass('active');
$(this).addClass('active');
});
$('#btn_trace').click(function() {
$('.tab_container > .tab').removeClass('active');
$('#tab_module').addClass('active');
$('.tab_bar > button').removeClass('active');
$(this).addClass('active');
});
};
\ No newline at end of file
const appInstance = require('../../app');
module.exports = function() {
$(window).resize(function() {
appInstance.getTracerManager().resize();
});
};
\ No newline at end of file
'use strict';
const appInstance = require('../app');
const {
isScratchPaper
} = require('../utils');
const showDescription = require('./show_description');
const showFiles = require('./show_files');
module.exports = (category, algorithm, data) => {
let $menu;
let category_name;
let algorithm_name;
if (isScratchPaper(category, algorithm)) {
$menu = $('#scratch-paper');
category_name = '';
algorithm_name = 'Scratch Paper';
} else {
$menu = $(`[data-category="${category}"][data-algorithm="${algorithm}"]`);
const categoryObj = appInstance.getCategory(category);
category_name = categoryObj.name;
algorithm_name = categoryObj.list[algorithm];
}
$('.sidemenu button').removeClass('active');
$menu.addClass('active');
$('#btn_desc').click();
$('#category').html(category_name);
$('#algorithm').html(algorithm_name);
$('#tab_desc > .wrapper').empty();
$('.files_bar > .wrapper').empty();
$('#explanation').html('');
appInstance.setLastFileUsed(null);
appInstance.getEditor().clearContent();
const {
files
} = data;
delete data.files;
showDescription(data);
showFiles(category, algorithm, files);
};
\ No newline at end of file
'use strict';
const appInstance = require('../app');
const Server = require('../server');
const showAlgorithm = require('./show_algorithm');
const {
each
} = $;
const addAlgorithmToCategoryDOM = (category, subList, algorithm) => {
const $algorithm = $('<button class="indent collapse">')
.append(subList[algorithm])
.attr('data-algorithm', algorithm)
.attr('data-category', category)
.click(function() {
Server.loadAlgorithm(category, algorithm).then((data) => {
showAlgorithm(category, algorithm, data);
});
});
$('#list').append($algorithm);
};
const addCategoryToDOM = (category) => {
const {
name: categoryName,
list: categorySubList
} = appInstance.getCategory(category);
const $category = $('<button class="category">')
.append('<i class="fa fa-fw fa-caret-right">')
.append(categoryName);
$category.click(function() {
$(`[data-category="${category}"]`).toggleClass('collapse');
$(this).find('i.fa').toggleClass('fa-caret-right fa-caret-down');
});
$('#list').append($category);
each(categorySubList, (algorithm) => {
addAlgorithmToCategoryDOM(category, categorySubList, algorithm);
});
};
module.exports = () => {
each(appInstance.getCategories(), addCategoryToDOM);
};
\ No newline at end of file
'use strict';
const {
isArray
} = Array;
const {
each
} = $;
module.exports = (data) => {
const $container = $('#tab_desc > .wrapper');
$container.empty();
each(data, (key, value) => {
if (key) {
$container.append($('<h3>').html(key));
}
if (typeof value === 'string') {
$container.append($('<p>').html(value));
} else if (isArray(value)) {
const $ul = $('<ul>');
$container.append($ul);
value.forEach((li) => {
$ul.append($('<li>').html(li));
});
} else if (typeof value === 'object') {
const $ul = $('<ul>');
$container.append($ul);
each(value, (prop) => {
$ul.append($('<li>').append($('<strong>').html(prop)).append(` ${value[prop]}`));
});
}
});
};
\ No newline at end of file
'use strict';
const Server = require('../server');
const {
each
} = $;
const addFileToDOM = (category, algorithm, file, explanation) => {
var $file = $('<button>').append(file).click(function() {
Server.loadFile(category, algorithm, file, explanation);
$('.files_bar > .wrapper > button').removeClass('active');
$(this).addClass('active');
});
$('.files_bar > .wrapper').append($file);
};
module.exports = (category, algorithm, files) => {
$('.files_bar > .wrapper').empty();
each(files, (file, explanation) => {
addFileToDOM(category, algorithm, file, explanation);
});
$('.files_bar > .wrapper > button').first().click();
$('.files_bar > .wrapper').scroll();
};
\ No newline at end of file
'use strict';
// click the first algorithm in the first category
module.exports = () => {
$('#list button.category').first().click();
$('#list button.category + .indent').first().click();
};
\ No newline at end of file
'use strict';
const showToast = (data, type) => {
const $toast = $(`<div class="toast ${type}">`).append(data);
$('.toast_container').append($toast);
setTimeout(() => {
$toast.fadeOut(() => {
$toast.remove();
});
}, 3000);
};
const showErrorToast = (err) => {
showToast(err, 'error');
};
const showInfoToast = (err) => {
showToast(err, 'info');
};
module.exports = {
showErrorToast,
showInfoToast
};
\ No newline at end of file
'use strict';
module.exports = function(id) {
const editor = ace.edit(id);
editor.setOptions({
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true
});
editor.setTheme('ace/theme/tomorrow_night_eighties');
editor.session.setMode('ace/mode/javascript');
editor.$blockScrolling = Infinity;
return editor;
};
\ No newline at end of file
'use strict';
const execute = (tracerManager, code) => {
// all modules available to eval are obtained from window
try {
tracerManager.deallocateAll();
eval(code);
tracerManager.visualize();
} catch (err) {
return err;
} finally {
tracerManager.removeUnallocated();
}
};
const executeData = (tracerManager, algoData) => {
return execute(tracerManager, algoData);
};
const executeDataAndCode = (tracerManager, algoData, algoCode) => {
return execute(tracerManager, `${algoData};${algoCode}`);
};
module.exports = {
executeData,
executeDataAndCode
};
\ No newline at end of file
'use strict';
const appInstance = require('../app');
const createEditor = require('./create');
const Executor = require('./executor');
function Editor(tracerManager) {
if (!tracerManager) {
throw 'Cannot create Editor. Missing the tracerManager';
}
ace.require('ace/ext/language_tools');
this.dataEditor = createEditor('data');
this.codeEditor = createEditor('code');
// Setting data
this.setData = (data) => {
this.dataEditor.setValue(data, -1);
};
this.setCode = (code) => {
this.codeEditor.setValue(code, -1);
};
this.setContent = (({
data,
code
}) => {
this.setData(data);
this.setCode(code);
});
// Clearing data
this.clearData = () => {
this.dataEditor.setValue('');
};
this.clearCode = () => {
this.codeEditor.setValue('');
};
this.clearContent = () => {
this.clearData();
this.clearCode();
};
this.execute = () => {
const data = this.dataEditor.getValue();
const code = this.codeEditor.getValue();
return Executor.executeDataAndCode(tracerManager, data, code);
};
// listeners
this.dataEditor.on('change', () => {
const data = this.dataEditor.getValue();
const lastFileUsed = appInstance.getLastFileUsed();
if (lastFileUsed) {
appInstance.updateCachedFile(lastFileUsed, {
data
});
}
Executor.executeData(tracerManager, data);
});
this.codeEditor.on('change', () => {
const code = this.codeEditor.getValue();
const lastFileUsed = appInstance.getLastFileUsed();
if (lastFileUsed) {
appInstance.updateCachedFile(lastFileUsed, {
code
});
}
});
};
module.exports = Editor;
\ No newline at end of file
'use strict';
const RSVP = require('rsvp');
const appInstance = require('./app');
const AppConstructor = require('./app/constructor');
const DOM = require('./dom');
const Server = require('./server');
const Helpers = require('./server/helpers');
const modules = require('./module');
const {
extend
} = $;
$.ajaxSetup({
cache: false,
dataType: 'text'
});
// set global promise error handler
RSVP.on('error', function(reason) {
console.assert(false, reason);
});
$(() => {
// initialize the application and attach in to the instance module
const app = new AppConstructor();
extend(true, appInstance, app);
// load modules to the global scope so they can be evaled
extend(true, window, modules);
Server.loadCategories().then((data) => {
appInstance.setCategories(data);
DOM.showCategories();
// determine if the app is loading a pre-existing scratch-pad
// or the home page
const gistID = Helpers.getParameterByName('scratch-paper');
if (gistID) {
Server.loadScratchPaper(gistID).then(({
category,
algorithm,
data
}) => {
DOM.showAlgorithm(category, algorithm, data);
});
} else {
DOM.showFirstAlgorithm();
}
});
// http://localhost:8080/?scratch-paper=dcf0d0de60a4ad335b3b0cb5c39035e7
});
\ No newline at end of file
const {
Array2D,
Array2DTracer
} = require('./array2d');
function Array1DTracer() {
return Array2DTracer.apply(this, arguments);
}
Array1DTracer.prototype = $.extend(true, Object.create(Array2DTracer.prototype), {
constructor: Array1DTracer,
_notify: function (idx, v) {
_notify: function(idx, v) {
Array2DTracer.prototype._notify.call(this, 0, idx, v);
return this;
},
_denotify: function (idx) {
_denotify: function(idx) {
Array2DTracer.prototype._denotify.call(this, 0, idx);
return this;
},
_select: function (s, e) {
_select: function(s, e) {
if (e === undefined) {
Array2DTracer.prototype._select.call(this, 0, s);
} else {
......@@ -20,7 +25,7 @@ Array1DTracer.prototype = $.extend(true, Object.create(Array2DTracer.prototype),
}
return this;
},
_deselect: function (s, e) {
_deselect: function(s, e) {
if (e === undefined) {
Array2DTracer.prototype._deselect.call(this, 0, s);
} else {
......@@ -28,32 +33,21 @@ Array1DTracer.prototype = $.extend(true, Object.create(Array2DTracer.prototype),
}
return this;
},
_separate: function (idx) {
this.manager.pushStep(this.capsule, {
type: 'separate',
x: 0,
y: idx
});
return this;
},
_deseparate: function (idx) {
this.manager.pushStep(this.capsule, {
type: 'deseparate',
x: 0,
y: idx
});
return this;
},
setData: function (D) {
setData: function(D) {
return Array2DTracer.prototype.setData.call(this, [D]);
}
});
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];
}
};
module.exports = {
Array1D,
Array1DTracer
};
\ No newline at end of file
const Tracer = require('./tracer');
const {
refineByType
} = require('../tracer_manager/util');
function Array2DTracer() {
if (Tracer.apply(this, arguments)) {
Array2DTracer.prototype.init.call(this);
......@@ -8,11 +13,11 @@ function Array2DTracer() {
Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
constructor: Array2DTracer,
init: function () {
init: function() {
this.$table = this.capsule.$table = $('<div class="mtbl-table">');
this.$container.append(this.$table);
},
_notify: function (x, y, v) {
_notify: function(x, y, v) {
this.manager.pushStep(this.capsule, {
type: 'notify',
x: x,
......@@ -21,7 +26,7 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
});
return this;
},
_denotify: function (x, y) {
_denotify: function(x, y) {
this.manager.pushStep(this.capsule, {
type: 'denotify',
x: x,
......@@ -29,31 +34,31 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
});
return this;
},
_select: function (sx, sy, ex, ey) {
_select: function(sx, sy, ex, ey) {
this.pushSelectingStep('select', null, arguments);
return this;
},
_selectRow: function (x, sy, ey) {
_selectRow: function(x, sy, ey) {
this.pushSelectingStep('select', 'row', arguments);
return this;
},
_selectCol: function (y, sx, ex) {
_selectCol: function(y, sx, ex) {
this.pushSelectingStep('select', 'col', arguments);
return this;
},
_deselect: function (sx, sy, ex, ey) {
_deselect: function(sx, sy, ex, ey) {
this.pushSelectingStep('deselect', null, arguments);
return this;
},
_deselectRow: function (x, sy, ey) {
_deselectRow: function(x, sy, ey) {
this.pushSelectingStep('deselect', 'row', arguments);
return this;
},
_deselectCol: function (y, sx, ex) {
_deselectCol: function(y, sx, ex) {
this.pushSelectingStep('deselect', 'col', arguments);
return this;
},
_separate: function (x, y) {
_separate: function(x, y) {
this.manager.pushStep(this.capsule, {
type: 'separate',
x: x,
......@@ -61,15 +66,15 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
});
return this;
},
_separateRow: function (x) {
_separateRow: function(x) {
this._separate(x, -1);
return this;
},
_separateCol: function (y) {
_separateCol: function(y) {
this._separate(-1, y);
return this;
},
_deseparate: function (x, y) {
_deseparate: function(x, y) {
this.manager.pushStep(this.capsule, {
type: 'deseparate',
x: x,
......@@ -77,15 +82,15 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
});
return this;
},
_deseparateRow: function (x) {
_deseparateRow: function(x) {
this._deseparate(x, -1);
return this;
},
_deseparateCol: function (y) {
_deseparateCol: function(y) {
this._deseparate(-1, y);
return this;
},
pushSelectingStep: function () {
pushSelectingStep: function() {
var args = Array.prototype.slice.call(arguments);
var type = args.shift();
var mode = args.shift();
......@@ -127,13 +132,13 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
$.extend(step, coord);
this.manager.pushStep(this.capsule, step);
},
processStep: function (step, options) {
processStep: function(step, options) {
switch (step.type) {
case 'notify':
if (step.v === 0 || step.v) {
var $row = this.$table.find('.mtbl-row').eq(step.x);
var $col = $row.find('.mtbl-col').eq(step.y);
$col.text(TracerUtil.refineByType(step.v));
$col.text(refineByType(step.v));
}
case 'denotify':
case 'select':
......@@ -161,16 +166,16 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
Tracer.prototype.processStep.call(this, step, options);
}
},
setData: function (D) {
setData: function(D) {
this.viewX = this.viewY = 0;
this.paddingH = 6;
this.paddingV = 3;
this.fontSize = 16;
if (Tracer.prototype.setData.apply(this, arguments)) {
this.$table.find('.mtbl-row').each(function (i) {
$(this).find('.mtbl-col').each(function (j) {
$(this).text(TracerUtil.refineByType(D[i][j]));
this.$table.find('.mtbl-row').each(function(i) {
$(this).find('.mtbl-col').each(function(j) {
$(this).text(refineByType(D[i][j]));
});
});
return true;
......@@ -183,7 +188,7 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
for (var j = 0; j < D[i].length; j++) {
var $col = $('<div class="mtbl-col">')
.css(this.getCellCss())
.text(TracerUtil.refineByType(D[i][j]));
.text(refineByType(D[i][j]));
$row.append($col);
}
}
......@@ -191,24 +196,24 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
return false;
},
resize: function () {
resize: function() {
Tracer.prototype.resize.call(this);
this.refresh();
},
clear: function () {
clear: function() {
Tracer.prototype.clear.call(this);
this.clearColor();
this.deseparateAll();
},
getCellCss: function () {
getCellCss: function() {
return {
padding: this.paddingV.toFixed(1) + 'px ' + this.paddingH.toFixed(1) + 'px',
'font-size': this.fontSize.toFixed(1) + 'px'
};
},
refresh: function () {
refresh: function() {
Tracer.prototype.refresh.call(this);
var $parent = this.$table.parent();
......@@ -217,14 +222,14 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
this.$table.css('margin-top', top);
this.$table.css('margin-left', left);
},
mousedown: function (e) {
mousedown: function(e) {
Tracer.prototype.mousedown.call(this, e);
this.dragX = e.pageX;
this.dragY = e.pageY;
this.dragging = true;
},
mousemove: function (e) {
mousemove: function(e) {
Tracer.prototype.mousemove.call(this, e);
if (this.dragging) {
......@@ -235,12 +240,12 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
this.refresh();
}
},
mouseup: function (e) {
mouseup: function(e) {
Tracer.prototype.mouseup.call(this, e);
this.dragging = false;
},
mousewheel: function (e) {
mousewheel: function(e) {
Tracer.prototype.mousewheel.call(this, e);
e.preventDefault();
......@@ -257,7 +262,7 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
this.$table.find('.mtbl-col').css(this.getCellCss());
this.refresh();
},
paintColor: function (sx, sy, ex, ey, colorClass, addClass) {
paintColor: function(sx, sy, ex, ey, colorClass, addClass) {
for (var i = sx; i <= ex; i++) {
var $row = this.$table.find('.mtbl-row').eq(i);
for (var j = sy; j <= ey; j++) {
......@@ -267,20 +272,20 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
}
}
},
clearColor: function () {
clearColor: function() {
this.$table.find('.mtbl-col').removeClass(Object.keys(this.colorClass).join(' '));
},
colorClass: {
selected: 'selected',
notified: 'notified'
},
separate: function (x, y) {
this.$table.find('.mtbl-row').each(function (i) {
separate: function(x, y) {
this.$table.find('.mtbl-row').each(function(i) {
var $row = $(this);
if (i == x) {
$row.after($('<div class="mtbl-empty-row">').attr('data-row', i))
}
$row.find('.mtbl-col').each(function (j) {
$row.find('.mtbl-col').each(function(j) {
var $col = $(this);
if (j == y) {
$col.after($('<div class="mtbl-empty-col">').attr('data-col', j));
......@@ -288,17 +293,17 @@ Array2DTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
});
});
},
deseparate: function (x, y) {
deseparate: function(x, y) {
this.$table.find('[data-row=' + x + ']').remove();
this.$table.find('[data-col=' + y + ']').remove();
},
deseparateAll: function () {
deseparateAll: function() {
this.$table.find('.mtbl-empty-row, .mtbl-empty-col').remove();
}
});
var Array2D = {
random: function (N, M, min, max) {
random: function(N, M, min, max) {
if (!N) N = 10;
if (!M) M = 10;
if (min === undefined) min = 1;
......@@ -312,11 +317,16 @@ var Array2D = {
}
return D;
},
randomSorted: function (N, M, min, max) {
return this.random(N, M, min, max).map(function (arr) {
return arr.sort(function (a, b) {
randomSorted: function(N, M, min, max) {
return this.random(N, M, min, max).map(function(arr) {
return arr.sort(function(a, b) {
return a - b;
});
});
}
};
module.exports = {
Array2D,
Array2DTracer
};
\ No newline at end of file
const Tracer = require('./tracer');
function ChartTracer() {
if (Tracer.apply(this, arguments)) {
ChartTracer.prototype.init.call(this, arguments);
......@@ -8,11 +10,11 @@ function ChartTracer() {
ChartTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
constructor: ChartTracer,
init: function () {
init: function() {
this.$wrapper = this.capsule.$wrapper = $('<canvas id="chart">');
this.$container.append(this.$wrapper);
},
setData: function (C) {
setData: function(C) {
if (Tracer.prototype.setData.apply(this, arguments)) return true;
var tracer = this;
var color = [];
......@@ -30,7 +32,7 @@ ChartTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
beginAtZero: true
}
}]
}
......@@ -38,23 +40,38 @@ ChartTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
};
this.chart = this.capsule.chart = new Chart(this.$wrapper, data);
},
_notify: function (s, v) {
this.manager.pushStep(this.capsule, { type: 'notify', s: s, v: v });
_notify: function(s, v) {
this.manager.pushStep(this.capsule, {
type: 'notify',
s: s,
v: v
});
return this;
},
_denotify: function (s) {
this.manager.pushStep(this.capsule, { type: 'denotify', s: s });
_denotify: function(s) {
this.manager.pushStep(this.capsule, {
type: 'denotify',
s: s
});
return this;
},
_select: function (s, e) {
this.manager.pushStep(this.capsule, { type: 'select', s: s, e: e });
_select: function(s, e) {
this.manager.pushStep(this.capsule, {
type: 'select',
s: s,
e: e
});
return this;
},
_deselect: function (s, e) {
this.manager.pushStep(this.capsule, { type: 'deselect', s: s, e: e });
_deselect: function(s, e) {
this.manager.pushStep(this.capsule, {
type: 'deselect',
s: s,
e: e
});
return this;
},
processStep: function (step, options) {
processStep: function(step, options) {
switch (step.type) {
case 'notify':
if (step.v) {
......@@ -65,11 +82,11 @@ ChartTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
case 'deselect':
var color = step.type == 'denotify' || step.type == 'deselect' ? 'rgba(136, 136, 136, 1)' : 'rgba(255, 0, 0, 1)';
case 'select':
if(color === undefined) var color = 'rgba(0, 0, 255, 1)';
if(step.e !== undefined)
for (var i = step.s; i <= step.e; i++)
if (color === undefined) var color = 'rgba(0, 0, 255, 1)';
if (step.e !== undefined)
for (var i = step.s; i <= step.e; i++)
this.chart.config.data.datasets[0].backgroundColor[i] = color;
else
else
this.chart.config.data.datasets[0].backgroundColor[step.s] = color;
this.chart.update();
break;
......@@ -78,3 +95,5 @@ ChartTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
}
},
});
module.exports = ChartTracer;
\ No newline at end of file
const Tracer = require('./tracer');
function DirectedGraphTracer() {
if (Tracer.apply(this, arguments)) {
DirectedGraphTracer.prototype.init.call(this);
......@@ -8,7 +10,7 @@ function DirectedGraphTracer() {
DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
constructor: DirectedGraphTracer,
init: function () {
init: function() {
var tracer = this;
this.s = this.capsule.s = new sigma({
......@@ -30,13 +32,13 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
maxNodeSize: 12,
labelSize: 'proportional',
labelSizeRatio: 1.3,
funcLabelsDef: function (node, context, settings) {
funcLabelsDef: function(node, context, settings) {
tracer.drawLabel(node, context, settings);
},
funcHoversDef: function (node, context, settings, next) {
funcHoversDef: function(node, context, settings, next) {
tracer.drawOnHover(node, context, settings, next);
},
funcEdgesArrow: function (edge, source, target, context, settings) {
funcEdgesArrow: function(edge, source, target, context, settings) {
var color = tracer.getColor(edge, source, target, settings);
tracer.drawArrow(edge, source, target, color, context, settings);
}
......@@ -45,19 +47,30 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
sigma.plugins.dragNodes(this.s, this.s.renderers[0]);
this.graph = this.capsule.graph = this.s.graph;
},
_setTreeData: function (G, root) {
this.manager.pushStep(this.capsule, {type: 'setTreeData', arguments: arguments});
_setTreeData: function(G, root) {
this.manager.pushStep(this.capsule, {
type: 'setTreeData',
arguments: arguments
});
return this;
},
_visit: function (target, source) {
this.manager.pushStep(this.capsule, {type: 'visit', target: target, source: source});
_visit: function(target, source) {
this.manager.pushStep(this.capsule, {
type: 'visit',
target: target,
source: source
});
return this;
},
_leave: function (target, source) {
this.manager.pushStep(this.capsule, {type: 'leave', target: target, source: source});
_leave: function(target, source) {
this.manager.pushStep(this.capsule, {
type: 'leave',
target: target,
source: source
});
return this;
},
processStep: function (step, options) {
processStep: function(step, options) {
switch (step.type) {
case 'setTreeData':
this.setTreeData.apply(this, step.arguments);
......@@ -84,14 +97,14 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
Tracer.prototype.processStep.call(this, step, options);
}
},
setTreeData: function (G, root) {
setTreeData: function(G, root) {
var tracer = this;
root = root || 0;
var maxDepth = -1;
var chk = new Array(G.length);
var getDepth = function (node, depth) {
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;
......@@ -103,14 +116,14 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
if (this.setData.apply(this, arguments)) return true;
var place = function (node, x, y) {
var place = function(node, x, y) {
var temp = tracer.graph.nodes(tracer.n(node));
temp.x = x;
temp.y = y;
};
var wgap = 1 / (maxDepth - 1);
var dfs = function (node, depth, top, bottom) {
var dfs = function(node, depth, top, bottom) {
place(node, top + bottom, depth * wgap);
var children = 0;
for (var i = 0; i < G[node].length; i++) {
......@@ -126,7 +139,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
this.refresh();
},
setData: function (G) {
setData: function(G) {
if (Tracer.prototype.setData.apply(this, arguments)) return true;
this.graph.clear();
......@@ -171,18 +184,18 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
return false;
},
resize: function () {
resize: function() {
Tracer.prototype.resize.call(this);
this.s.renderers[0].resize();
this.refresh();
},
refresh: function () {
refresh: function() {
Tracer.prototype.refresh.call(this);
this.s.refresh();
},
clear: function () {
clear: function() {
Tracer.prototype.clear.call(this);
this.clearGraphColor();
......@@ -192,23 +205,23 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
left: '#000',
default: '#888'
},
clearGraphColor: function () {
clearGraphColor: function() {
var tracer = this;
this.graph.nodes().forEach(function (node) {
this.graph.nodes().forEach(function(node) {
node.color = tracer.color.default;
});
this.graph.edges().forEach(function (edge) {
this.graph.edges().forEach(function(edge) {
edge.color = tracer.color.default;
});
},
n: function (v) {
n: function(v) {
return 'n' + v;
},
e: function (v1, v2) {
e: function(v1, v2) {
return 'e' + v1 + '_' + v2;
},
getColor: function (edge, source, target, settings) {
getColor: function(edge, source, target, settings) {
var color = edge.color,
edgeColor = settings('edgeColor'),
defaultNodeColor = settings('defaultNodeColor'),
......@@ -228,7 +241,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
return color;
},
drawLabel: function (node, context, settings) {
drawLabel: function(node, context, settings) {
var fontSize,
prefix = settings('prefix') || '',
size = node[prefix + 'size'];
......@@ -241,7 +254,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
fontSize = (settings('labelSize') === 'fixed') ?
settings('defaultLabelSize') :
settings('labelSizeRatio') * size;
settings('labelSizeRatio') * size;
context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
fontSize + 'px ' + settings('font');
......@@ -256,7 +269,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
Math.round(node[prefix + 'y'] + fontSize / 3)
);
},
drawArrow: function (edge, source, target, color, context, settings) {
drawArrow: function(edge, source, target, color, context, settings) {
var prefix = settings('prefix') || '',
size = edge[prefix + 'size'] || 1,
tSize = target[prefix + 'size'],
......@@ -296,12 +309,12 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
context.closePath();
context.fill();
},
drawOnHover: function (node, context, settings, next) {
drawOnHover: function(node, context, settings, next) {
var tracer = this;
context.setLineDash([5, 5]);
var nodeIdx = node.id.substring(1);
this.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';
......@@ -321,7 +334,7 @@ DirectedGraphTracer.prototype = $.extend(true, Object.create(Tracer.prototype),
});
var DirectedGraph = {
random: function (N, ratio) {
random: function(N, ratio) {
if (!N) N = 5;
if (!ratio) ratio = .3;
var G = new Array(N);
......@@ -337,27 +350,32 @@ var DirectedGraph = {
}
};
sigma.canvas.labels.def = function (node, context, settings) {
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) {
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) {
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) {
sigma.canvas.edges.arrow = function(edge, source, target, context, settings) {
var func = settings('funcEdgesArrow');
if (func) {
func(edge, source, target, context, settings);
}
};
module.exports = {
DirectedGraph,
DirectedGraphTracer
};
\ No newline at end of file
'use strict';
const Tracer = require('./tracer');
const LogTracer = require('./log_tracer');
const {
Array1D,
Array1DTracer
} = require('./array1d');
const {
Array2D,
Array2DTracer
} = require('./array2d');
const ChartTracer = require('./chart');
const {
DirectedGraph,
DirectedGraphTracer
} = require('./directed_graph');
const {
UndirectedGraph,
UndirectedGraphTracer
} = require('./undirected_graph');
const {
WeightedDirectedGraph,
WeightedDirectedGraphTracer
} = require('./weighted_directed_graph');
const {
WeightedUndirectedGraph,
WeightedUndirectedGraphTracer
} = require('./weighted_undirected_graph');
module.exports = {
Tracer,
LogTracer,
Array1D,
Array1DTracer,
Array2D,
Array2DTracer,
ChartTracer,
DirectedGraph,
DirectedGraphTracer,
UndirectedGraph,
UndirectedGraphTracer,
WeightedDirectedGraph,
WeightedDirectedGraphTracer,
WeightedUndirectedGraph,
WeightedUndirectedGraphTracer
};
\ No newline at end of file
const Tracer = require('./tracer');
function LogTracer() {
if (Tracer.apply(this, arguments)) {
LogTracer.prototype.init.call(this);
......@@ -8,33 +10,40 @@ function LogTracer() {
LogTracer.prototype = $.extend(true, Object.create(Tracer.prototype), {
constructor: LogTracer,
init: function () {
init: function() {
this.$wrapper = this.capsule.$wrapper = $('<div class="wrapper">');
this.$container.append(this.$wrapper);
},
_print: function (msg) {
this.manager.pushStep(this.capsule, {type: 'print', msg: msg});
_print: function(msg) {
this.manager.pushStep(this.capsule, {
type: 'print',
msg: msg
});
return this;
},
processStep: function (step, options) {
processStep: function(step, options) {
switch (step.type) {
case 'print':
this.print(step.msg);
break;
}
},
refresh: function () {
refresh: function() {
this.scrollToEnd(Math.min(50, this.interval));
},
clear: function () {
clear: function() {
Tracer.prototype.clear.call(this);
this.$wrapper.empty();
},
print: function (message) {
print: function(message) {
this.$wrapper.append($('<span>').append(message + '<br/>'));
},
scrollToEnd: function (duration) {
this.$container.animate({scrollTop: this.$container[0].scrollHeight}, duration);
scrollToEnd: function(duration) {
this.$container.animate({
scrollTop: this.$container[0].scrollHeight
}, duration);
}
});
\ No newline at end of file
});
module.exports = LogTracer;
\ No newline at end of file
const {
toJSON,
fromJSON
} = require('../tracer_manager/util');
function Tracer(name) {
this.module = this.constructor;
this.capsule = this.manager.allocate(this);
$.extend(this, this.capsule);
this.setName(name);
return this.new;
return this.isNew;
}
Tracer.prototype = {
constructor: Tracer,
manager: null,
_setData: function () {
var args = Array.prototype.slice.call(arguments);
this.manager.pushStep(this.capsule, {type: 'setData', args: TracerUtil.toJSON(args)});
_setData(...args) {
this.manager.pushStep(this.capsule, {
type: 'setData',
args: toJSON(args)
});
return this;
},
_clear: function () {
this.manager.pushStep(this.capsule, {type: 'clear'});
_clear() {
this.manager.pushStep(this.capsule, {
type: 'clear'
});
return this;
},
_wait: function () {
_wait() {
this.manager.newStep();
return this;
},
processStep: function (step, options) {
switch (step.type) {
processStep(step, options) {
const {
type,
args
} = step;
switch (type) {
case 'setData':
this.setData.apply(this, TracerUtil.fromJSON(step.args));
this.setData(...fromJSON(args));
break;
case 'clear':
this.clear();
break;
}
},
setName: function (name) {
var $name;
if (this.new) {
setName(name) {
let $name;
if (this.isNew) {
$name = $('<span class="name">');
this.$container.append($name);
} else {
......@@ -42,31 +62,32 @@ Tracer.prototype = {
}
$name.text(name || this.defaultName);
},
setData: function () {
var data = TracerUtil.toJSON(arguments);
if (!this.new && this.lastData == data) return true;
this.new = this.capsule.new = false;
setData() {
const data = toJSON(arguments);
if (!this.isNew && this.lastData === data) {
return true;
}
this.isNew = this.capsule.isNew = false;
this.lastData = this.capsule.lastData = data;
return false;
},
resize: function () {
},
refresh: function () {
},
clear: function () {
},
attach: function (tracer) {
if (tracer.module == LogTracer) {
resize() {},
refresh() {},
clear() {},
attach(tracer) {
if (tracer.module === LogTracer) {
this.logTracer = tracer;
}
return this;
},
mousedown: function (e) {
},
mousemove: function (e) {
},
mouseup: function (e) {
},
mousewheel: function (e) {
}
};
\ No newline at end of file
mousedown(e) {},
mousemove(e) {},
mouseup(e) {},
mousewheel(e) {}
};
module.exports = Tracer;
\ No newline at end of file
const {
DirectedGraph,
DirectedGraphTracer
} = require('./directed_graph');
function UndirectedGraphTracer() {
if (DirectedGraphTracer.apply(this, arguments)) {
UndirectedGraphTracer.prototype.init.call(this);
......@@ -8,18 +13,18 @@ function UndirectedGraphTracer() {
UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTracer.prototype), {
constructor: UndirectedGraphTracer,
init: function () {
init: function() {
var tracer = this;
this.s.settings({
defaultEdgeType: 'def',
funcEdgesDef: function (edge, source, target, context, settings) {
funcEdgesDef: 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) {
setData: function(G) {
if (Tracer.prototype.setData.apply(this, arguments)) return true;
this.graph.clear();
......@@ -66,7 +71,7 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
return false;
},
e: function (v1, v2) {
e: function(v1, v2) {
if (v1 > v2) {
var temp = v1;
v1 = v2;
......@@ -74,12 +79,12 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
}
return 'e' + v1 + '_' + v2;
},
drawOnHover: function (node, context, settings, next) {
drawOnHover: function(node, context, settings, next) {
var tracer = this;
context.setLineDash([5, 5]);
var nodeIdx = node.id.substring(1);
this.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';
......@@ -96,7 +101,7 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
}
});
},
drawEdge: function (edge, source, target, color, context, settings) {
drawEdge: function(edge, source, target, color, context, settings) {
var prefix = settings('prefix') || '',
size = edge[prefix + 'size'] || 1;
......@@ -116,7 +121,7 @@ UndirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTrac
});
var UndirectedGraph = {
random: function (N, ratio) {
random: function(N, ratio) {
if (!N) N = 5;
if (!ratio) ratio = .3;
var G = new Array(N);
......@@ -130,4 +135,9 @@ var UndirectedGraph = {
}
return G;
}
};
module.exports = {
UndirectedGraph,
UndirectedGraphTracer
};
\ No newline at end of file
const {
DirectedGraph,
DirectedGraphTracer
} = require('./directed_graph');
const {
refineByType
} = require('../tracer_manager/util');
function WeightedDirectedGraphTracer() {
if (DirectedGraphTracer.apply(this, arguments)) {
WeightedDirectedGraphTracer.prototype.init.call(this);
......@@ -8,44 +17,58 @@ function WeightedDirectedGraphTracer() {
WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGraphTracer.prototype), {
constructor: WeightedDirectedGraphTracer,
init: function () {
init: function() {
var tracer = this;
this.s.settings({
edgeLabelSize: 'proportional',
defaultEdgeLabelSize: 20,
edgeLabelSizePowRatio: 0.8,
funcLabelsDef: function (node, context, settings) {
funcLabelsDef: function(node, context, settings) {
tracer.drawNodeWeight(node, context, settings);
tracer.drawLabel(node, context, settings);
},
funcHoversDef: function (node, context, settings) {
funcHoversDef: function(node, context, settings) {
tracer.drawOnHover(node, context, settings, tracer.drawEdgeWeight);
},
funcEdgesArrow: function (edge, source, target, context, settings) {
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);
}
});
},
_weight: function (target, weight) {
this.manager.pushStep(this.capsule, {type: 'weight', target: target, weight: weight});
_weight: function(target, weight) {
this.manager.pushStep(this.capsule, {
type: 'weight',
target: target,
weight: weight
});
return this;
},
_visit: function (target, source, weight) {
this.manager.pushStep(this.capsule, {type: 'visit', target: target, source: source, weight: weight});
_visit: function(target, source, weight) {
this.manager.pushStep(this.capsule, {
type: 'visit',
target: target,
source: source,
weight: weight
});
return this;
},
_leave: function (target, source, weight) {
this.manager.pushStep(this.capsule, {type: 'leave', target: target, source: source, weight: weight});
_leave: function(target, source, weight) {
this.manager.pushStep(this.capsule, {
type: 'leave',
target: target,
source: source,
weight: weight
});
return this;
},
processStep: function (step, options) {
processStep: function(step, options) {
switch (step.type) {
case 'weight':
var targetNode = this.graph.nodes(this.n(step.target));
if (step.weight !== undefined) targetNode.weight = TracerUtil.refineByType(step.weight);
if (step.weight !== undefined) targetNode.weight = refineByType(step.weight);
break;
case 'visit':
case 'leave':
......@@ -53,7 +76,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
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 = TracerUtil.refineByType(step.weight);
if (step.weight !== undefined) targetNode.weight = refineByType(step.weight);
if (step.source !== undefined) {
var edgeId = this.e(step.source, step.target);
var edge = this.graph.edges(edgeId);
......@@ -70,7 +93,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
DirectedGraphTracer.prototype.processStep.call(this, step, options);
}
},
setData: function (G) {
setData: function(G) {
if (Tracer.prototype.setData.apply(this, arguments)) return true;
this.graph.clear();
......@@ -97,7 +120,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
target: this.n(j),
color: this.color.default,
size: 1,
weight: TracerUtil.refineByType(G[i][j])
weight: refineByType(G[i][j])
});
}
}
......@@ -117,17 +140,17 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
return false;
},
clear: function () {
clear: function() {
DirectedGraphTracer.prototype.clear.call(this);
this.clearWeights();
},
clearWeights: function () {
this.graph.nodes().forEach(function (node) {
clearWeights: function() {
this.graph.nodes().forEach(function(node) {
node.weight = 0;
});
},
drawEdgeWeight: function (edge, source, target, color, context, settings) {
drawEdgeWeight: function(edge, source, target, color, context, settings) {
if (source == target)
return;
......@@ -149,9 +172,9 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
fontSize = (settings('edgeLabelSize') === 'fixed') ?
settings('defaultEdgeLabelSize') :
settings('defaultEdgeLabelSize') *
size *
Math.pow(size, -1 / settings('edgeLabelSizePowRatio'));
settings('defaultEdgeLabelSize') *
size *
Math.pow(size, -1 / settings('edgeLabelSizePowRatio'));
context.save();
......@@ -163,8 +186,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
].join(' ');
context.fillStyle = color;
}
else {
} else {
context.font = [
settings('fontStyle'),
fontSize + 'px',
......@@ -187,7 +209,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
context.restore();
},
drawNodeWeight: function (node, context, settings) {
drawNodeWeight: function(node, context, settings) {
var fontSize,
prefix = settings('prefix') || '',
size = node[prefix + 'size'];
......@@ -197,7 +219,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
fontSize = (settings('labelSize') === 'fixed') ?
settings('defaultLabelSize') :
settings('labelSizeRatio') * size;
settings('labelSizeRatio') * size;
context.font = (settings('fontStyle') ? settings('fontStyle') + ' ' : '') +
fontSize + 'px ' + settings('font');
......@@ -215,7 +237,7 @@ WeightedDirectedGraphTracer.prototype = $.extend(true, Object.create(DirectedGra
});
var WeightedDirectedGraph = {
random: function (N, ratio, min, max) {
random: function(N, ratio, min, max) {
if (!N) N = 5;
if (!ratio) ratio = .3;
if (!min) min = 1;
......@@ -231,4 +253,9 @@ var WeightedDirectedGraph = {
}
return G;
}
};
module.exports = {
WeightedDirectedGraph,
WeightedDirectedGraphTracer
};
\ No newline at end of file
const {
WeightedDirectedGraph,
WeightedDirectedGraphTracer
} = require('./weighted_directed_graph');
const {
UndirectedGraphTracer
} = require('./undirected_graph');
function WeightedUndirectedGraphTracer() {
if (WeightedDirectedGraphTracer.apply(this, arguments)) {
WeightedUndirectedGraphTracer.prototype.init.call(this);
......@@ -8,19 +17,19 @@ function WeightedUndirectedGraphTracer() {
WeightedUndirectedGraphTracer.prototype = $.extend(true, Object.create(WeightedDirectedGraphTracer.prototype), {
constructor: WeightedUndirectedGraphTracer,
init: function () {
init: function() {
var tracer = this;
this.s.settings({
defaultEdgeType: 'def',
funcEdgesDef: function (edge, source, target, context, settings) {
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);
}
});
},
setData: function (G) {
setData: function(G) {
if (Tracer.prototype.setData.apply(this, arguments)) return true;
this.graph.clear();
......@@ -72,7 +81,7 @@ WeightedUndirectedGraphTracer.prototype = $.extend(true, Object.create(WeightedD
e: UndirectedGraphTracer.prototype.e,
drawOnHover: UndirectedGraphTracer.prototype.drawOnHover,
drawEdge: UndirectedGraphTracer.prototype.drawEdge,
drawEdgeWeight: function (edge, source, target, color, context, settings) {
drawEdgeWeight: function(edge, source, target, color, context, settings) {
var prefix = settings('prefix') || '';
if (source[prefix + 'x'] > target[prefix + 'x']) {
var temp = source;
......@@ -84,7 +93,7 @@ WeightedUndirectedGraphTracer.prototype = $.extend(true, Object.create(WeightedD
});
var WeightedUndirectedGraph = {
random: function (N, ratio, min, max) {
random: function(N, ratio, min, max) {
if (!N) N = 5;
if (!ratio) ratio = .3;
if (!min) min = 1;
......@@ -100,4 +109,9 @@ var WeightedUndirectedGraph = {
}
return G;
}
};
module.exports = {
WeightedUndirectedGraph,
WeightedUndirectedGraphTracer
};
\ No newline at end of file
此差异已折叠。
'use strict';
const request = require('./request');
module.exports = (url) => {
return request(url, {
type: 'GET'
});
};
\ No newline at end of file
'use strict';
const request = require('./request');
module.exports = function(url) {
return request(url, {
dataType: 'json',
type: 'GET'
});
};
\ No newline at end of file
'use strict';
const request = require('./request');
module.exports = function(url, data) {
return request(url, {
dataType: 'json',
type: 'POST',
data: JSON.stringify(data),
});
};
\ No newline at end of file
'use strict';
const RSVP = require('rsvp');
const appInstance = require('../../app');
const {
ajax,
extend
} = $;
const defaults = {
};
module.exports = function(url, options = {}) {
appInstance.setIsLoading(true);
return new RSVP.Promise((resolve, reject) => {
const callbacks = {
success(response) {
appInstance.setIsLoading(false);
resolve(response);
},
error(reason) {
appInstance.setIsLoading(false);
reject(reason);
}
};
const opts = extend({}, defaults, options, callbacks, {
url
});
ajax(opts);
});
};
\ No newline at end of file
'use strict';
const appInstance = require('../app');
const Toast = require('../dom/toast');
const checkLoading = () => {
if (appInstance.getIsLoading()) {
Toast.showErrorToast('Wait until it completes loading of previous file.');
return true;
}
return false;
};
const getParameterByName = (name) => {
const url = window.location.href;
const cleanName = name.replace(/[\[\]]/g, '\\$&');
const regex = new RegExp(`[?&]${name}(=([^&#]*)|&|#|$)`);
const results = regex.exec(url);
if (!results || results.length !== 3) {
return null;
}
const [, , id] = results;
return id;
};
module.exports = {
checkLoading,
getParameterByName
};
\ No newline at end of file
'use strict';
const loadAlgorithm = require('./load_algorithm');
const loadCategories = require('./load_categories');
const loadFile = require('./load_file');
const loadScratchPaper = require('./load_scratch_paper');
const shareScratchPaper = require('./share_scratch_paper');
module.exports = {
loadAlgorithm,
loadCategories,
loadFile,
loadScratchPaper,
shareScratchPaper
};
\ No newline at end of file
'use strict';
const Utils = require('../utils');
const getJSON = require('./ajax/get_json');
module.exports = (category, algorithm) => {
const dir = Utils.getAlgorithmDir(category, algorithm);
return getJSON(`${dir}desc.json`);
};
\ No newline at end of file
'use strict';
const appInstance = require('../app');
const getJSON = require('./ajax/get_json');
module.exports = () => {
return getJSON('./algorithm/category.json');
};
\ No newline at end of file
'use strict';
const RSVP = require('rsvp');
const appInstance = require('../app');
const Utils = require('../utils');
const {
checkLoading
} = require('./helpers');
const get = require('./ajax/get');
const loadDataAndCode = (dir) => {
return RSVP.hash({
data: get(`${dir}data.js`),
code: get(`${dir}code.js`)
});
};
const loadFileAndUpdateContent = (dir) => {
appInstance.setIsLoading(true);
appInstance.getEditor().clearContent();
return loadDataAndCode(dir).then((content) => {
appInstance.updateCachedFile(dir, content);
appInstance.getEditor().setContent(content);
});
};
const cachedContentExists = (cachedFile) => {
return cachedFile &&
cachedFile.data !== undefined &&
cachedFile.code !== undefined;
};
module.exports = (category, algorithm, file, explanation) => {
return new RSVP.Promise((resolve, reject) => {
if (checkLoading()) {
reject();
} else {
$('#explanation').html(explanation);
let dir = Utils.getFileDir(category, algorithm, file);
appInstance.setLastFileUsed(dir);
const cachedFile = appInstance.getCachedFile(dir);
if (cachedContentExists(cachedFile)) {
appInstance.getEditor().setContent(cachedFile);
resolve();
} else {
loadFileAndUpdateContent(dir).then(resolve, reject);
}
}
});
};
\ No newline at end of file
'use strict';
const RSVP = require('rsvp');
const Utils = require('../utils');
const appInstance = require('../app');
const getJSON = require('./ajax/get_json');
const loadAlgorithm = require('./load_algorithm');
const extractGistCode = (files, name) => files[`${name}.js`].content;
module.exports = (gistID) => {
return new RSVP.Promise((resolve, reject) => {
getJSON(`https://api.github.com/gists/${gistID}`).then(({
files
}) => {
const algorithm = 'scratch_paper';
const category = null;
loadAlgorithm(category, algorithm).then((data) => {
const algoData = extractGistCode(files, 'data');
const algoCode = extractGistCode(files, 'code');
// update scratch paper algo code with the loaded gist code
const dir = Utils.getFileDir(category, algorithm, 'scratch_paper');
appInstance.updateCachedFile(dir, {
data: algoData,
code: algoCode,
'CREDIT.md': 'Shared by an anonymous user from http://parkjs814.github.io/AlgorithmVisualizer'
});
resolve({
category,
algorithm,
data
});
});
});
});
};
\ No newline at end of file
'use strict';
const RSVP = require('rsvp');
const appInstance = require('../app');
const postJSON = require('./ajax/post_json');
module.exports = () => {
return new RSVP.Promise((resolve, reject) => {
const {
dataEditor,
codeEditor
} = appInstance.getEditor();
const gist = {
'description': 'temp',
'public': true,
'files': {
'data.js': {
'content': dataEditor.getValue()
},
'code.js': {
'content': codeEditor.getValue()
}
}
};
postJSON('https://api.github.com/gists', gist).then(({
id
}) => {
const {
protocol,
host,
pathname
} = location;
const url = `${protocol}//${host}${pathname}?scratch-paper=${id}`;
resolve(url);
});
});
};
\ No newline at end of file
const stepLimit = 1e6;
var TracerManager = function () {
this.timer = null;
this.pause = false;
this.capsules = [];
this.interval = 500;
};
TracerManager.prototype = {
add: function (tracer) {
var $container = $('<section class="module_wrapper">');
$('.module_container').append($container);
var capsule = {
module: tracer.module,
tracer: tracer,
allocated: true,
defaultName: null,
$container: $container,
new: true
};
this.capsules.push(capsule);
return capsule;
},
allocate: function (newTracer) {
var selectedCapsule = null;
var count = 0;
$.each(this.capsules, function (i, capsule) {
if (capsule.module == newTracer.module) {
count++;
if (!capsule.allocated) {
capsule.tracer = newTracer;
capsule.allocated = true;
capsule.new = false;
selectedCapsule = capsule;
return false;
}
}
});
if (selectedCapsule == null) {
count++;
selectedCapsule = this.add(newTracer);
}
selectedCapsule.defaultName = newTracer.constructor.name + ' ' + count;
return selectedCapsule;
},
deallocateAll: function () {
this.reset();
$.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 = 100;
var height = (100 / capsules.length);
var top = height * i;
capsule.$container.css({
top: top + '%',
width: width + '%',
height: height + '%'
});
capsule.tracer.resize();
});
},
resize: function () {
this.command('resize');
},
isPause: function () {
return this.pause;
},
setInterval: function (interval) {
$('#interval').val(interval);
},
reset: function () {
this.traces = [];
this.traceIndex = -1;
this.stepCnt = 0;
if (this.timer) clearTimeout(this.timer);
this.command('clear');
},
pushStep: function (capsule, step) {
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($.extend(step, {capsule: capsule}));
},
newStep: function () {
this.traces.push([]);
},
pauseStep: function () {
if (this.traceIndex < 0) return;
this.pause = true;
if (this.timer) clearTimeout(this.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];
trace.forEach(function (step) {
step.capsule.tracer.processStep(step, options);
});
if (!options.virtual) {
this.command('refresh');
}
if (this.pause) return;
this.timer = setTimeout(function () {
tracer.step(i + 1, options);
}, this.interval);
},
prevStep: function () {
this.command('clear');
var finalIndex = this.traceIndex - 1;
if (finalIndex < 0) {
this.traceIndex = -1;
this.command('refresh');
return;
}
for (var i = 0; i < finalIndex; i++) {
this.step(i, {virtual: true});
}
this.step(finalIndex);
},
nextStep: function () {
this.step(this.traceIndex + 1);
},
visualize: function () {
this.traceIndex = -1;
this.resumeStep();
},
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);
}
});
},
findOwner: function (container) {
var selectedCapsule = null;
$.each(this.capsules, function (i, capsule) {
if (capsule.$container[0] == container) {
selectedCapsule = capsule;
return false;
}
});
return selectedCapsule.tracer;
}
};
var TracerUtil = {
toJSON: function (obj) {
return JSON.stringify(obj, function (key, value) {
return value === Infinity ? "Infinity" : value;
});
},
fromJSON: function (obj) {
return JSON.parse(obj, function (key, value) {
return value === "Infinity" ? Infinity : value;
});
},
refineByType: function (item) {
return typeof(item) === 'number' ? this.refineNumber(item) : this.refineString(item);
},
refineString: function (str) {
return str === '' ? ' ' : str;
},
refineNumber: function (num) {
return num === Infinity ? '' : num;
}
};
\ No newline at end of file
'use strict';
const TracerManager = require('./manager');
const Tracer = require('../module/tracer');
module.exports = {
init() {
const tm = new TracerManager();
Tracer.prototype.manager = tm;
return tm;
}
};
\ No newline at end of file
'use strict';
const stepLimit = 1e6;
const TracerManager = function() {
this.timer = null;
this.pause = false;
this.capsules = [];
this.interval = 500;
};
TracerManager.prototype = {
add(tracer) {
const $container = $('<section class="module_wrapper">');
$('.module_container').append($container);
const capsule = {
module: tracer.module,
tracer,
allocated: true,
defaultName: null,
$container,
isNew: true
};
this.capsules.push(capsule);
return capsule;
},
allocate(newTracer) {
let selectedCapsule = null;
let count = 0;
$.each(this.capsules, (i, capsule) => {
if (capsule.module === newTracer.module) {
count++;
if (!capsule.allocated) {
capsule.tracer = newTracer;
capsule.allocated = true;
capsule.isNew = false;
selectedCapsule = capsule;
return false;
}
}
});
if (selectedCapsule === null) {
count++;
selectedCapsule = this.add(newTracer);
}
selectedCapsule.defaultName = `${newTracer.constructor.name} ${count}`;
return selectedCapsule;
},
deallocateAll() {
this.reset();
$.each(this.capsules, (i, capsule) => {
capsule.allocated = false;
});
},
removeUnallocated() {
let changed = false;
this.capsules = $.grep(this.capsules, (capsule) => {
let removed = !capsule.allocated;
if (capsule.isNew || removed) {
changed = true;
}
if (removed) {
capsule.$container.remove();
}
return !removed;
});
if (changed) {
this.place();
}
},
place() {
const {
capsules
} = this;
$.each(capsules, (i, capsule) => {
let width = 100;
let height = (100 / capsules.length);
let top = height * i;
capsule.$container.css({
top: `${top}%`,
width: `${width}%`,
height: `${height}%`
});
capsule.tracer.resize();
});
},
resize() {
this.command('resize');
},
isPause() {
return this.pause;
},
setInterval(interval) {
$('#interval').val(interval);
},
reset() {
this.traces = [];
this.traceIndex = -1;
this.stepCnt = 0;
if (this.timer) {
clearTimeout(this.timer);
}
this.command('clear');
},
pushStep(capsule, step) {
if (this.stepCnt++ > stepLimit) throw "Tracer's stack overflow";
let len = this.traces.length;
let last = [];
if (len === 0) {
this.traces.push(last);
} else {
last = this.traces[len - 1];
}
last.push($.extend(step, {
capsule
}));
},
newStep() {
this.traces.push([]);
},
pauseStep() {
if (this.traceIndex < 0) return;
this.pause = true;
if (this.timer) {
clearTimeout(this.timer);
}
$('#btn_pause').addClass('active');
},
resumeStep() {
this.pause = false;
this.step(this.traceIndex + 1);
$('#btn_pause').removeClass('active');
},
step(i, options = {}) {
const tracer = this;
if (isNaN(i) || i >= this.traces.length || i < 0) return;
this.traceIndex = i;
const trace = this.traces[i];
trace.forEach((step) => {
step.capsule.tracer.processStep(step, options);
});
if (!options.virtual) {
this.command('refresh');
}
if (this.pause) return;
this.timer = setTimeout(() => {
tracer.step(i + 1, options);
}, this.interval);
},
prevStep() {
this.command('clear');
const finalIndex = this.traceIndex - 1;
if (finalIndex < 0) {
this.traceIndex = -1;
this.command('refresh');
return;
}
for (let i = 0; i < finalIndex; i++) {
this.step(i, {
virtual: true
});
}
this.step(finalIndex);
},
nextStep() {
this.step(this.traceIndex + 1);
},
visualize() {
this.traceIndex = -1;
this.resumeStep();
},
command(...args) {
const functionName = args.shift();
$.each(this.capsules, (i, capsule) => {
if (capsule.allocated) {
capsule.tracer.module.prototype[functionName].apply(capsule.tracer, args);
}
});
},
findOwner(container) {
let selectedCapsule = null;
$.each(this.capsules, (i, capsule) => {
if (capsule.$container[0] === container) {
selectedCapsule = capsule;
return false;
}
});
return selectedCapsule.tracer;
}
};
module.exports = TracerManager;
\ No newline at end of file
const {
parse
} = JSON;
const fromJSON = (obj) => {
return parse(obj, (key, value) => {
return value === 'Infinity' ? Infinity : value;
});
};
module.exports = fromJSON;
\ No newline at end of file
const toJSON = require('./to_json');
const fromJSON = require('./from_json');
const refineByType = require('./refine_by_type');
module.exports = {
toJSON,
fromJSON,
refineByType
};
\ No newline at end of file
const refineByType = (item) => {
return typeof(item) === 'number' ? refineNumber(item) : refineString(item);
};
const refineString = (str) => {
return str === '' ? ' ' : str;
};
const refineNumber = (num) => {
return num === Infinity ? '' : num;
};
module.exports = refineByType;
\ No newline at end of file
const {
stringify
} = JSON;
const toJSON = (obj) => {
return stringify(obj, (key, value) => {
return value === Infinity ? 'Infinity' : value;
});
};
module.exports = toJSON;
\ No newline at end of file
'use strict';
const isScratchPaper = (category, algorithm) => {
return category === null && algorithm === 'scratch_paper';
};
const getAlgorithmDir = (category, algorithm) => {
if (isScratchPaper(category, algorithm)) {
return './algorithm/scratch_paper/';
}
return `./algorithm/${category}/${algorithm}/`;
};
const getFileDir = (category, algorithm, file) => {
if (isScratchPaper(category, algorithm)) {
return './algorithm/scratch_paper/';
}
return `./algorithm/${category}/${algorithm}/${file}/`;
};
module.exports = {
isScratchPaper,
getAlgorithmDir,
getFileDir
};
\ No newline at end of file
{
"name": "algorithm-visualizer",
"version": "0.1.0",
"description": "Algorithm Visualizer",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/parkjs814/AlgorithmVisualizer.git"
},
"keywords": [
"algorithm",
"visualizer"
],
"author": "Jason Park & contributors",
"license": "MIT",
"bugs": {
"url": "https://github.com/parkjs814/AlgorithmVisualizer/issues"
},
"homepage": "https://github.com/parkjs814/AlgorithmVisualizer#readme",
"devDependencies": {
"babel-core": "^6.9.0",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.9.0",
"babelify": "^7.3.0",
"browserify": "^13.0.1",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.0",
"gulp-babel": "^6.1.2",
"gulp-clean-css": "^2.0.8",
"gulp-concat": "^2.6.0",
"gulp-connect": "^4.0.0",
"gulp-header": "^1.8.2",
"gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^1.5.3",
"gulp-util": "^3.0.7",
"vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0"
},
"dependencies": {
"rsvp": "^3.2.1"
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册