Browse Source

Reworked all code to commonjs modules. Replaced the build script with Gulp

css_transitions^2
jos 10 years ago
parent
commit
72dfc0c45f
77 changed files with 39602 additions and 32801 deletions
  1. +0
    -208
      Jakefile.js
  2. +2
    -8
      README.md
  3. +1
    -1
      dist/vis.css
  4. +32953
    -25864
      dist/vis.js
  5. +1
    -0
      dist/vis.map
  6. +0
    -0
      dist/vis.min.css
  7. +17
    -13
      dist/vis.min.js
  8. +1
    -1
      examples/network/07_selections.html
  9. +138
    -0
      gulpfile.js
  10. +56
    -0
      index.js
  11. +10
    -14
      lib/DOMutil.js
  12. +4
    -0
      lib/DataSet.js
  13. +5
    -0
      lib/DataView.js
  14. +218
    -0
      lib/graph3d/Filter.js
  15. +10
    -466
      lib/graph3d/Graph3d.js
  16. +11
    -0
      lib/graph3d/Point2d.js
  17. +85
    -0
      lib/graph3d/Point3d.js
  18. +140
    -0
      lib/graph3d/StepNumber.js
  19. +0
    -0
      lib/header.js
  20. +0
    -84
      lib/module/exports.js
  21. +10
    -0
      lib/module/hammer.js
  22. +0
    -31
      lib/module/imports.js
  23. +3
    -0
      lib/module/moment.js
  24. +10
    -6
      lib/network/Edge.js
  25. +4
    -0
      lib/network/Groups.js
  26. +2
    -0
      lib/network/Images.js
  27. +24
    -14
      lib/network/Network.js
  28. +3
    -0
      lib/network/Node.js
  29. +2
    -0
      lib/network/Popup.js
  30. +694
    -697
      lib/network/dotparser.js
  31. +1137
    -0
      lib/network/mixins/ClusterMixin.js
  32. +304
    -0
      lib/network/mixins/HierarchicalLayoutMixin.js
  33. +571
    -0
      lib/network/mixins/ManipulationMixin.js
  34. +198
    -0
      lib/network/mixins/MixinLoader.js
  35. +196
    -0
      lib/network/mixins/NavigationMixin.js
  36. +548
    -0
      lib/network/mixins/SectorsMixin.js
  37. +705
    -0
      lib/network/mixins/SelectionMixin.js
  38. +393
    -0
      lib/network/mixins/physics/BarnesHutMixin.js
  39. +125
    -0
      lib/network/mixins/physics/HierarchialRepulsionMixin.js
  40. +700
    -0
      lib/network/mixins/physics/PhysicsMixin.js
  41. +58
    -0
      lib/network/mixins/physics/RepulsionMixin.js
  42. +0
    -1143
      lib/network/networkMixins/ClusterMixin.js
  43. +0
    -311
      lib/network/networkMixins/HierarchicalLayoutMixin.js
  44. +0
    -576
      lib/network/networkMixins/ManipulationMixin.js
  45. +0
    -199
      lib/network/networkMixins/MixinLoader.js
  46. +0
    -205
      lib/network/networkMixins/NavigationMixin.js
  47. +0
    -552
      lib/network/networkMixins/SectorsMixin.js
  48. +0
    -708
      lib/network/networkMixins/SelectionMixin.js
  49. +0
    -398
      lib/network/networkMixins/physics/BarnesHut.js
  50. +0
    -133
      lib/network/networkMixins/physics/HierarchialRepulsion.js
  51. +0
    -706
      lib/network/networkMixins/physics/PhysicsMixin.js
  52. +0
    -66
      lib/network/networkMixins/physics/Repulsion.js
  53. +0
    -252
      lib/shim.js
  54. +3
    -2
      lib/timeline/DataStep.js
  55. +13
    -0
      lib/timeline/Graph2d.js
  56. +6
    -0
      lib/timeline/Range.js
  57. +7
    -10
      lib/timeline/Stack.js
  58. +4
    -0
      lib/timeline/TimeStep.js
  59. +13
    -0
      lib/timeline/Timeline.js
  60. +2
    -0
      lib/timeline/component/Component.js
  61. +5
    -1
      lib/timeline/component/CurrentTime.js
  62. +6
    -0
      lib/timeline/component/CustomTime.js
  63. +7
    -0
      lib/timeline/component/DataAxis.js
  64. +8
    -3
      lib/timeline/component/GraphGroup.js
  65. +6
    -0
      lib/timeline/component/Group.js
  66. +12
    -0
      lib/timeline/component/ItemSet.js
  67. +14
    -8
      lib/timeline/component/Legend.js
  68. +10
    -4
      lib/timeline/component/LineGraph.js
  69. +6
    -0
      lib/timeline/component/TimeAxis.js
  70. +4
    -0
      lib/timeline/component/item/Item.js
  71. +4
    -0
      lib/timeline/component/item/ItemBox.js
  72. +4
    -0
      lib/timeline/component/item/ItemPoint.js
  73. +5
    -0
      lib/timeline/component/item/ItemRange.js
  74. +96
    -94
      lib/util.js
  75. +20
    -12
      package.json
  76. +4
    -5
      test/dataset.js
  77. +4
    -6
      test/dataview.js

+ 0
- 208
Jakefile.js View File

@ -1,208 +0,0 @@
/**
* Jake build script
*/
var jake = require('jake'),
browserify = require('browserify'),
wrench = require('wrench'),
CleanCSS = require('clean-css'),
fs = require('fs');
require('jake-utils');
// constants
var DIST = './dist';
var VIS = DIST + '/vis.js';
var VIS_CSS = DIST + '/vis.css';
var VIS_TMP = DIST + '/vis.js.tmp';
var VIS_MIN = DIST + '/vis.min.js';
var VIS_MIN_CSS = DIST + '/vis.min.css';
/**
* default task
*/
desc('Default task: build all libraries');
task('default', ['build', 'minify'], function () {
console.log('done');
});
/**
* build the visualization library vis.js
*/
desc('Build the visualization library vis.js');
task('build', {async: true}, function () {
jake.mkdirP(DIST);
jake.mkdirP(DIST + '/img');
// concatenate and stringify the css files
concat({
src: [
'./lib/timeline/component/css/timeline.css',
'./lib/timeline/component/css/panel.css',
'./lib/timeline/component/css/labelset.css',
'./lib/timeline/component/css/itemset.css',
'./lib/timeline/component/css/item.css',
'./lib/timeline/component/css/timeaxis.css',
'./lib/timeline/component/css/currenttime.css',
'./lib/timeline/component/css/customtime.css',
'./lib/timeline/component/css/animation.css',
'./lib/timeline/component/css/dataaxis.css',
'./lib/timeline/component/css/pathStyles.css',
'./lib/network/css/network-manipulation.css',
'./lib/network/css/network-navigation.css'
],
dest: VIS_CSS,
separator: '\n'
});
console.log('created ' + VIS_CSS);
// concatenate the script files
concat({
dest: VIS_TMP,
src: [
'./lib/module/imports.js',
'./lib/shim.js',
'./lib/util.js',
'./lib/DOMutil.js',
'./lib/DataSet.js',
'./lib/DataView.js',
'./lib/timeline/component/GraphGroup.js',
'./lib/timeline/component/Legend.js',
'./lib/timeline/component/DataAxis.js',
'./lib/timeline/component/LineGraph.js',
'./lib/timeline/DataStep.js',
'./lib/timeline/Stack.js',
'./lib/timeline/TimeStep.js',
'./lib/timeline/Range.js',
'./lib/timeline/component/Component.js',
'./lib/timeline/component/TimeAxis.js',
'./lib/timeline/component/CurrentTime.js',
'./lib/timeline/component/CustomTime.js',
'./lib/timeline/component/ItemSet.js',
'./lib/timeline/component/item/*.js',
'./lib/timeline/component/Group.js',
'./lib/timeline/Timeline.js',
'./lib/timeline/Graph2d.js',
'./lib/network/dotparser.js',
'./lib/network/shapes.js',
'./lib/network/Node.js',
'./lib/network/Edge.js',
'./lib/network/Popup.js',
'./lib/network/Groups.js',
'./lib/network/Images.js',
'./lib/network/networkMixins/physics/PhysicsMixin.js',
'./lib/network/networkMixins/physics/HierarchialRepulsion.js',
'./lib/network/networkMixins/physics/BarnesHut.js',
'./lib/network/networkMixins/physics/Repulsion.js',
'./lib/network/networkMixins/HierarchicalLayoutMixin.js',
'./lib/network/networkMixins/ManipulationMixin.js',
'./lib/network/networkMixins/SectorsMixin.js',
'./lib/network/networkMixins/ClusterMixin.js',
'./lib/network/networkMixins/SelectionMixin.js',
'./lib/network/networkMixins/NavigationMixin.js',
'./lib/network/networkMixins/MixinLoader.js',
'./lib/network/Network.js',
'./lib/graph3d/Graph3d.js',
'./lib/module/exports.js'
],
separator: '\n'
});
// copy images
wrench.copyDirSyncRecursive('./lib/network/img', DIST + '/img/network', {
forceDelete: true
});
wrench.copyDirSyncRecursive('./lib/timeline/img', DIST + '/img/timeline', {
forceDelete: true
});
var timeStart = Date.now();
// bundle the concatenated script and dependencies into one file
var b = browserify();
b.add(VIS_TMP);
b.bundle({
standalone: 'vis'
}, function (err, code) {
if(err) {
throw err;
}
console.log("browserify",Date.now() - timeStart); timeStart = Date.now();
// add header and footer
var lib = read('./lib/module/header.js') + code;
// write bundled file
write(VIS, lib);
console.log('created js' + VIS);
// remove temporary file
fs.unlinkSync(VIS_TMP);
// update version number and stuff in the javascript files
replacePlaceholders(VIS);
complete();
});
});
/**
* minify the visualization library vis.js
*/
desc('Minify the visualization library vis.js');
task('minify', {async: true}, function () {
// minify javascript
minify({
src: VIS,
dest: VIS_MIN,
header: read('./lib/module/header.js')
});
// update version number and stuff in the javascript files
replacePlaceholders(VIS_MIN);
console.log('created minified ' + VIS_MIN);
var minified = new CleanCSS().minify(read(VIS_CSS));
write(VIS_MIN_CSS, minified);
console.log('created minified ' + VIS_MIN_CSS);
});
/**
* test task
*/
desc('Test the library');
task('test', function () {
// TODO: use a testing suite for testing: nodeunit, mocha, tap, ...
var filelist = new jake.FileList();
filelist.include([
'./test/**/*.js'
]);
var files = filelist.toArray();
files.forEach(function (file) {
require('./' + file);
});
console.log('Executed ' + files.length + ' test files successfully');
});
/**
* replace version, date, and name placeholders in the provided file
* @param {String} filename
*/
var replacePlaceholders = function (filename) {
replace({
replacements: [
{pattern: '@@date', replacement: today()},
{pattern: '@@version', replacement: version()}
],
src: filename
});
};

+ 2
- 8
README.md View File

@ -124,15 +124,9 @@ To build the library from source, clone the project from github
git clone git://github.com/almende/vis.git
The project uses [jake](https://github.com/mde/jake) as build tool.
The build script uses [Browserify](http://browserify.org/) to
bundle the source code into a library,
and uses [UglifyJS](http://lisperator.net/uglifyjs/) to minify the code.
The source code uses the module style of node (require and module.exports) to
organize dependencies.
To install all dependencies and build the library, run `npm install` in the
root of the project.
organize dependencies. To install all dependencies and build the library,
run `npm install` in the root of the project.
cd vis
npm install

+ 1
- 1
dist/vis.css View File

@ -703,4 +703,4 @@ div.network-navigation.zoomExtends {
background-image: url("img/network/zoomExtends.png");
bottom:50px;
right:15px;
}
}

+ 32953
- 25864
dist/vis.js
File diff suppressed because it is too large
View File


+ 1
- 0
dist/vis.map
File diff suppressed because it is too large
View File


+ 0
- 0
dist/vis.min.css View File


+ 17
- 13
dist/vis.min.js
File diff suppressed because it is too large
View File


+ 1
- 1
examples/network/07_selections.html View File

@ -56,7 +56,7 @@
});
// set initial selection (id's of some nodes)
network.setSelection([3, 4, 5]);
network.selectNodes([3, 4, 5]);
</script>
</body>

+ 138
- 0
gulpfile.js View File

@ -0,0 +1,138 @@
var fs = require('fs');
var gulp = require('gulp');
var gutil = require('gulp-util');
var concat = require('gulp-concat');
var minifyCSS = require('gulp-minify-css');
var rename = require("gulp-rename");
var webpack = require('webpack');
var uglify = require('uglify-js');
var rimraf = require('rimraf');
var merge = require('merge-stream');
var ENTRY = './index.js';
var HEADER = './lib/header.js';
var DIST = './dist';
var VIS_JS = 'vis.js';
var VIS_MAP = 'vis.map';
var VIS_CSS = 'vis.css';
var VIS_MIN_CSS = 'vis.min.css';
var DIST_VIS_MIN_JS = DIST + '/vis.min.js';
var DIST_VIS_MAP = DIST + '/' + VIS_MAP;
// generate banner with today's date and correct version
function createBanner() {
var today = gutil.date(new Date(), 'yyyy-mm-dd'); // today, formatted as yyyy-mm-dd
var version = require('./package.json').version;
return String(fs.readFileSync(HEADER))
.replace('@@date', today)
.replace('@@version', version);
}
var bannerPlugin = new webpack.BannerPlugin(createBanner(), {
entryOnly: true,
raw: true
});
var webpackConfig = {
entry: ENTRY,
output: {
library: 'vis',
libraryTarget: 'umd',
path: DIST,
filename: VIS_JS,
sourcePrefix: ' '
},
plugins: [ bannerPlugin ],
cache: true
};
var uglifyConfig = {
outSourceMap: VIS_MAP,
output: {
comments: /@license/
}
};
// create a single instance of the compiler to allow caching
var compiler = webpack(webpackConfig);
// clean the dist directory
gulp.task('clean', function (cb) {
rimraf(DIST, cb);
});
gulp.task('bundle-js', ['clean'], function (cb) {
// update the banner contents (has a date in it which should stay up to date)
bannerPlugin.banner = createBanner();
compiler.run(function (err, stats) {
if (err) gutil.log(err);
cb();
});
});
// bundle and minify css
gulp.task('bundle-css', ['clean'], function () {
var files = [
'./lib/timeline/component/css/timeline.css',
'./lib/timeline/component/css/panel.css',
'./lib/timeline/component/css/labelset.css',
'./lib/timeline/component/css/itemset.css',
'./lib/timeline/component/css/item.css',
'./lib/timeline/component/css/timeaxis.css',
'./lib/timeline/component/css/currenttime.css',
'./lib/timeline/component/css/customtime.css',
'./lib/timeline/component/css/animation.css',
'./lib/timeline/component/css/dataaxis.css',
'./lib/timeline/component/css/pathStyles.css',
'./lib/network/css/network-manipulation.css',
'./lib/network/css/network-navigation.css'
];
return gulp.src(files)
.pipe(concat(VIS_CSS))
.pipe(gulp.dest(DIST))
// TODO: nicer to put minifying css in a separate task?
.pipe(minifyCSS())
.pipe(rename(VIS_MIN_CSS))
.pipe(gulp.dest(DIST));
});
gulp.task('copy-img', ['clean'], function () {
var network = gulp.src('./lib/network/img/**/*')
.pipe(gulp.dest(DIST + '/img/network'));
var timeline = gulp.src('./lib/timeline/img/**/*')
.pipe(gulp.dest(DIST + '/img/timeline'));
return merge(network, timeline);
});
gulp.task('minify', ['bundle-js'], function (cb) {
var result = uglify.minify([DIST + '/' + VIS_JS], uglifyConfig);
fs.writeFileSync(DIST_VIS_MIN_JS, result.code);
fs.writeFileSync(DIST_VIS_MAP, result.map);
cb();
});
gulp.task('bundle', ['bundle-js', 'bundle-css', 'copy-img']);
// The watch task (to automatically rebuild when the source code changes)
gulp.task('watch', ['bundle', 'minify'], function () {
gulp.watch(['index.js', 'lib/**/*.js'], ['bundle', 'minify']);
});
// The watch task (to automatically rebuild when the source code changes)
// this watch only rebuilds vis.js, not vis.min.js
gulp.task('watch-dev', ['bundle'], function () {
gulp.watch(['index.js', 'lib/**/*.js'], ['bundle']);
});
// The default task (called when you run `gulp`)
gulp.task('default', ['clean', 'bundle', 'minify']);

+ 56
- 0
index.js View File

@ -0,0 +1,56 @@
// utils
exports.util = require('./lib/util');
exports.DOMutil = require('./lib/DOMutil');
// data
exports.DataSet = require('./lib/DataSet');
exports.DataView = require('./lib/DataView');
// Graph3d
exports.Graph3d = require('./lib/graph3d/Graph3d');
// Timeline
exports.Timeline = require('./lib/timeline/Timeline');
exports.Graph2d = require('./lib/timeline/Graph2d');
exports.timeline= {
DataStep: require('./lib/timeline/DataStep'),
Range: require('./lib/timeline/Range'),
stack: require('./lib/timeline/Stack'),
TimeStep: require('./lib/timeline/TimeStep'),
components: {
items: {
Item: require('./lib/timeline/component/item/Item'),
ItemBox: require('./lib/timeline/component/item/ItemBox'),
ItemPoint: require('./lib/timeline/component/item/ItemPoint'),
ItemRange: require('./lib/timeline/component/item/ItemRange')
},
Component: require('./lib/timeline/component/Component'),
CurrentTime: require('./lib/timeline/component/CurrentTime'),
CustomTime: require('./lib/timeline/component/CustomTime'),
DataAxis: require('./lib/timeline/component/DataAxis'),
GraphGroup: require('./lib/timeline/component/GraphGroup'),
Group: require('./lib/timeline/component/Group'),
ItemSet: require('./lib/timeline/component/ItemSet'),
Legend: require('./lib/timeline/component/Legend'),
LineGraph: require('./lib/timeline/component/LineGraph'),
TimeAxis: require('./lib/timeline/component/TimeAxis')
}
};
// Network
exports.Network = require('./lib/network/Network');
exports.network = {
Edge: require('./lib/network/Edge'),
Groups: require('./lib/network/Groups'),
Images: require('./lib/network/Images'),
Node: require('./lib/network/Node'),
Popup: require('./lib/network/Popup'),
dotparser: require('./lib/network/dotparser')
};
// Deprecated since v3.0.0
exports.Graph = function () {
throw new Error('Graph is renamed to Network. Please create a graph as new vis.Network(...)');
};

+ 10
- 14
lib/DOMutil.js View File

@ -1,15 +1,11 @@
/**
* Created by Alex on 6/20/14.
*/
var DOMutil = {};
// DOM utility methods
/**
* this prepares the JSON container for allocating SVG elements
* @param JSONcontainer
* @private
*/
DOMutil.prepareElements = function(JSONcontainer) {
exports.prepareElements = function(JSONcontainer) {
// cleanup the redundant svgElements;
for (var elementType in JSONcontainer) {
if (JSONcontainer.hasOwnProperty(elementType)) {
@ -26,7 +22,7 @@ DOMutil.prepareElements = function(JSONcontainer) {
* @param JSONcontainer
* @private
*/
DOMutil.cleanupElements = function(JSONcontainer) {
exports.cleanupElements = function(JSONcontainer) {
// cleanup the redundant svgElements;
for (var elementType in JSONcontainer) {
if (JSONcontainer.hasOwnProperty(elementType)) {
@ -50,7 +46,7 @@ DOMutil.cleanupElements = function(JSONcontainer) {
* @returns {*}
* @private
*/
DOMutil.getSVGElement = function (elementType, JSONcontainer, svgContainer) {
exports.getSVGElement = function (elementType, JSONcontainer, svgContainer) {
var element;
// allocate SVG element, if it doesnt yet exist, create one.
if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before
@ -86,7 +82,7 @@ DOMutil.getSVGElement = function (elementType, JSONcontainer, svgContainer) {
* @returns {*}
* @private
*/
DOMutil.getDOMElement = function (elementType, JSONcontainer, DOMContainer) {
exports.getDOMElement = function (elementType, JSONcontainer, DOMContainer) {
var element;
// allocate SVG element, if it doesnt yet exist, create one.
if (JSONcontainer.hasOwnProperty(elementType)) { // this element has been created before
@ -126,17 +122,17 @@ DOMutil.getDOMElement = function (elementType, JSONcontainer, DOMContainer) {
* @param svgContainer
* @returns {*}
*/
DOMutil.drawPoint = function(x, y, group, JSONcontainer, svgContainer) {
exports.drawPoint = function(x, y, group, JSONcontainer, svgContainer) {
var point;
if (group.options.drawPoints.style == 'circle') {
point = DOMutil.getSVGElement('circle',JSONcontainer,svgContainer);
point = exports.getSVGElement('circle',JSONcontainer,svgContainer);
point.setAttributeNS(null, "cx", x);
point.setAttributeNS(null, "cy", y);
point.setAttributeNS(null, "r", 0.5 * group.options.drawPoints.size);
point.setAttributeNS(null, "class", group.className + " point");
}
else {
point = DOMutil.getSVGElement('rect',JSONcontainer,svgContainer);
point = exports.getSVGElement('rect',JSONcontainer,svgContainer);
point.setAttributeNS(null, "x", x - 0.5*group.options.drawPoints.size);
point.setAttributeNS(null, "y", y - 0.5*group.options.drawPoints.size);
point.setAttributeNS(null, "width", group.options.drawPoints.size);
@ -153,8 +149,8 @@ DOMutil.drawPoint = function(x, y, group, JSONcontainer, svgContainer) {
* @param y
* @param className
*/
DOMutil.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) {
var rect = DOMutil.getSVGElement('rect',JSONcontainer, svgContainer);
exports.drawBar = function (x, y, width, height, className, JSONcontainer, svgContainer) {
var rect = exports.getSVGElement('rect',JSONcontainer, svgContainer);
rect.setAttributeNS(null, "x", x - 0.5 * width);
rect.setAttributeNS(null, "y", y);
rect.setAttributeNS(null, "width", width);

+ 4
- 0
lib/DataSet.js View File

@ -1,3 +1,5 @@
var util = require('./util');
/**
* DataSet
*
@ -932,3 +934,5 @@ DataSet.prototype._appendRow = function (dataTable, columns, item) {
dataTable.setValue(row, col, item[field]);
}
};
module.exports = DataSet;

+ 5
- 0
lib/DataView.js View File

@ -1,3 +1,6 @@
var util = require('./util');
var DataSet = require('./DataSet');
/**
* DataView
*
@ -294,3 +297,5 @@ DataView.prototype._trigger = DataSet.prototype._trigger;
// TODO: make these functions deprecated (replaced with `on` and `off` since version 0.5)
DataView.prototype.subscribe = DataView.prototype.on;
DataView.prototype.unsubscribe = DataView.prototype.off;
module.exports = DataView;

+ 218
- 0
lib/graph3d/Filter.js View File

@ -0,0 +1,218 @@
var DataView = require('../DataView');
/**
* @class Filter
*
* @param {DataSet} data The google data table
* @param {Number} column The index of the column to be filtered
* @param {Graph} graph The graph
*/
function Filter (data, column, graph) {
this.data = data;
this.column = column;
this.graph = graph; // the parent graph
this.index = undefined;
this.value = undefined;
// read all distinct values and select the first one
this.values = graph.getDistinctValues(data.get(), this.column);
// sort both numeric and string values correctly
this.values.sort(function (a, b) {
return a > b ? 1 : a < b ? -1 : 0;
});
if (this.values.length > 0) {
this.selectValue(0);
}
// create an array with the filtered datapoints. this will be loaded afterwards
this.dataPoints = [];
this.loaded = false;
this.onLoadCallback = undefined;
if (graph.animationPreload) {
this.loaded = false;
this.loadInBackground();
}
else {
this.loaded = true;
}
};
/**
* Return the label
* @return {string} label
*/
Filter.prototype.isLoaded = function() {
return this.loaded;
};
/**
* Return the loaded progress
* @return {Number} percentage between 0 and 100
*/
Filter.prototype.getLoadedProgress = function() {
var len = this.values.length;
var i = 0;
while (this.dataPoints[i]) {
i++;
}
return Math.round(i / len * 100);
};
/**
* Return the label
* @return {string} label
*/
Filter.prototype.getLabel = function() {
return this.graph.filterLabel;
};
/**
* Return the columnIndex of the filter
* @return {Number} columnIndex
*/
Filter.prototype.getColumn = function() {
return this.column;
};
/**
* Return the currently selected value. Returns undefined if there is no selection
* @return {*} value
*/
Filter.prototype.getSelectedValue = function() {
if (this.index === undefined)
return undefined;
return this.values[this.index];
};
/**
* Retrieve all values of the filter
* @return {Array} values
*/
Filter.prototype.getValues = function() {
return this.values;
};
/**
* Retrieve one value of the filter
* @param {Number} index
* @return {*} value
*/
Filter.prototype.getValue = function(index) {
if (index >= this.values.length)
throw 'Error: index out of range';
return this.values[index];
};
/**
* Retrieve the (filtered) dataPoints for the currently selected filter index
* @param {Number} [index] (optional)
* @return {Array} dataPoints
*/
Filter.prototype._getDataPoints = function(index) {
if (index === undefined)
index = this.index;
if (index === undefined)
return [];
var dataPoints;
if (this.dataPoints[index]) {
dataPoints = this.dataPoints[index];
}
else {
var f = {};
f.column = this.column;
f.value = this.values[index];
var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get();
dataPoints = this.graph._getDataPoints(dataView);
this.dataPoints[index] = dataPoints;
}
return dataPoints;
};
/**
* Set a callback function when the filter is fully loaded.
*/
Filter.prototype.setOnLoadCallback = function(callback) {
this.onLoadCallback = callback;
};
/**
* Add a value to the list with available values for this filter
* No double entries will be created.
* @param {Number} index
*/
Filter.prototype.selectValue = function(index) {
if (index >= this.values.length)
throw 'Error: index out of range';
this.index = index;
this.value = this.values[index];
};
/**
* Load all filtered rows in the background one by one
* Start this method without providing an index!
*/
Filter.prototype.loadInBackground = function(index) {
if (index === undefined)
index = 0;
var frame = this.graph.frame;
if (index < this.values.length) {
var dataPointsTemp = this._getDataPoints(index);
//this.graph.redrawInfo(); // TODO: not neat
// create a progress box
if (frame.progress === undefined) {
frame.progress = document.createElement('DIV');
frame.progress.style.position = 'absolute';
frame.progress.style.color = 'gray';
frame.appendChild(frame.progress);
}
var progress = this.getLoadedProgress();
frame.progress.innerHTML = 'Loading animation... ' + progress + '%';
// TODO: this is no nice solution...
frame.progress.style.bottom = 60 + 'px'; // TODO: use height of slider
frame.progress.style.left = 10 + 'px';
var me = this;
setTimeout(function() {me.loadInBackground(index+1);}, 10);
this.loaded = false;
}
else {
this.loaded = true;
// remove the progress box
if (frame.progress !== undefined) {
frame.removeChild(frame.progress);
frame.progress = undefined;
}
if (this.onLoadCallback)
this.onLoadCallback();
}
};
module.exports = Filter;

+ 10
- 466
lib/graph3d/Graph3d.js View File

@ -1,3 +1,11 @@
var Emitter = require('emitter-component');
var DataSet = require('../DataSet');
var DataView = require('../DataView');
var Point3d = require('./Point3d');
var Point2d = require('./Point2d');
var Filter = require('./Filter');
var StepNumber = require('./StepNumber');
/**
* @constructor Graph3d
* Graph3d displays data in 3d.
@ -715,19 +723,6 @@ Graph3d.prototype._getDataPoints = function (data) {
return dataPoints;
};
/**
* Append suffix 'px' to provided value x
* @param {int} x An integer value
* @return {string} the string value of x, followed by the suffix 'px'
*/
Graph3d.px = function(x) {
return x + 'px';
};
/**
* Create the main frame for the Graph3d.
* This function is executed once when a Graph3d object is created. The frame
@ -2455,458 +2450,6 @@ G3DpreventDefault = function (event) {
}
};
/**
* @prototype Point3d
* @param {Number} x
* @param {Number} y
* @param {Number} z
*/
function Point3d(x, y, z) {
this.x = x !== undefined ? x : 0;
this.y = y !== undefined ? y : 0;
this.z = z !== undefined ? z : 0;
};
/**
* Subtract the two provided points, returns a-b
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} a-b
*/
Point3d.subtract = function(a, b) {
var sub = new Point3d();
sub.x = a.x - b.x;
sub.y = a.y - b.y;
sub.z = a.z - b.z;
return sub;
};
/**
* Add the two provided points, returns a+b
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} a+b
*/
Point3d.add = function(a, b) {
var sum = new Point3d();
sum.x = a.x + b.x;
sum.y = a.y + b.y;
sum.z = a.z + b.z;
return sum;
};
/**
* Calculate the average of two 3d points
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} The average, (a+b)/2
*/
Point3d.avg = function(a, b) {
return new Point3d(
(a.x + b.x) / 2,
(a.y + b.y) / 2,
(a.z + b.z) / 2
);
};
/**
* Calculate the cross product of the two provided points, returns axb
* Documentation: http://en.wikipedia.org/wiki/Cross_product
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} cross product axb
*/
Point3d.crossProduct = function(a, b) {
var crossproduct = new Point3d();
crossproduct.x = a.y * b.z - a.z * b.y;
crossproduct.y = a.z * b.x - a.x * b.z;
crossproduct.z = a.x * b.y - a.y * b.x;
return crossproduct;
};
/**
* Rtrieve the length of the vector (or the distance from this point to the origin
* @return {Number} length
*/
Point3d.prototype.length = function() {
return Math.sqrt(
this.x * this.x +
this.y * this.y +
this.z * this.z
);
};
/**
* @prototype Point2d
*/
Point2d = function (x, y) {
this.x = x !== undefined ? x : 0;
this.y = y !== undefined ? y : 0;
};
/**
* @class Filter
*
* @param {DataSet} data The google data table
* @param {Number} column The index of the column to be filtered
* @param {Graph} graph The graph
*/
function Filter (data, column, graph) {
this.data = data;
this.column = column;
this.graph = graph; // the parent graph
this.index = undefined;
this.value = undefined;
// read all distinct values and select the first one
this.values = graph.getDistinctValues(data.get(), this.column);
// sort both numeric and string values correctly
this.values.sort(function (a, b) {
return a > b ? 1 : a < b ? -1 : 0;
});
if (this.values.length > 0) {
this.selectValue(0);
}
// create an array with the filtered datapoints. this will be loaded afterwards
this.dataPoints = [];
this.loaded = false;
this.onLoadCallback = undefined;
if (graph.animationPreload) {
this.loaded = false;
this.loadInBackground();
}
else {
this.loaded = true;
}
};
/**
* Return the label
* @return {string} label
*/
Filter.prototype.isLoaded = function() {
return this.loaded;
};
/**
* Return the loaded progress
* @return {Number} percentage between 0 and 100
*/
Filter.prototype.getLoadedProgress = function() {
var len = this.values.length;
var i = 0;
while (this.dataPoints[i]) {
i++;
}
return Math.round(i / len * 100);
};
/**
* Return the label
* @return {string} label
*/
Filter.prototype.getLabel = function() {
return this.graph.filterLabel;
};
/**
* Return the columnIndex of the filter
* @return {Number} columnIndex
*/
Filter.prototype.getColumn = function() {
return this.column;
};
/**
* Return the currently selected value. Returns undefined if there is no selection
* @return {*} value
*/
Filter.prototype.getSelectedValue = function() {
if (this.index === undefined)
return undefined;
return this.values[this.index];
};
/**
* Retrieve all values of the filter
* @return {Array} values
*/
Filter.prototype.getValues = function() {
return this.values;
};
/**
* Retrieve one value of the filter
* @param {Number} index
* @return {*} value
*/
Filter.prototype.getValue = function(index) {
if (index >= this.values.length)
throw 'Error: index out of range';
return this.values[index];
};
/**
* Retrieve the (filtered) dataPoints for the currently selected filter index
* @param {Number} [index] (optional)
* @return {Array} dataPoints
*/
Filter.prototype._getDataPoints = function(index) {
if (index === undefined)
index = this.index;
if (index === undefined)
return [];
var dataPoints;
if (this.dataPoints[index]) {
dataPoints = this.dataPoints[index];
}
else {
var f = {};
f.column = this.column;
f.value = this.values[index];
var dataView = new DataView(this.data,{filter: function (item) {return (item[f.column] == f.value);}}).get();
dataPoints = this.graph._getDataPoints(dataView);
this.dataPoints[index] = dataPoints;
}
return dataPoints;
};
/**
* Set a callback function when the filter is fully loaded.
*/
Filter.prototype.setOnLoadCallback = function(callback) {
this.onLoadCallback = callback;
};
/**
* Add a value to the list with available values for this filter
* No double entries will be created.
* @param {Number} index
*/
Filter.prototype.selectValue = function(index) {
if (index >= this.values.length)
throw 'Error: index out of range';
this.index = index;
this.value = this.values[index];
};
/**
* Load all filtered rows in the background one by one
* Start this method without providing an index!
*/
Filter.prototype.loadInBackground = function(index) {
if (index === undefined)
index = 0;
var frame = this.graph.frame;
if (index < this.values.length) {
var dataPointsTemp = this._getDataPoints(index);
//this.graph.redrawInfo(); // TODO: not neat
// create a progress box
if (frame.progress === undefined) {
frame.progress = document.createElement('DIV');
frame.progress.style.position = 'absolute';
frame.progress.style.color = 'gray';
frame.appendChild(frame.progress);
}
var progress = this.getLoadedProgress();
frame.progress.innerHTML = 'Loading animation... ' + progress + '%';
// TODO: this is no nice solution...
frame.progress.style.bottom = Graph3d.px(60); // TODO: use height of slider
frame.progress.style.left = Graph3d.px(10);
var me = this;
setTimeout(function() {me.loadInBackground(index+1);}, 10);
this.loaded = false;
}
else {
this.loaded = true;
// remove the progress box
if (frame.progress !== undefined) {
frame.removeChild(frame.progress);
frame.progress = undefined;
}
if (this.onLoadCallback)
this.onLoadCallback();
}
};
/**
* @prototype StepNumber
* The class StepNumber is an iterator for Numbers. You provide a start and end
* value, and a best step size. StepNumber itself rounds to fixed values and
* a finds the step that best fits the provided step.
*
* If prettyStep is true, the step size is chosen as close as possible to the
* provided step, but being a round value like 1, 2, 5, 10, 20, 50, ....
*
* Example usage:
* var step = new StepNumber(0, 10, 2.5, true);
* step.start();
* while (!step.end()) {
* alert(step.getCurrent());
* step.next();
* }
*
* Version: 1.0
*
* @param {Number} start The start value
* @param {Number} end The end value
* @param {Number} step Optional. Step size. Must be a positive value.
* @param {boolean} prettyStep Optional. If true, the step size is rounded
* To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/
StepNumber = function (start, end, step, prettyStep) {
// set default values
this._start = 0;
this._end = 0;
this._step = 1;
this.prettyStep = true;
this.precision = 5;
this._current = 0;
this.setRange(start, end, step, prettyStep);
};
/**
* Set a new range: start, end and step.
*
* @param {Number} start The start value
* @param {Number} end The end value
* @param {Number} step Optional. Step size. Must be a positive value.
* @param {boolean} prettyStep Optional. If true, the step size is rounded
* To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/
StepNumber.prototype.setRange = function(start, end, step, prettyStep) {
this._start = start ? start : 0;
this._end = end ? end : 0;
this.setStep(step, prettyStep);
};
/**
* Set a new step size
* @param {Number} step New step size. Must be a positive value
* @param {boolean} prettyStep Optional. If true, the provided step is rounded
* to a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/
StepNumber.prototype.setStep = function(step, prettyStep) {
if (step === undefined || step <= 0)
return;
if (prettyStep !== undefined)
this.prettyStep = prettyStep;
if (this.prettyStep === true)
this._step = StepNumber.calculatePrettyStep(step);
else
this._step = step;
};
/**
* Calculate a nice step size, closest to the desired step size.
* Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an
* integer Number. For example 1, 2, 5, 10, 20, 50, etc...
* @param {Number} step Desired step size
* @return {Number} Nice step size
*/
StepNumber.calculatePrettyStep = function (step) {
var log10 = function (x) {return Math.log(x) / Math.LN10;};
// try three steps (multiple of 1, 2, or 5
var step1 = Math.pow(10, Math.round(log10(step))),
step2 = 2 * Math.pow(10, Math.round(log10(step / 2))),
step5 = 5 * Math.pow(10, Math.round(log10(step / 5)));
// choose the best step (closest to minimum step)
var prettyStep = step1;
if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2;
if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5;
// for safety
if (prettyStep <= 0) {
prettyStep = 1;
}
return prettyStep;
};
/**
* returns the current value of the step
* @return {Number} current value
*/
StepNumber.prototype.getCurrent = function () {
return parseFloat(this._current.toPrecision(this.precision));
};
/**
* returns the current step size
* @return {Number} current step size
*/
StepNumber.prototype.getStep = function () {
return this._step;
};
/**
* Set the current value to the largest value smaller than start, which
* is a multiple of the step size
*/
StepNumber.prototype.start = function() {
this._current = this._start - this._start % this._step;
};
/**
* Do a step, add the step size to the current value
*/
StepNumber.prototype.next = function () {
this._current += this._step;
};
/**
* Returns true whether the end is reached
* @return {boolean} True if the current value has passed the end value.
*/
StepNumber.prototype.end = function () {
return (this._current > this._end);
};
/**
* @constructor Slider
*
@ -2981,7 +2524,7 @@ function Slider(container, options) {
this.playTimeout = undefined;
this.playInterval = 1000; // milliseconds
this.playLoop = true;
};
}
/**
* Select the previous index
@ -3308,3 +2851,4 @@ getMouseY = function(event) {
return event.targetTouches[0] && event.targetTouches[0].clientY || 0;
};
module.exports = Graph3d;

+ 11
- 0
lib/graph3d/Point2d.js View File

@ -0,0 +1,11 @@
/**
* @prototype Point2d
* @param {Number} [x]
* @param {Number} [y]
*/
Point2d = function (x, y) {
this.x = x !== undefined ? x : 0;
this.y = y !== undefined ? y : 0;
};
module.exports = Point2d;

+ 85
- 0
lib/graph3d/Point3d.js View File

@ -0,0 +1,85 @@
/**
* @prototype Point3d
* @param {Number} [x]
* @param {Number} [y]
* @param {Number} [z]
*/
function Point3d(x, y, z) {
this.x = x !== undefined ? x : 0;
this.y = y !== undefined ? y : 0;
this.z = z !== undefined ? z : 0;
};
/**
* Subtract the two provided points, returns a-b
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} a-b
*/
Point3d.subtract = function(a, b) {
var sub = new Point3d();
sub.x = a.x - b.x;
sub.y = a.y - b.y;
sub.z = a.z - b.z;
return sub;
};
/**
* Add the two provided points, returns a+b
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} a+b
*/
Point3d.add = function(a, b) {
var sum = new Point3d();
sum.x = a.x + b.x;
sum.y = a.y + b.y;
sum.z = a.z + b.z;
return sum;
};
/**
* Calculate the average of two 3d points
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} The average, (a+b)/2
*/
Point3d.avg = function(a, b) {
return new Point3d(
(a.x + b.x) / 2,
(a.y + b.y) / 2,
(a.z + b.z) / 2
);
};
/**
* Calculate the cross product of the two provided points, returns axb
* Documentation: http://en.wikipedia.org/wiki/Cross_product
* @param {Point3d} a
* @param {Point3d} b
* @return {Point3d} cross product axb
*/
Point3d.crossProduct = function(a, b) {
var crossproduct = new Point3d();
crossproduct.x = a.y * b.z - a.z * b.y;
crossproduct.y = a.z * b.x - a.x * b.z;
crossproduct.z = a.x * b.y - a.y * b.x;
return crossproduct;
};
/**
* Rtrieve the length of the vector (or the distance from this point to the origin
* @return {Number} length
*/
Point3d.prototype.length = function() {
return Math.sqrt(
this.x * this.x +
this.y * this.y +
this.z * this.z
);
};
module.exports = Point3d;

+ 140
- 0
lib/graph3d/StepNumber.js View File

@ -0,0 +1,140 @@
/**
* @prototype StepNumber
* The class StepNumber is an iterator for Numbers. You provide a start and end
* value, and a best step size. StepNumber itself rounds to fixed values and
* a finds the step that best fits the provided step.
*
* If prettyStep is true, the step size is chosen as close as possible to the
* provided step, but being a round value like 1, 2, 5, 10, 20, 50, ....
*
* Example usage:
* var step = new StepNumber(0, 10, 2.5, true);
* step.start();
* while (!step.end()) {
* alert(step.getCurrent());
* step.next();
* }
*
* Version: 1.0
*
* @param {Number} start The start value
* @param {Number} end The end value
* @param {Number} step Optional. Step size. Must be a positive value.
* @param {boolean} prettyStep Optional. If true, the step size is rounded
* To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/
function StepNumber(start, end, step, prettyStep) {
// set default values
this._start = 0;
this._end = 0;
this._step = 1;
this.prettyStep = true;
this.precision = 5;
this._current = 0;
this.setRange(start, end, step, prettyStep);
};
/**
* Set a new range: start, end and step.
*
* @param {Number} start The start value
* @param {Number} end The end value
* @param {Number} step Optional. Step size. Must be a positive value.
* @param {boolean} prettyStep Optional. If true, the step size is rounded
* To a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/
StepNumber.prototype.setRange = function(start, end, step, prettyStep) {
this._start = start ? start : 0;
this._end = end ? end : 0;
this.setStep(step, prettyStep);
};
/**
* Set a new step size
* @param {Number} step New step size. Must be a positive value
* @param {boolean} prettyStep Optional. If true, the provided step is rounded
* to a pretty step size (like 1, 2, 5, 10, 20, 50, ...)
*/
StepNumber.prototype.setStep = function(step, prettyStep) {
if (step === undefined || step <= 0)
return;
if (prettyStep !== undefined)
this.prettyStep = prettyStep;
if (this.prettyStep === true)
this._step = StepNumber.calculatePrettyStep(step);
else
this._step = step;
};
/**
* Calculate a nice step size, closest to the desired step size.
* Returns a value in one of the ranges 1*10^n, 2*10^n, or 5*10^n, where n is an
* integer Number. For example 1, 2, 5, 10, 20, 50, etc...
* @param {Number} step Desired step size
* @return {Number} Nice step size
*/
StepNumber.calculatePrettyStep = function (step) {
var log10 = function (x) {return Math.log(x) / Math.LN10;};
// try three steps (multiple of 1, 2, or 5
var step1 = Math.pow(10, Math.round(log10(step))),
step2 = 2 * Math.pow(10, Math.round(log10(step / 2))),
step5 = 5 * Math.pow(10, Math.round(log10(step / 5)));
// choose the best step (closest to minimum step)
var prettyStep = step1;
if (Math.abs(step2 - step) <= Math.abs(prettyStep - step)) prettyStep = step2;
if (Math.abs(step5 - step) <= Math.abs(prettyStep - step)) prettyStep = step5;
// for safety
if (prettyStep <= 0) {
prettyStep = 1;
}
return prettyStep;
};
/**
* returns the current value of the step
* @return {Number} current value
*/
StepNumber.prototype.getCurrent = function () {
return parseFloat(this._current.toPrecision(this.precision));
};
/**
* returns the current step size
* @return {Number} current step size
*/
StepNumber.prototype.getStep = function () {
return this._step;
};
/**
* Set the current value to the largest value smaller than start, which
* is a multiple of the step size
*/
StepNumber.prototype.start = function() {
this._current = this._start - this._start % this._step;
};
/**
* Do a step, add the step size to the current value
*/
StepNumber.prototype.next = function () {
this._current += this._step;
};
/**
* Returns true whether the end is reached
* @return {boolean} True if the current value has passed the end value.
*/
StepNumber.prototype.end = function () {
return (this._current > this._end);
};
module.exports = StepNumber;

lib/module/header.js → lib/header.js View File


+ 0
- 84
lib/module/exports.js View File

@ -1,84 +0,0 @@
/**
* vis.js module exports
*/
var vis = {
moment: moment,